diff options
author | Antenore Gatta <antenore@simbiosi.org> | 2020-10-09 16:43:45 +0300 |
---|---|---|
committer | Antenore Gatta <antenore@simbiosi.org> | 2020-10-09 16:43:45 +0300 |
commit | 688e947c6be146628d903012699009221fbd379c (patch) | |
tree | e458f108f8c6c56acd89103ac4676848e8188d44 | |
parent | 77832afed28899aadf274ef77340a87d66f714e9 (diff) |
Implementing text search in the SSH plugin
* Regular expressions
* Match case
* Wrap around
* Whole word
Signed-off-by: Antenore Gatta <antenore@simbiosi.org>
-rw-r--r-- | .gitlab-ci.yml | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | cmake/FindPCRE2.cmake | 23 | ||||
-rw-r--r-- | data/ui/CMakeLists.txt | 9 | ||||
-rw-r--r-- | data/ui/remmina_preferences.glade | 210 | ||||
-rw-r--r-- | data/ui/remmina_search.glade | 270 | ||||
-rw-r--r-- | data/ui/remmina_search_popover.glade | 265 | ||||
-rw-r--r-- | snap/snapcraft.yaml | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/remmina_pref.c | 6 | ||||
-rw-r--r-- | src/remmina_pref.h | 1 | ||||
-rw-r--r-- | src/remmina_pref_dialog.c | 3 | ||||
-rw-r--r-- | src/remmina_pref_dialog.h | 1 | ||||
-rw-r--r-- | src/remmina_ssh_plugin.c | 251 |
14 files changed, 1003 insertions, 51 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa87807bb..5f056cfe5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -44,6 +44,7 @@ ubuntu:devel: stage: build before_script: - apt-get update -qq + - apt-get install -y -qq libpcre2-8-0 libpcre2-dev script: - mkdir $BUILD_FOLDER @@ -60,10 +61,11 @@ ubuntu:devel: appimage:build: # image: ubuntu:devel # stage: cross_environment - image: registry.gitlab.com/remmina/remmina/ubuntu:16.04 + image: registry.gitlab.com/remmina/remmina/ubuntu:18.04 stage: build before_script: - apt-get update -qq + - apt-get install -y -qq libpcre2-8-0 libpcre2-dev wget script: - mkdir $BUILD_FOLDER @@ -93,8 +95,6 @@ appimage:build: expire_in: 7 days only: refs: - - merge_requests - - tags - web - schedules diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a4db5e9f..214077ba2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ include(FindOptionalPackage) include(ConfigOptions) include(GtkUpdateIconCache) include(CheckHasModule) +include(FindPCRE2) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") diff --git a/cmake/FindPCRE2.cmake b/cmake/FindPCRE2.cmake new file mode 100644 index 000000000..8654b4422 --- /dev/null +++ b/cmake/FindPCRE2.cmake @@ -0,0 +1,23 @@ +find_path(PCRE2_INCLUDE_DIR + NAMES pcre2.h + PATHS ../../../../libs + /usr + PATH_SUFFIXES include) + +find_library(PCRE2_LIBRARY + NAMES pcre2-8 + PATHS ../../../../libs + /usr + PATH_SUFFIXES lib) + +if (PCRE2_INCLUDE_DIR AND PCRE2_LIBRARY) + message(STATUS "found pcre2 headers at ${PCRE2_INCLUDE_DIR}") + message(STATUS "found pcre2 libraries at ${PCRE2_LIBRARY}") + set(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR}) + set(PCRE2_LIBRARIES ${PCRE2_LIBRARY}) + set(PCRE2_FOUND yes) +else() + set(PCRE2_INCLUDE_DIRS) + set(PCRE2_LIBRARIES) + set(PCRE2_FOUND no) +endif() diff --git a/data/ui/CMakeLists.txt b/data/ui/CMakeLists.txt index 36eb5e2b7..ae40a07ae 100644 --- a/data/ui/CMakeLists.txt +++ b/data/ui/CMakeLists.txt @@ -33,12 +33,13 @@ install(FILES remmina_about.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_key_chooser.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_main.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_mpc.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_news.glade DESTINATION "${REMMINA_UIDIR}") -install(FILES remmina_spinner.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_preferences.glade DESTINATION "${REMMINA_UIDIR}") -install(FILES remmina_key_chooser.glade DESTINATION "${REMMINA_UIDIR}") -install(FILES remmina_string_list.glade DESTINATION "${REMMINA_UIDIR}") -install(FILES remmina_mpc.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_search.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_snap_info_dialog.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_spinner.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_string_list.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_unlock.glade DESTINATION "${REMMINA_UIDIR}") diff --git a/data/ui/remmina_preferences.glade b/data/ui/remmina_preferences.glade index b2fc189bc..f979b906d 100644 --- a/data/ui/remmina_preferences.glade +++ b/data/ui/remmina_preferences.glade @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.22.2 +<!-- Generated with glade 3.22.2 Remmina Preferences Dialog - Copyright (C) Antenore Gatta & Giovanni Panozzo 2014-2020 @@ -1784,14 +1784,13 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">(Host key+)</property> - <property name="halign">start</property> <property name="margin_right">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">4</property> - <property name="width">8</property> + <property name="width">2</property> </packing> </child> <child> @@ -1802,14 +1801,13 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">(Host key+)</property> - <property name="halign">start</property> <property name="margin_right">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">5</property> - <property name="width">8</property> + <property name="width">2</property> </packing> </child> <child> @@ -1820,14 +1818,13 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">(Host key+)</property> - <property name="halign">start</property> <property name="margin_right">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">6</property> - <property name="width">8</property> + <property name="width">2</property> </packing> </child> <child> @@ -1892,7 +1889,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">14</property> + <property name="top_attach">15</property> </packing> </child> <child> @@ -1907,7 +1904,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">14</property> + <property name="top_attach">15</property> <property name="width">8</property> </packing> </child> @@ -1921,7 +1918,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1933,7 +1930,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1945,7 +1942,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">2</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1957,7 +1954,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">3</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1969,7 +1966,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">4</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1981,7 +1978,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">5</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -1993,7 +1990,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">6</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -2005,7 +2002,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">7</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -2018,7 +2015,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">8</property> - <property name="top_attach">13</property> + <property name="top_attach">14</property> </packing> </child> <child> @@ -2030,7 +2027,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2042,7 +2039,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">2</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2054,7 +2051,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">3</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2066,7 +2063,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">4</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2078,7 +2075,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">5</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2090,7 +2087,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">6</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2102,7 +2099,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">7</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2115,7 +2112,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">8</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2128,7 +2125,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">12</property> + <property name="top_attach">13</property> </packing> </child> <child> @@ -2141,7 +2138,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">11</property> + <property name="top_attach">12</property> </packing> </child> <child> @@ -2155,7 +2152,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">11</property> + <property name="top_attach">12</property> <property name="width">8</property> </packing> </child> @@ -2169,7 +2166,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">10</property> + <property name="top_attach">11</property> </packing> </child> <child> @@ -2183,7 +2180,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">10</property> + <property name="top_attach">11</property> <property name="width">8</property> </packing> </child> @@ -2198,7 +2195,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">9</property> + <property name="top_attach">10</property> <property name="width">8</property> </packing> </child> @@ -2212,7 +2209,7 @@ Author: Antenore Gatta </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">9</property> + <property name="top_attach">10</property> </packing> </child> <child> @@ -2220,6 +2217,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="margin_left">18</property> <property name="label" translatable="yes">Increase font size</property> </object> <packing> @@ -2232,6 +2230,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="margin_left">18</property> <property name="label" translatable="yes">Decrease font size</property> </object> <packing> @@ -2247,13 +2246,13 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">(Host key+)</property> - <property name="halign">start</property> + <property name="margin_right">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">7</property> - <property name="width">8</property> + <property name="width">2</property> </packing> </child> <child> @@ -2264,15 +2263,152 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">(Host key+)</property> - <property name="halign">start</property> + <property name="margin_right">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">8</property> - <property name="width">8</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_keyboard_search_text"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="margin_left">18</property> + <property name="label" translatable="yes">Search text</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">9</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_keyboard_search_text"> + <property name="label">Search</property> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">(Host key+)</property> + <property name="margin_right">18</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">9</property> + <property name="width">2</property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </object> <packing> <property name="position">6</property> diff --git a/data/ui/remmina_search.glade b/data/ui/remmina_search.glade new file mode 100644 index 000000000..388664cb8 --- /dev/null +++ b/data/ui/remmina_search.glade @@ -0,0 +1,270 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 + +- +Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Author: Antenore Gatta + +--> +<interface> + <requires lib="gtk+" version="3.18"/> + <!-- interface-license-type gplv2 --> + <!-- interface-copyright 2016-2020 Antenore Gatta, Giovanni Panozzo --> + <!-- interface-authors Antenore Gatta --> + <object class="GtkWindow" id="RemminaSearchWidget"> + <property name="can_focus">False</property> + <property name="modal">True</property> + <property name="destroy_with_parent">True</property> + <child type="titlebar"> + <placeholder/> + </child> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">12</property> + <property name="margin_bottom">12</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">18</property> + <child> + <object class="GtkBox" id="box4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkSearchEntry" id="search_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="activates_default">True</property> + <property name="width_chars">30</property> + <property name="primary_icon_name">edit-find-symbolic</property> + <property name="primary_icon_activatable">False</property> + <property name="primary_icon_sensitive">False</property> + <property name="placeholder_text" translatable="yes">Search</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="search_prev_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Search for previous occurrence</property> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">go-up-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="search_next_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Search for next occurrence</property> + <child> + <object class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">go-down-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <style> + <class name="linked"/> + </style> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="reveal_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Toggle search options</property> + <child> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">open-menu-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + <accessibility> + <relation type="controller-for" target="revealer"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="close_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <child> + <object class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">window-close-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRevealer" id="revealer"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="transition_type">none</property> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">18</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkCheckButton" id="match_case_checkbutton"> + <property name="label" translatable="yes">_Match case</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="entire_word_checkbutton"> + <property name="label" translatable="yes">Match _entire word only</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="regex_checkbutton"> + <property name="label" translatable="yes">Match as _regular expression</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="wrap_around_checkbutton"> + <property name="label" translatable="yes">_Wrap around</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/data/ui/remmina_search_popover.glade b/data/ui/remmina_search_popover.glade new file mode 100644 index 000000000..de1e21780 --- /dev/null +++ b/data/ui/remmina_search_popover.glade @@ -0,0 +1,265 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 + +- +Copyright (C) Antenore Gatta & Giovanni Panozzo + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Author: Antenore Gatta + +--> +<interface> + <requires lib="gtk+" version="3.12"/> + <!-- interface-license-type gplv2 --> + <!-- interface-copyright Antenore Gatta & Giovanni Panozzo --> + <!-- interface-authors Antenore Gatta --> + <object class="GtkPopover" id="SearchPopover"> + <property name="can_focus">False</property> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">12</property> + <property name="margin_bottom">12</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">18</property> + <child> + <object class="GtkBox" id="box4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkSearchEntry" id="search_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="activates_default">True</property> + <property name="width_chars">30</property> + <property name="primary_icon_name">edit-find-symbolic</property> + <property name="primary_icon_activatable">False</property> + <property name="primary_icon_sensitive">False</property> + <property name="placeholder_text" translatable="yes">Search</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="search_prev_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Search for previous occurrence</property> + <child> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">go-up-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="search_next_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Search for next occurrence</property> + <child> + <object class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">go-down-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <style> + <class name="linked"/> + </style> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="reveal_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Toggle search options</property> + <child> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">open-menu-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + <accessibility> + <relation type="controller-for" target="revealer"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="close_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <child> + <object class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">window-close-symbolic</property> + <property name="use_fallback">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRevealer" id="revealer"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="transition_type">none</property> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">18</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkCheckButton" id="match_case_checkbutton"> + <property name="label" translatable="yes">_Match case</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="entire_word_checkbutton"> + <property name="label" translatable="yes">Match _entire word only</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="regex_checkbutton"> + <property name="label" translatable="yes">Match as _regular expression</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="wrap_around_checkbutton"> + <property name="label" translatable="yes">_Wrap around</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">False</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 65f8e4015..0b1bb69de 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -159,6 +159,7 @@ parts: - libvte-2.91-dev - libxkbfile-dev - libwebkit2gtk-4.0-dev + - libpcre2-dev stage-packages: - libgpm2 - libssh-4 @@ -265,6 +266,7 @@ parts: - libxdmcp6 - libogg0 - libvorbis0a + - libpcre2-8-0 # Needed for the example .wav files for testing purposes - alsa-utils diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 770e82615..1e32fc8ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -222,6 +222,12 @@ if(GTK3_FOUND) endif() endif() +include(FindPCRE2) +if (NOT PCRE2_FOUND) + message(FATAL_ERROR "require pcre2") +endif () +include_directories(${PCRE2_INCLUDE_DIRS}) + add_subdirectory(external_tools) install(TARGETS remmina DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/remmina_pref.c b/src/remmina_pref.c index 0f60a9a63..f1d8cbb7a 100644 --- a/src/remmina_pref.c +++ b/src/remmina_pref.c @@ -646,6 +646,12 @@ void remmina_pref_init(void) else remmina_pref.vte_shortcutkey_decrease_font = GDK_KEY_Page_Down; + if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_search_text", NULL)) + remmina_pref.vte_shortcutkey_search_text = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_search_text", + NULL); + else + remmina_pref.vte_shortcutkey_search_text = GDK_KEY_g; + /* If we have a color scheme file, we switch to it, GIO will merge it in the * remmina.pref file */ diff --git a/src/remmina_pref.h b/src/remmina_pref.h index 729cf983a..e13f2db81 100644 --- a/src/remmina_pref.h +++ b/src/remmina_pref.h @@ -171,6 +171,7 @@ typedef struct _RemminaPref { guint vte_shortcutkey_select_all; guint vte_shortcutkey_increase_font; guint vte_shortcutkey_decrease_font; + guint vte_shortcutkey_search_text; /* In View menu */ gboolean hide_toolbar; gboolean small_toolbutton; diff --git a/src/remmina_pref_dialog.c b/src/remmina_pref_dialog.c index b19163272..de4863107 100644 --- a/src/remmina_pref_dialog.c +++ b/src/remmina_pref_dialog.c @@ -350,6 +350,7 @@ void remmina_pref_on_dialog_destroy(GtkWidget *widget, gpointer user_data) remmina_pref.vte_shortcutkey_select_all = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_select_all)); remmina_pref.vte_shortcutkey_increase_font = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_increase_font)); remmina_pref.vte_shortcutkey_decrease_font = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_decrease_font)); + remmina_pref.vte_shortcutkey_search_text = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_search_text)); remmina_pref_save(); remmina_pref_init(); @@ -609,6 +610,7 @@ static void remmina_pref_dialog_init(void) remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_select_all, remmina_pref.vte_shortcutkey_select_all); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_increase_font, remmina_pref.vte_shortcutkey_increase_font); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_decrease_font, remmina_pref.vte_shortcutkey_decrease_font); + remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_search_text, remmina_pref.vte_shortcutkey_search_text); remmina_plugin_manager_for_each_plugin(REMMINA_PLUGIN_TYPE_PREF, remmina_pref_dialog_add_pref_plugin, remmina_pref_dialog->dialog); @@ -693,6 +695,7 @@ GtkDialog* remmina_pref_dialog_new(gint default_tab, GtkWindow *parent) remmina_pref_dialog->button_keyboard_select_all = GTK_BUTTON(GET_OBJECT("button_keyboard_select_all")); remmina_pref_dialog->button_keyboard_increase_font = GTK_BUTTON(GET_OBJECT("button_keyboard_increase_font")); remmina_pref_dialog->button_keyboard_decrease_font = GTK_BUTTON(GET_OBJECT("button_keyboard_decrease_font")); + remmina_pref_dialog->button_keyboard_search_text = GTK_BUTTON(GET_OBJECT("button_keyboard_search_text")); remmina_pref_dialog->label_terminal_foreground = GTK_LABEL(GET_OBJECT("label_terminal_foreground")); remmina_pref_dialog->colorbutton_foreground = GTK_COLOR_BUTTON(GET_OBJECT("colorbutton_foreground")); remmina_pref_dialog->label_terminal_background = GTK_LABEL(GET_OBJECT("label_terminal_background")); diff --git a/src/remmina_pref_dialog.h b/src/remmina_pref_dialog.h index 233713b29..2fc2a3cd8 100644 --- a/src/remmina_pref_dialog.h +++ b/src/remmina_pref_dialog.h @@ -114,6 +114,7 @@ typedef struct _RemminaPrefDialog { GtkButton * button_keyboard_select_all; GtkButton * button_keyboard_increase_font; GtkButton * button_keyboard_decrease_font; + GtkButton * button_keyboard_search_text; GtkLabel * label_terminal_cursor_color; GtkLabel * label_terminal_normal_colors; GtkLabel * label_terminal_bright_colors; diff --git a/src/remmina_ssh_plugin.c b/src/remmina_ssh_plugin.c index de533a20a..007d4ed42 100644 --- a/src/remmina_ssh_plugin.c +++ b/src/remmina_ssh_plugin.c @@ -43,6 +43,8 @@ #include <gtk/gtk.h> #include <glib/gi18n.h> #include <gio/gio.h> +#include <glib-object.h> +#include <gobject/gvaluecollector.h> #include <vte/vte.h> #include <locale.h> #include <langinfo.h> @@ -55,11 +57,16 @@ #include "remmina_ssh_plugin.h" #include "remmina_masterthread_exec.h" +#define PCRE2_CODE_UNIT_WIDTH 8 +#include <pcre2.h> + + #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_COPY 1 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_PASTE 2 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_SELECT_ALL 3 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_INCREASE_FONT 4 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_DECREASE_FONT 5 +#define REMMINA_PLUGIN_SSH_FEATURE_TOOL_SEARCH 6 #define GET_PLUGIN_DATA(gp) (RemminaPluginSshData *)g_object_get_data(G_OBJECT(gp), "plugin-data"); @@ -200,6 +207,29 @@ static struct { /** The SSH plugin implementation */ +typedef struct _RemminaSshSearch { + GtkWidget* parent; + + GtkBuilder* builder; + GtkWidget* window; + GtkWidget* search_entry; + GtkWidget* search_prev_button; + GtkWidget* search_next_button; + GtkWidget* close_button; + GtkToggleButton* match_case_checkbutton; + GtkToggleButton* entire_word_checkbutton; + GtkToggleButton* regex_checkbutton; + GtkToggleButton* wrap_around_checkbutton; + GtkWidget* reveal_button; + GtkWidget* revealer; + + //VteTerminal *terminal; + gboolean regex_caseless; + gboolean has_regex; + gchar* regex_pattern; + +} RemminaSshSearch; + typedef struct _RemminaPluginSshData { RemminaSSHShell * shell; GFile * vte_session_file; @@ -208,9 +238,13 @@ typedef struct _RemminaPluginSshData { const GdkRGBA * palette; pthread_t thread; + + RemminaSshSearch * search_widget; } RemminaPluginSshData; +#define GET_OBJECT(object_name) gtk_builder_get_object(search_widget->builder, object_name) + static RemminaPluginService *remmina_plugin_service = NULL; static gboolean @@ -343,12 +377,6 @@ void remmina_plugin_ssh_vte_terminal_set_encoding_and_pty(VteTerminal *terminal, setlocale(LC_ALL, ""); if (codeset && codeset[0] != '\0') { -#if VTE_CHECK_VERSION(0, 38, 0) - vte_terminal_set_encoding(terminal, codeset, NULL); -#else - vte_terminal_set_emulation(terminal, "xterm"); - vte_terminal_set_encoding(terminal, codeset); -#endif } vte_terminal_set_backspace_binding(terminal, VTE_ERASE_ASCII_DELETE); @@ -504,6 +532,206 @@ static void remmina_ssh_keystroke(RemminaProtocolWidget *gp, const guint keystro return; } + +/* regex */ + +static void jit_regex(VteRegex* regex, char const* pattern) +{ + TRACE_CALL(__func__); + GError *error; + if (!vte_regex_jit(regex, PCRE2_JIT_COMPLETE, &error) || + !vte_regex_jit(regex, PCRE2_JIT_PARTIAL_SOFT, &error)) { + if (!g_error_matches(error, VTE_REGEX_ERROR, -45 /* PCRE2_ERROR_JIT_BADOPTION: JIT not supported */)) + REMMINA_DEBUG("JITing regex \"%s\" failed: %s\n", pattern, error->message); + } +} + +static VteRegex* compile_regex_for_search(char const* pattern, gboolean caseless, GError** error) +{ + TRACE_CALL(__func__); + uint32_t flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_MULTILINE; + if (caseless) + flags |= PCRE2_CASELESS; + + VteRegex *regex = vte_regex_new_for_search(pattern, strlen(pattern), flags, error); + if (regex != NULL) + jit_regex(regex, pattern); + + return regex; +} + +static void +remmina_search_widget_update_sensitivity(RemminaSshSearch* search_widget) +{ + TRACE_CALL(__func__); + gboolean can_search = search_widget->has_regex; + + gtk_widget_set_sensitive(search_widget->search_next_button, can_search); + gtk_widget_set_sensitive(search_widget->search_prev_button, can_search); +} + +static void +remmina_search_widget_update_regex(RemminaPluginSshData* gpdata) +{ + TRACE_CALL(__func__); + GError *error = NULL; + + RemminaSshSearch *search_widget = gpdata->search_widget; + char const* search_text = gtk_entry_get_text(GTK_ENTRY(search_widget->search_entry)); + gboolean caseless = gtk_toggle_button_get_active(search_widget->match_case_checkbutton) == FALSE; + + char* pattern; + if (gtk_toggle_button_get_active(search_widget->regex_checkbutton)) + pattern = g_strdup(search_text); + else + pattern = g_regex_escape_string(search_text, -1); + + if (gtk_toggle_button_get_active(search_widget->regex_checkbutton)) { + char* tmp = g_strdup_printf("\\b%s\\b", pattern); + g_free(pattern); + pattern = tmp; + } + + if (caseless == search_widget->regex_caseless && + g_strcmp0(pattern, search_widget->regex_pattern) == 0) + return; + + search_widget->regex_caseless = caseless; + g_free(search_widget->regex_pattern); + search_widget->regex_pattern = NULL; + + if (search_text[0] != '\0') { + REMMINA_DEBUG("Search text is: %s", search_text); + VteRegex *regex = compile_regex_for_search(pattern, caseless, &error); + vte_terminal_search_set_regex(VTE_TERMINAL(gpdata->vte), regex, 0); + if (regex != NULL) + vte_regex_unref(regex); + + if (!error) { + search_widget->has_regex = TRUE; + search_widget->regex_pattern = pattern; /* adopt */ + pattern = NULL; /* adopted */ + gtk_widget_set_tooltip_text(search_widget->search_entry, NULL); + } else { + search_widget->has_regex = FALSE; + REMMINA_DEBUG ("Regex not set, cannot search"); + gtk_widget_set_tooltip_text(search_widget->search_entry, error->message); + } + } + + g_free(pattern); + g_free(error); + + remmina_search_widget_update_sensitivity(search_widget); +} + +static void +remmina_search_widget_wrap_around_toggled(GtkToggleButton* button, RemminaPluginSshData* gpdata) +{ + TRACE_CALL(__func__); + + vte_terminal_search_set_wrap_around(VTE_TERMINAL(gpdata->vte), gtk_toggle_button_get_active(button)); +} + +static void +remmina_search_widget_search_forward(RemminaPluginSshData* gpdata) +{ + TRACE_CALL(__func__); + + RemminaSshSearch *search_sidget = gpdata->search_widget; + if (!search_sidget->has_regex) + return; + vte_terminal_search_find_next(VTE_TERMINAL(gpdata->vte)); +} + +static void +remmina_search_widget_search_backward(RemminaPluginSshData* gpdata) +{ + TRACE_CALL(__func__); + + RemminaSshSearch *search_sidget = gpdata->search_widget; + if (!search_sidget->has_regex) + return; + vte_terminal_search_find_previous(VTE_TERMINAL(gpdata->vte)); +} + +GtkWidget * remmina_plugin_pop_search_new (GtkWidget *relative_to, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp); + + gpdata->search_widget = g_new0(RemminaSshSearch, 1); + RemminaSshSearch *search_widget = gpdata->search_widget; + + search_widget->regex_caseless = FALSE; + search_widget->has_regex = FALSE; + search_widget->regex_pattern = NULL; + + search_widget->builder = remmina_public_gtk_builder_new_from_file("remmina_search.glade"); + search_widget->window = GTK_WIDGET(GET_OBJECT("RemminaSearchWidget")); + search_widget->search_entry = GTK_WIDGET(GET_OBJECT("search_entry")); + search_widget->search_prev_button = GTK_WIDGET(GET_OBJECT("search_prev_button")); + search_widget->search_next_button = GTK_WIDGET(GET_OBJECT("search_next_button")); + search_widget->close_button = GTK_WIDGET(GET_OBJECT("close_button")); + search_widget->match_case_checkbutton = GTK_TOGGLE_BUTTON(GET_OBJECT("match_case_checkbutton")); + search_widget->entire_word_checkbutton = GTK_TOGGLE_BUTTON(GET_OBJECT("entire_word_checkbutton")); + search_widget->regex_checkbutton = GTK_TOGGLE_BUTTON(GET_OBJECT("regex_checkbutton")); + search_widget->wrap_around_checkbutton = GTK_TOGGLE_BUTTON(GET_OBJECT("wrap_around_checkbutton")); + search_widget->reveal_button = GTK_WIDGET(GET_OBJECT("reveal_button")); + search_widget->revealer = GTK_WIDGET(GET_OBJECT("revealer")); + + gtk_widget_set_can_default (search_widget->search_next_button, TRUE); + gtk_widget_grab_default (search_widget->search_next_button); + + gtk_entry_set_activates_default (GTK_ENTRY(search_widget->search_entry), TRUE); + + /* Connect signals */ + gtk_builder_connect_signals(search_widget->builder, NULL); + + g_signal_connect_swapped(search_widget->close_button, "clicked", G_CALLBACK(gtk_widget_destroy), GTK_WIDGET(search_widget->window)); + + g_object_bind_property(search_widget->reveal_button, "active", + search_widget->revealer, "reveal-child", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + + g_signal_connect_swapped(search_widget->search_entry, "next-match", G_CALLBACK(remmina_search_widget_search_forward), gpdata); + g_signal_connect_swapped(search_widget->search_entry, "previous-match", G_CALLBACK(remmina_search_widget_search_backward), gpdata); + g_signal_connect_swapped(search_widget->search_entry, "search-changed", G_CALLBACK(remmina_search_widget_update_regex), gpdata); + + g_signal_connect_swapped(search_widget->search_next_button,"clicked", G_CALLBACK(remmina_search_widget_search_forward), gpdata); + g_signal_connect_swapped(search_widget->search_prev_button,"clicked", G_CALLBACK(remmina_search_widget_search_backward), gpdata); + + g_signal_connect_swapped(search_widget->match_case_checkbutton,"toggled", G_CALLBACK(remmina_search_widget_update_regex), gpdata); + g_signal_connect_swapped(search_widget->entire_word_checkbutton,"toggled", G_CALLBACK(remmina_search_widget_update_regex), gpdata); + g_signal_connect_swapped(search_widget->regex_checkbutton,"toggled", G_CALLBACK(remmina_search_widget_update_regex), gpdata); + g_signal_connect_swapped(search_widget->match_case_checkbutton, "toggled", G_CALLBACK(remmina_search_widget_update_regex), gpdata); + + g_signal_connect(search_widget->wrap_around_checkbutton, "toggled", G_CALLBACK(remmina_search_widget_wrap_around_toggled), gpdata); + + remmina_search_widget_update_sensitivity(search_widget); + return search_widget->window; + +} + +void remmina_plugin_pop_search (GtkMenuItem *menuitem, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp); + + GtkWindow *parent = NULL; + + REMMINA_DEBUG ("Before popover"); + GtkWidget *window = remmina_plugin_pop_search_new (gpdata->vte, gp); + GtkWidget *toplevel = gtk_widget_get_toplevel (gpdata->vte); + if (GTK_IS_WINDOW (toplevel)) { + parent = GTK_WINDOW(toplevel); + gtk_window_set_transient_for (GTK_WINDOW(window), parent); + gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT); + } + gtk_widget_show(window); + REMMINA_DEBUG ("After popover"); +} + gboolean remmina_ssh_plugin_popup_menu(GtkWidget *widget, GdkEvent *event, GtkWidget *menu) { @@ -546,6 +774,7 @@ void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp) GtkWidget *save = gtk_menu_item_new_with_label(_("Save session to file")); GtkWidget *font_incr = gtk_menu_item_new_with_label(_("Increase font size (host+Page Up)")); GtkWidget *font_decr = gtk_menu_item_new_with_label(_("Decrease font size (host+Page Down)")); + GtkWidget *find_text = gtk_menu_item_new_with_label(_("Find text (host+G)")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_all); gtk_menu_shell_append(GTK_MENU_SHELL(menu), copy); @@ -553,6 +782,7 @@ void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp) gtk_menu_shell_append(GTK_MENU_SHELL(menu), save); gtk_menu_shell_append(GTK_MENU_SHELL(menu), font_incr); gtk_menu_shell_append(GTK_MENU_SHELL(menu), font_decr); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), find_text); g_signal_connect(G_OBJECT(gpdata->vte), "button_press_event", G_CALLBACK(remmina_ssh_plugin_popup_menu), menu); @@ -569,6 +799,8 @@ void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp) G_CALLBACK(remmina_plugin_ssh_vte_increase_font), gpdata->vte); g_signal_connect(G_OBJECT(font_decr), "activate", G_CALLBACK(remmina_plugin_ssh_vte_decrease_font), gpdata->vte); + g_signal_connect(G_OBJECT(find_text), "activate", + G_CALLBACK(remmina_plugin_pop_search), gp); gtk_widget_show_all(menu); } @@ -613,7 +845,7 @@ remmina_plugin_ssh_init(RemminaProtocolWidget *gp) g_signal_connect(G_OBJECT(hbox), "focus-in-event", G_CALLBACK(remmina_plugin_ssh_on_focus_in), gp); vte = vte_terminal_new(); - gtk_widget_show(vte); + //gtk_widget_show(vte); vte_terminal_set_size(VTE_TERMINAL(vte), 80, 25); vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(vte), TRUE); #if !VTE_CHECK_VERSION(0, 38, 0) @@ -836,6 +1068,7 @@ remmina_plugin_ssh_init(RemminaProtocolWidget *gp) gpdata->vte_session_file = g_file_new_for_path(fp); remmina_plugin_ssh_popup_ui(gp); + gtk_widget_show_all(hbox); } /** @@ -957,6 +1190,8 @@ remmina_plugin_ssh_call_feature(RemminaProtocolWidget *gp, const RemminaProtocol case REMMINA_PLUGIN_SSH_FEATURE_TOOL_DECREASE_FONT: vte_terminal_set_font_scale(VTE_TERMINAL(gpdata->vte), vte_terminal_get_font_scale(VTE_TERMINAL(gpdata->vte))-SCALE_FACTOR); + case REMMINA_PLUGIN_SSH_FEATURE_TOOL_SEARCH: + remmina_plugin_pop_search(NULL, gp); return; } } @@ -1048,6 +1283,7 @@ static RemminaProtocolFeature remmina_plugin_ssh_features[] = { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_PLUGIN_SSH_FEATURE_TOOL_SELECT_ALL, N_("Select all"), N_("_Select all"), NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_PLUGIN_SSH_FEATURE_TOOL_INCREASE_FONT, N_("Increase font size"), N_("_Increase font size"), NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_PLUGIN_SSH_FEATURE_TOOL_DECREASE_FONT, N_("Decrease font size"), N_("_Decrease font size"), NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_PLUGIN_SSH_FEATURE_TOOL_SEARCH, N_("Find text"), N_("_Find text"), NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL } }; @@ -1255,6 +1491,7 @@ remmina_ssh_plugin_register(void) remmina_plugin_ssh_features[2].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_select_all); remmina_plugin_ssh_features[3].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_increase_font); remmina_plugin_ssh_features[4].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_decrease_font); + remmina_plugin_ssh_features[5].opt3 = GUINT_TO_POINTER(remmina_pref.vte_shortcutkey_search_text); remmina_plugin_service = &remmina_plugin_manager_service; |