From bd038e1d0f20e3202c161c1b324e64f89ef6e842 Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Sun, 24 Sep 2023 14:40:46 +0000 Subject: Automatic doc build by remmina-ci --- public/remmina__exec_8c_source.html | 4 +- public/remmina__file__editor_8c.html | 96 ++++++++++++++--------------- public/remmina__file__editor_8c_source.html | 94 ++++++++++++++-------------- public/remmina__file__editor_8h.html | 14 ++--- public/remmina__file__editor_8h_source.html | 14 ++--- public/remmina__main_8c_source.html | 6 +- 6 files changed, 114 insertions(+), 114 deletions(-) diff --git a/public/remmina__exec_8c_source.html b/public/remmina__exec_8c_source.html index cff5ec6e2..97a024cd3 100644 --- a/public/remmina__exec_8c_source.html +++ b/public/remmina__exec_8c_source.html @@ -105,7 +105,7 @@ $(document).ready(function(){initNavTree('remmina__exec_8c_source.html','');});
void remmina_exec_exitremmina_one_confirm()
Definition: remmina_exec.c:123
gboolean remmina_icon_is_available(void)
Determine whenever the Remmina icon is available.
Definition: remmina_icon.c:330
-
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
+
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
GtkWidget * remmina_main_new(void)
void remmina_main_save_before_destroy()
Save the Remmina Main Window size and the expanded group before to close Remmina. ...
Definition: remmina_main.c:180
const gchar * remmina_exec_get_build_config(void)
Definition: remmina_exec.c:78
@@ -130,7 +130,7 @@ $(document).ready(function(){initNavTree('remmina__exec_8c_source.html','');});
void remmina_exec_exitremmina()
Definition: remmina_exec.c:89
gboolean remmina_pref_get_boolean(const gchar *key)
Definition: remmina_exec.h:54
-
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
void remmina_main_destroy()
Definition: remmina_main.c:193
RemminaFile * remmina_file_new(void)
Definition: remmina_file.c:93
diff --git a/public/remmina__file__editor_8c.html b/public/remmina__file__editor_8c.html index 68a659f5c..c3d5b0092 100644 --- a/public/remmina__file__editor_8c.html +++ b/public/remmina__file__editor_8c.html @@ -113,10 +113,10 @@ Functions   static GtkWidget * remmina_file_editor_create_notebook_tab (RemminaFileEditor *gfe, const gchar *stock_id, const gchar *label, gint rows, gint cols)   -static void remmina_file_editor_ssh_tunnel_server_custom_radio_on_toggled (GtkToggleButton *togglebutton, RemminaFileEditor *gfe) -  static void remmina_file_editor_assistance_enabled_check_on_toggled (GtkToggleButton *togglebutton, RemminaFileEditor *gfe)   +static void remmina_file_editor_ssh_tunnel_server_custom_radio_on_toggled (GtkToggleButton *togglebutton, RemminaFileEditor *gfe) +  static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled (GtkToggleButton *togglebutton, RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)   static void remmina_file_editor_create_server (RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row) @@ -281,7 +281,7 @@ Variables
-

Definition at line 376 of file remmina_file_editor.c.

+

Definition at line 365 of file remmina_file_editor.c.

@@ -357,7 +357,7 @@ Variables
-

Definition at line 552 of file remmina_file_editor.c.

+

Definition at line 553 of file remmina_file_editor.c.

@@ -415,7 +415,7 @@ Variables
-

Definition at line 1970 of file remmina_file_editor.c.

+

Definition at line 1971 of file remmina_file_editor.c.

@@ -471,7 +471,7 @@ Variables
-

Definition at line 1385 of file remmina_file_editor.c.

+

Definition at line 1386 of file remmina_file_editor.c.

@@ -521,7 +521,7 @@ Variables
-

Definition at line 648 of file remmina_file_editor.c.

+

Definition at line 649 of file remmina_file_editor.c.

@@ -549,7 +549,7 @@ Variables
-

Definition at line 1155 of file remmina_file_editor.c.

+

Definition at line 1156 of file remmina_file_editor.c.

@@ -617,7 +617,7 @@ Variables
-

Definition at line 817 of file remmina_file_editor.c.

+

Definition at line 818 of file remmina_file_editor.c.

@@ -694,7 +694,7 @@ Variables

Create checkbox + gtk_file_chooser for open files and select folders.

The code is wrong, because if the checkbox is not active, the value should be set to NULL and remove it from the remmina file. The problem is that this function knows nothing about the remmina file. This should be rewritten in a more generic way Please use REMMINA_PROTOCOL_SETTING_TYPE_TEXT

-

Definition at line 845 of file remmina_file_editor.c.

+

Definition at line 846 of file remmina_file_editor.c.

@@ -768,7 +768,7 @@ Variables
-

Definition at line 794 of file remmina_file_editor.c.

+

Definition at line 795 of file remmina_file_editor.c.

@@ -848,7 +848,7 @@ Variables
-

Definition at line 950 of file remmina_file_editor.c.

+

Definition at line 951 of file remmina_file_editor.c.

@@ -928,7 +928,7 @@ Variables
-

Definition at line 908 of file remmina_file_editor.c.

+

Definition at line 909 of file remmina_file_editor.c.

@@ -1080,7 +1080,7 @@ Variables
-

Definition at line 503 of file remmina_file_editor.c.

+

Definition at line 504 of file remmina_file_editor.c.

@@ -1130,7 +1130,7 @@ Variables
-

Definition at line 568 of file remmina_file_editor.c.

+

Definition at line 569 of file remmina_file_editor.c.

@@ -1204,7 +1204,7 @@ Variables
-

Definition at line 772 of file remmina_file_editor.c.

+

Definition at line 773 of file remmina_file_editor.c.

@@ -1254,7 +1254,7 @@ Variables
-

Definition at line 452 of file remmina_file_editor.c.

+

Definition at line 453 of file remmina_file_editor.c.

@@ -1298,7 +1298,7 @@ Variables
-

Definition at line 995 of file remmina_file_editor.c.

+

Definition at line 996 of file remmina_file_editor.c.

@@ -1336,7 +1336,7 @@ Variables
-

Definition at line 1217 of file remmina_file_editor.c.

+

Definition at line 1218 of file remmina_file_editor.c.

@@ -1404,7 +1404,7 @@ Variables
-

Definition at line 730 of file remmina_file_editor.c.

+

Definition at line 731 of file remmina_file_editor.c.

@@ -1484,7 +1484,7 @@ Variables
-

Definition at line 696 of file remmina_file_editor.c.

+

Definition at line 697 of file remmina_file_editor.c.

@@ -1552,7 +1552,7 @@ Variables
-

Definition at line 739 of file remmina_file_editor.c.

+

Definition at line 740 of file remmina_file_editor.c.

@@ -1638,7 +1638,7 @@ Variables
-

Definition at line 897 of file remmina_file_editor.c.

+

Definition at line 898 of file remmina_file_editor.c.

@@ -1676,7 +1676,7 @@ Variables
-

Definition at line 1980 of file remmina_file_editor.c.

+

Definition at line 1981 of file remmina_file_editor.c.

@@ -1696,7 +1696,7 @@ Variables
-

Definition at line 1997 of file remmina_file_editor.c.

+

Definition at line 1998 of file remmina_file_editor.c.

@@ -1724,7 +1724,7 @@ Variables
-

Definition at line 1905 of file remmina_file_editor.c.

+

Definition at line 1906 of file remmina_file_editor.c.

@@ -1772,7 +1772,7 @@ Variables
-

Definition at line 883 of file remmina_file_editor.c.

+

Definition at line 884 of file remmina_file_editor.c.

@@ -1816,7 +1816,7 @@ Variables
-

Definition at line 1948 of file remmina_file_editor.c.

+

Definition at line 1949 of file remmina_file_editor.c.

@@ -1836,7 +1836,7 @@ Variables
-

Definition at line 2140 of file remmina_file_editor.c.

+

Definition at line 2141 of file remmina_file_editor.c.

@@ -1856,7 +1856,7 @@ Variables
-

Definition at line 2160 of file remmina_file_editor.c.

+

Definition at line 2161 of file remmina_file_editor.c.

@@ -1876,7 +1876,7 @@ Variables
-

Definition at line 2011 of file remmina_file_editor.c.

+

Definition at line 2012 of file remmina_file_editor.c.

@@ -1896,7 +1896,7 @@ Variables
-

Definition at line 2179 of file remmina_file_editor.c.

+

Definition at line 2180 of file remmina_file_editor.c.

@@ -1926,7 +1926,7 @@ Variables
-

Definition at line 2146 of file remmina_file_editor.c.

+

Definition at line 2147 of file remmina_file_editor.c.

@@ -1964,7 +1964,7 @@ Variables
-

Definition at line 1899 of file remmina_file_editor.c.

+

Definition at line 1900 of file remmina_file_editor.c.

@@ -2002,7 +2002,7 @@ Variables
-

Definition at line 1850 of file remmina_file_editor.c.

+

Definition at line 1851 of file remmina_file_editor.c.

@@ -2040,7 +2040,7 @@ Variables
-

Definition at line 1792 of file remmina_file_editor.c.

+

Definition at line 1793 of file remmina_file_editor.c.

@@ -2116,7 +2116,7 @@ Variables
-

Definition at line 1830 of file remmina_file_editor.c.

+

Definition at line 1831 of file remmina_file_editor.c.

@@ -2155,7 +2155,7 @@ Variables

: Call remmina_file_editor_on_save

-

Definition at line 1872 of file remmina_file_editor.c.

+

Definition at line 1873 of file remmina_file_editor.c.

@@ -2193,7 +2193,7 @@ Variables
-

Definition at line 1422 of file remmina_file_editor.c.

+

Definition at line 1423 of file remmina_file_editor.c.

@@ -2221,7 +2221,7 @@ Variables
-

Definition at line 1466 of file remmina_file_editor.c.

+

Definition at line 1467 of file remmina_file_editor.c.

@@ -2249,7 +2249,7 @@ Variables
-

Definition at line 1482 of file remmina_file_editor.c.

+

Definition at line 1483 of file remmina_file_editor.c.

@@ -2350,7 +2350,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 395 of file remmina_file_editor.c.

+

Definition at line 396 of file remmina_file_editor.c.

@@ -2388,7 +2388,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 366 of file remmina_file_editor.c.

+

Definition at line 386 of file remmina_file_editor.c.

@@ -2426,7 +2426,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 1726 of file remmina_file_editor.c.

+

Definition at line 1727 of file remmina_file_editor.c.

@@ -2464,7 +2464,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 540 of file remmina_file_editor.c.

+

Definition at line 541 of file remmina_file_editor.c.

@@ -2502,7 +2502,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 1621 of file remmina_file_editor.c.

+

Definition at line 1622 of file remmina_file_editor.c.

@@ -2552,7 +2552,7 @@ TODO: Responsive text size and line wrap.

-

Definition at line 1543 of file remmina_file_editor.c.

+

Definition at line 1544 of file remmina_file_editor.c.

@@ -2578,7 +2578,7 @@ TODO: Responsive text size and line wrap.

Initial value:
=
{
"0", N_("Password"),
"1", N_("SSH identity file"),
"2", N_("SSH agent"),
"3", N_("Public key (automatic)"),
"4", N_("Kerberos (GSSAPI)"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 1206 of file remmina_file_editor.c.

+

Definition at line 1207 of file remmina_file_editor.c.

diff --git a/public/remmina__file__editor_8c_source.html b/public/remmina__file__editor_8c_source.html index 72a3adcd2..1c8290cfc 100644 --- a/public/remmina__file__editor_8c_source.html +++ b/public/remmina__file__editor_8c_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
remmina_file_editor.c
-Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #include <ctype.h>
38 #include "config.h"
39 #ifdef HAVE_LIBAVAHI_UI
40 #include <avahi-ui/avahi-ui.h>
41 #endif
42 #include "remmina_public.h"
43 #include "remmina_pref.h"
44 #include "rcw.h"
46 #include "remmina_file.h"
47 #include "remmina_file_editor.h"
48 #include "remmina_file_manager.h"
49 #include "remmina_icon.h"
50 #include "remmina_main.h"
51 #include "remmina_plugin_manager.h"
52 #include "remmina_pref_dialog.h"
53 #include "remmina_ssh.h"
54 #include "remmina_string_list.h"
55 #include "remmina_unlock.h"
56 #include "remmina_widget_pool.h"
57 
58 G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
59 
60 static const gchar *server_tips = N_("<big>"
61  "Supported formats\n"
62  "• server\n"
63  "• server[:port]\n"
64  "VNC additional formats\n"
65  "• ID:repeater ID number\n"
66  "• unix:///path/socket.sock"
67  "</big>");
68 
69 static const gchar *cmd_tips = N_("<big>"
70  "• command in PATH args %h\n"
71  "• /path/to/foo -options %h %u\n"
72  "• %h is substituted with the server name\n"
73  "• %t is substituted with the SSH server name\n"
74  "• %u is substituted with the username\n"
75  "• %U is substituted with the SSH username\n"
76  "• %p is substituted with Remmina profile name\n"
77  "• %g is substituted with Remmina profile group name\n"
78  "• %d is substituted with local date and time in ISO 8601 format\n"
79  "Do not run in background if you want the command to be executed before connecting.\n"
80  "</big>");
81 
82 #ifdef HAVE_LIBSSH
83 static const gchar *server_tips2 = N_("<big>"
84  "Supported formats\n"
85  "• server\n"
86  "• server[:port]\n"
87  "• username@server[:port] (SSH protocol only)"
88  "</big>");
89 #endif
90 
91 struct _RemminaFileEditorPriv {
92  RemminaFile * remmina_file;
93  RemminaProtocolPlugin * plugin;
94  const gchar * avahi_service_type;
95 
96  GtkWidget * name_entry;
97  GtkWidget * labels_entry;
98  GtkWidget * group_combo;
99  GtkWidget * protocol_combo;
100  GtkWidget * save_button;
101 
102  GtkWidget * config_box;
103  GtkWidget * config_scrollable;
104  GtkWidget * config_viewport;
105  GtkWidget * config_container;
106 
107  GtkWidget * server_combo;
108  GtkWidget * resolution_iws_radio;
109  GtkWidget * resolution_auto_radio;
110  GtkWidget * resolution_custom_radio;
111  GtkWidget * resolution_custom_combo;
112  GtkWidget * keymap_combo;
113 
114  GtkWidget * assistance_toggle;
115  GtkWidget * assistance_file;
116  GtkWidget * assistance_password;
117  GtkWidget * assistance_file_label;
118  GtkWidget * assistance_password_label;
119 
120  GtkWidget * behavior_autostart_check;
121  GtkWidget * behavior_precommand_entry;
122  GtkWidget * behavior_postcommand_entry;
123  GtkWidget * behavior_lock_check;
124  GtkWidget * behavior_disconnect;
125 
126  GtkWidget * ssh_tunnel_enabled_check;
127  GtkWidget * ssh_tunnel_loopback_check;
128  GtkWidget * ssh_tunnel_server_default_radio;
129  GtkWidget * ssh_tunnel_server_custom_radio;
130  GtkWidget * ssh_tunnel_server_entry;
131  GtkWidget * ssh_tunnel_auth_agent_radio;
132  GtkWidget * ssh_tunnel_auth_password_radio;
133  GtkWidget * ssh_tunnel_auth_password;
134  GtkWidget * ssh_tunnel_passphrase;
135  GtkWidget * ssh_tunnel_auth_publickey_radio;
136  GtkWidget * ssh_tunnel_auth_auto_publickey_radio;
137  GtkWidget * ssh_tunnel_auth_combo;
138  GtkWidget * ssh_tunnel_username_entry;
139  GtkWidget * ssh_tunnel_privatekey_chooser;
140  GtkWidget * ssh_tunnel_certfile_chooser;
141 
142  GHashTable * setting_widgets;
143 };
144 
146 {
147  TRACE_CALL(__func__);
148 }
149 
166  GtkWidget * failed_widget,
167  GError * err)
168 {
169  if (!err) {
170  err = NULL; // g_set_error doesn't like overwriting errors.
171  g_set_error(&err, 1, 1, _("Input is invalid."));
172  }
173 
174  if (!gfe || !failed_widget) {
175  g_critical("(%s): Parameters RemminaFileEditor 'gfe' or "
176  "GtkWidget* 'failed_widget' are 'NULL'!",
177  __func__);
178  return;
179  }
180 
181  gint widget_width = gtk_widget_get_allocated_width(failed_widget);
182  gint widget_height = gtk_widget_get_allocated_height(failed_widget);
183 
184  GtkWidget *err_label = gtk_label_new("");
185  GtkWidget *alert_icon = NULL;
186  GtkWindow *err_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
187  GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
188  GdkWindow *window = gtk_widget_get_window(failed_widget);
189 
190  GtkAllocation allocation;
191  gint failed_widget_x, failed_widget_y;
192 
193  gchar *markup = g_strdup_printf("<span size='large'>%s</span>", err->message);
194 
195  // Setup err_window
196  gtk_window_set_decorated(err_window, FALSE);
197  gtk_window_set_type_hint(err_window, GDK_WINDOW_TYPE_HINT_TOOLTIP);
198  gtk_window_set_default_size(err_window, widget_width, widget_height);
199  gtk_window_set_title(err_window, "Error");
200  gtk_window_set_resizable(err_window, TRUE);
201 
202  // Move err_window under failed_widget
203  gtk_window_set_attached_to(err_window, failed_widget);
204  gtk_window_set_transient_for(err_window, GTK_WINDOW(gfe));
205  gdk_window_get_origin(GDK_WINDOW(window), &failed_widget_x, &failed_widget_y);
206  gtk_widget_get_allocation(failed_widget, &allocation);
207  failed_widget_x += allocation.x;
208  failed_widget_y += allocation.y + allocation.height;
209  gtk_window_move(err_window, failed_widget_x, failed_widget_y);
210 
211  // Setup label
212  gtk_label_set_selectable(GTK_LABEL(err_label), FALSE);
213  gtk_label_set_max_width_chars(GTK_LABEL(err_label), 1);
214  gtk_widget_set_hexpand(GTK_WIDGET(err_label), TRUE);
215  gtk_widget_set_vexpand(GTK_WIDGET(err_label), TRUE);
216  gtk_label_set_ellipsize(GTK_LABEL(err_label), PANGO_ELLIPSIZE_END);
217  gtk_label_set_line_wrap(GTK_LABEL(err_label), TRUE);
218  gtk_label_set_line_wrap_mode(GTK_LABEL(err_label), PANGO_WRAP_WORD_CHAR);
219  gtk_label_set_markup(GTK_LABEL(err_label), markup);
220 
221  alert_icon = gtk_image_new_from_icon_name("dialog-warning-symbolic",
222  GTK_ICON_SIZE_DND);
223 
224  // Fill icon and label into a box.
225  gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(alert_icon), FALSE, FALSE, 0);
226  gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(err_label), TRUE, TRUE, 5);
227 
228  // Attach box to err_window
229  gtk_container_add(GTK_CONTAINER(err_window), GTK_WIDGET(box));
230 
231  // Display everything.
232  gtk_widget_show_all(GTK_WIDGET(err_window));
233 
234  // Mouse click and focus-loss will delete the err_window.
235  g_signal_connect(G_OBJECT(err_window), "focus-out-event",
236  G_CALLBACK(gtk_window_close), NULL);
237  g_signal_connect(G_OBJECT(err_window), "button-press-event",
238  G_CALLBACK(gtk_window_close), NULL);
239 }
240 
241 #ifdef HAVE_LIBAVAHI_UI
242 
243 static void remmina_file_editor_browse_avahi(GtkWidget *button, RemminaFileEditor *gfe)
244 {
245  TRACE_CALL(__func__);
246  GtkWidget *dialog;
247  gchar *host;
248 
249  dialog = aui_service_dialog_new(_("Choose a Remote Desktop Server"),
250  GTK_WINDOW(gfe),
251  _("_Cancel"), GTK_RESPONSE_CANCEL,
252  _("_OK"), GTK_RESPONSE_ACCEPT,
253  NULL);
254 
255  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
256  aui_service_dialog_set_resolve_service(AUI_SERVICE_DIALOG(dialog), TRUE);
257  aui_service_dialog_set_resolve_host_name(AUI_SERVICE_DIALOG(dialog), TRUE);
258  aui_service_dialog_set_browse_service_types(AUI_SERVICE_DIALOG(dialog),
259  gfe->priv->avahi_service_type, NULL);
260 
261  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
262  host = g_strdup_printf("[%s]:%i",
263  aui_service_dialog_get_host_name(AUI_SERVICE_DIALOG(dialog)),
264  aui_service_dialog_get_port(AUI_SERVICE_DIALOG(dialog)));
265  } else {
266  host = NULL;
267  }
268  gtk_widget_destroy(dialog);
269 
270  if (host) {
271  gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gfe->priv->server_combo))), host);
272  g_free(host);
273  }
274 }
275 #endif
276 
277 static void remmina_file_editor_on_realize(GtkWidget *widget, gpointer user_data)
278 {
279  TRACE_CALL(__func__);
280  RemminaFileEditor *gfe;
281  GtkWidget *defaultwidget;
282 
283  gfe = REMMINA_FILE_EDITOR(widget);
284 
285  defaultwidget = gfe->priv->server_combo;
286 
287  if (defaultwidget) {
288  if (GTK_IS_EDITABLE(defaultwidget))
289  gtk_editable_select_region(GTK_EDITABLE(defaultwidget), 0, -1);
290  gtk_widget_grab_focus(defaultwidget);
291  }
292 }
293 
294 static void remmina_file_editor_destroy(GtkWidget *widget, gpointer data)
295 {
296  TRACE_CALL(__func__);
297  remmina_file_free(REMMINA_FILE_EDITOR(widget)->priv->remmina_file);
298  g_hash_table_destroy(REMMINA_FILE_EDITOR(widget)->priv->setting_widgets);
299  g_free(REMMINA_FILE_EDITOR(widget)->priv);
300 }
301 
302 static void remmina_file_editor_button_on_toggled(GtkToggleButton *togglebutton, GtkWidget *widget)
303 {
304  TRACE_CALL(__func__);
305  gtk_widget_set_sensitive(widget, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)));
306 }
307 
309 {
310  TRACE_CALL(__func__);
311  /* Create the notebook */
312  gfe->priv->config_container = gtk_notebook_new();
313  gfe->priv->config_viewport = gtk_viewport_new(NULL, NULL);
314  gfe->priv->config_scrollable = gtk_scrolled_window_new(NULL, NULL);
315  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_scrollable), 2);
316  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gfe->priv->config_scrollable),
317  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
318  gtk_widget_show(gfe->priv->config_scrollable);
319 
320  gtk_container_add(GTK_CONTAINER(gfe->priv->config_viewport), gfe->priv->config_container);
321  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_viewport), 2);
322  gtk_widget_show(gfe->priv->config_viewport);
323  gtk_container_add(GTK_CONTAINER(gfe->priv->config_scrollable), gfe->priv->config_viewport);
324  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_container), 2);
325  gtk_widget_show(gfe->priv->config_container);
326 
327  gtk_container_add(GTK_CONTAINER(gfe->priv->config_box), gfe->priv->config_scrollable);
328 }
329 
331  const gchar *stock_id, const gchar *label, gint rows, gint cols)
332 {
333  TRACE_CALL(__func__);
334  GtkWidget *tablabel;
335  GtkWidget *tabbody;
336  GtkWidget *grid;
337  GtkWidget *widget;
338 
339  tablabel = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
340  gtk_widget_show(tablabel);
341 
342  widget = gtk_image_new_from_icon_name(stock_id, GTK_ICON_SIZE_BUTTON);
343  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
344  gtk_widget_show(widget);
345 
346  widget = gtk_label_new(label);
347  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
348  gtk_widget_show(widget);
349 
350  tabbody = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
351  gtk_widget_show(tabbody);
352  gtk_notebook_append_page(GTK_NOTEBOOK(gfe->priv->config_container), tabbody, tablabel);
353 
354  grid = gtk_grid_new();
355  gtk_widget_show(grid);
356  gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
357  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
358  gtk_container_set_border_width(GTK_CONTAINER(grid), 15);
359  gtk_box_pack_start(GTK_BOX(tabbody), grid, FALSE, FALSE, 0);
360 
361  return grid;
362 }
363 
364 #ifdef HAVE_LIBSSH
365 
367 {
368  TRACE_CALL(__func__);
369  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_entry),
370  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check)) &&
371  (gfe->priv->ssh_tunnel_server_custom_radio == NULL ||
372  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_server_custom_radio))));
373 }
374 
375 
376 static void remmina_file_editor_assistance_enabled_check_on_toggled(GtkToggleButton *togglebutton,
377  RemminaFileEditor *gfe)
378 {
379  TRACE_CALL(__func__);
380  gboolean enabled = TRUE;
381 
382  if (gfe->priv->assistance_toggle) {
383  enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->assistance_toggle));
384  if (gfe->priv->assistance_file)
385  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_file), enabled);
386  if (gfe->priv->assistance_password)
387  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_password), enabled);
388  if (gfe->priv->assistance_file_label)
389  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_file_label), enabled);
390  if (gfe->priv->assistance_password_label)
391  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_password_label), enabled);
392  }
393 }
394 
395 static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton,
397 {
398  TRACE_CALL(__func__);
399  RemminaFileEditorPriv *priv = gfe->priv;
400  gboolean enabled = TRUE;
401  gchar *p;
402  const gchar *cp;
403  const gchar *s = NULL;
404 
405  if (gfe->priv->ssh_tunnel_enabled_check) {
406  enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check));
407  if (gfe->priv->ssh_tunnel_loopback_check)
408  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_loopback_check), enabled);
409  if (gfe->priv->ssh_tunnel_server_default_radio)
410  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_default_radio), enabled);
411  if (gfe->priv->ssh_tunnel_server_custom_radio)
412  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_custom_radio), enabled);
414  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
415  // if (!(g_strcmp0(p, "SFTP") == 0 || g_strcmp0(p, "SSH") == 0)) {
416  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_username_entry), enabled);
417  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_password), enabled);
418  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_combo), enabled);
419  //}
420  g_free(p);
421  }
422  // remmina_file_editor_ssh_tunnel_auth_publickey_radio_on_toggled(NULL, gfe);
423  s = remmina_file_get_string(gfe->priv->remmina_file, "ssh_tunnel_privatekey");
424  if (s)
425  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gfe->priv->ssh_tunnel_privatekey_chooser), s);
426  s = remmina_file_get_string(gfe->priv->remmina_file, "ssh_tunnel_certfile");
427  if (s)
428  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gfe->priv->ssh_tunnel_certfile_chooser), s);
429 
430  if (gfe->priv->ssh_tunnel_username_entry)
431  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry))[0] == '\0') {
432  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_username");
433  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry), cp ? cp : "");
434  }
435 
436  if (gfe->priv->ssh_tunnel_auth_password) {
437  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password))[0] == '\0') {
438  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_password");
439  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password), cp ? cp : "");
440  }
441  }
442  if (gfe->priv->ssh_tunnel_passphrase) {
443  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase))[0] == '\0') {
444  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_passphrase");
445  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase), cp ? cp : "");
446  }
447  }
448 }
449 
450 #endif
451 
452 static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid,
453  gint row)
454 {
455  TRACE_CALL(__func__);
456  RemminaProtocolPlugin *plugin = gfe->priv->plugin;
457  GtkWidget *widget;
458 #ifdef HAVE_LIBAVAHI_UI
459  GtkWidget *hbox;
460 #endif
461  gchar *s;
462 
463  widget = gtk_label_new(_("Server"));
464  gtk_widget_show(widget);
465  gtk_widget_set_valign(widget, GTK_ALIGN_START);
466  gtk_widget_set_halign(widget, GTK_ALIGN_START);
467  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, row + 1);
468 
469  s = remmina_pref_get_recent(plugin->name);
470  widget = remmina_public_create_combo_entry(s, remmina_file_get_string(gfe->priv->remmina_file, "server"), TRUE);
471  gtk_widget_set_hexpand(widget, TRUE);
472  gtk_widget_show(widget);
473  gtk_widget_set_tooltip_markup(widget, _(server_tips));
474  gtk_entry_set_activates_default(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(widget))), TRUE);
475  gfe->priv->server_combo = widget;
476  g_free(s);
477 
478 #ifdef HAVE_LIBAVAHI_UI
479  if (setting->opt1) {
480  gfe->priv->avahi_service_type = (const gchar *)setting->opt1;
481 
482  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
483  gtk_widget_show(hbox);
484  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
485 
486  widget = gtk_button_new_with_label("…");
487  s = g_strdup_printf(_("Browse the network to find a %s server"), plugin->name);
488  gtk_widget_set_tooltip_text(widget, s);
489  g_free(s);
490  gtk_widget_show(widget);
491  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
492  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_avahi), gfe);
493 
494  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
495  } else
496 #endif
497  {
498  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
499  }
500 }
501 
502 
503 static GtkWidget *remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
504 {
505  TRACE_CALL(__func__);
506  GtkWidget *widget;
507 
508  widget = gtk_label_new(label);
509  gtk_widget_show(widget);
510 #if GTK_CHECK_VERSION(3, 12, 0)
511  gtk_widget_set_margin_end(widget, 40);
512 #else
513  gtk_widget_set_margin_right(widget, 40);
514 #endif
515  gtk_widget_set_valign(widget, GTK_ALIGN_START);
516  gtk_widget_set_halign(widget, GTK_ALIGN_START);
517  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
518 
519  widget = gtk_entry_new();
520  gtk_widget_show(widget);
521  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
522  gtk_entry_set_max_length(GTK_ENTRY(widget), 0);
523  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
524  gtk_widget_set_hexpand(widget, TRUE);
525  gtk_entry_set_activates_default(GTK_ENTRY(widget), TRUE);
526  if (setting_name)
527  gtk_widget_set_name(widget, setting_name);
528 
529  if (value)
530  gtk_entry_set_text(GTK_ENTRY(widget), value);
531  /* Password view Toogle*/
532  if (setting_name) {
533  gtk_entry_set_icon_from_icon_name(GTK_ENTRY(widget), GTK_ENTRY_ICON_SECONDARY, "org.remmina.Remmina-password-reveal-symbolic");
534  gtk_entry_set_icon_activatable(GTK_ENTRY(widget), GTK_ENTRY_ICON_SECONDARY, TRUE);
535  g_signal_connect(widget, "icon-press", G_CALLBACK(remmina_main_toggle_password_view), NULL);
536  }
537  return widget;
538 }
539 
540 static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
541 {
542  TRACE_CALL(__func__);
543  gchar *res_str;
544  res_str = g_strdup_printf("%dx%d",
545  remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", 0),
546  remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", 0));
547  remmina_public_load_combo_text_d(gfe->priv->resolution_custom_combo, remmina_pref.resolutions,
548  res_str, NULL);
549  g_free(res_str);
550 }
551 
552 static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
553 {
554  TRACE_CALL(__func__);
555 
556  GtkDialog *dialog = remmina_string_list_new(FALSE, NULL);
559  remmina_string_list_set_titles(_("Resolutions"), _("Configure the available resolutions"));
560  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
561  gtk_dialog_run(dialog);
562  g_free(remmina_pref.resolutions);
564  g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(remmina_file_editor_update_resolution), gfe);
565  gtk_widget_destroy(GTK_WIDGET(dialog));
566 }
567 
569  GtkWidget *grid, gint row)
570 {
571  TRACE_CALL(__func__);
572  GtkWidget *widget;
573  GtkWidget *hbox;
574  int resolution_w, resolution_h;
575  gchar *res_str;
577 
578  res_mode = remmina_file_get_int(gfe->priv->remmina_file, "resolution_mode", RES_INVALID);
579  resolution_w = remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", -1);
580  resolution_h = remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", -1);
581 
582  /* If resolution_mode is non-existent (-1), then we try to calculate it
583  * as we did before having resolution_mode */
584  if (res_mode == RES_INVALID) {
585  if (resolution_w <= 0 || resolution_h <= 0)
586  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
587  else
588  res_mode = RES_USE_CUSTOM;
589  }
590  if (res_mode == RES_USE_CUSTOM)
591  res_str = g_strdup_printf("%dx%d", resolution_w, resolution_h);
592  else
593  res_str = NULL;
594 
595  widget = gtk_label_new(_("Resolution"));
596  gtk_widget_show(widget);
597  gtk_widget_set_valign(widget, GTK_ALIGN_START);
598  gtk_widget_set_halign(widget, GTK_ALIGN_START);
599  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
600 
601  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
602  widget = gtk_radio_button_new_with_label(NULL, _("Use initial window size"));
603  gtk_widget_show(widget);
604  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
605  gfe->priv->resolution_iws_radio = widget;
606  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Use client resolution"));
607  gtk_widget_show(widget);
608  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
609  gfe->priv->resolution_auto_radio = widget;
610  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
611  gtk_widget_show(hbox);
612 
613  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
614  gtk_widget_show(hbox);
615  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row + 1, 1, 1);
616 
617  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Custom"));
618  gtk_widget_show(widget);
619  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
620  gfe->priv->resolution_custom_radio = widget;
621 
623  gtk_widget_show(widget);
624  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
625  gfe->priv->resolution_custom_combo = widget;
626 
627  widget = gtk_button_new_with_label("…");
628  gtk_widget_show(widget);
629  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
630  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_resolution), gfe);
631 
632  g_signal_connect(G_OBJECT(gfe->priv->resolution_custom_radio), "toggled",
633  G_CALLBACK(remmina_file_editor_button_on_toggled), gfe->priv->resolution_custom_combo);
634 
635  if (res_mode == RES_USE_CUSTOM)
636  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio), TRUE);
637  else if (res_mode == RES_USE_CLIENT)
638  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_auto_radio), TRUE);
639  else
640  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_iws_radio), TRUE);
641 
642  gtk_widget_set_sensitive(gfe->priv->resolution_custom_combo, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio)));
643 
644  g_free(res_str);
645 }
646 
647 
649  GtkWidget *grid, gint row)
650 {
651  TRACE_CALL(__func__);
652  GtkWidget *widget;
653 
654 
655 
656  widget = gtk_toggle_button_new_with_label(_("Assistance Mode"));
657  gtk_widget_set_halign(widget, GTK_ALIGN_START);
658  gtk_widget_show(widget);
659  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
660  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), remmina_file_get_int(gfe->priv->remmina_file, "assistance_mode", 0));
661  gfe->priv->assistance_toggle = widget;
662  g_signal_connect(widget, "toggled", G_CALLBACK(remmina_file_editor_assistance_enabled_check_on_toggled), gfe);
663 
664 
665  widget = gtk_label_new("Assistance file");
666  gtk_widget_set_halign(widget, GTK_ALIGN_END);
667  gtk_widget_show(widget);
668  gtk_grid_attach(GTK_GRID(grid), widget, 0, row+1, 1, 1);
669  gfe->priv->assistance_file_label = widget;
670 
671  widget = gtk_entry_new();
672  gtk_widget_set_halign(widget, GTK_ALIGN_START);
673  gtk_widget_show(widget);
674  gtk_entry_set_text(GTK_ENTRY(widget), remmina_file_get_string(gfe->priv->remmina_file, "assistance_file"));
675  gtk_grid_attach(GTK_GRID(grid), widget, 1, row+1, 1, 1);
676  gfe->priv->assistance_file = widget;
677 
678  widget = gtk_label_new("Assistance Password");
679  gtk_widget_set_halign(widget, GTK_ALIGN_END);
680  gtk_widget_show(widget);
681  gtk_grid_attach(GTK_GRID(grid), widget, 0, row+2, 1, 1);
682  gfe->priv->assistance_password_label = widget;
683 
684  widget = gtk_entry_new();
685  gtk_widget_set_halign(widget, GTK_ALIGN_START);
686  gtk_widget_show(widget);
687  gtk_entry_set_text(GTK_ENTRY(widget), remmina_file_get_string(gfe->priv->remmina_file, "assistance_pass"));
688  gtk_grid_attach(GTK_GRID(grid), widget, 1, row+2, 1, 1);
689  gfe->priv->assistance_password = widget;
690 
692 
693 }
694 
695 
696 static GtkWidget *remmina_file_editor_create_text2(RemminaFileEditor *gfe, GtkWidget *grid,
697  gint row, gint col, const gchar *label, const gchar *value, gint left,
698  gint right, gchar *setting_name)
699 {
700  TRACE_CALL(__func__);
701  GtkWidget *widget;
702 
703  widget = gtk_label_new(label);
704  gtk_widget_show(widget);
705 #if GTK_CHECK_VERSION(3, 12, 0)
706  gtk_widget_set_margin_start(widget, left);
707  gtk_widget_set_margin_end(widget, right);
708 #else
709  gtk_widget_set_margin_left(widget, left);
710  gtk_widget_set_margin_right(widget, right);
711 #endif
712  gtk_widget_set_valign(widget, GTK_ALIGN_START);
713  gtk_widget_set_halign(widget, GTK_ALIGN_START);
714  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
715 
716  widget = gtk_entry_new();
717  gtk_widget_show(widget);
718  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
719  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
720  gtk_widget_set_hexpand(widget, TRUE);
721  if (setting_name)
722  gtk_widget_set_name(widget, setting_name);
723 
724  if (value)
725  gtk_entry_set_text(GTK_ENTRY(widget), value);
726 
727  return widget;
728 }
729 
730 static GtkWidget *remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid,
731  gint row, gint col, const gchar *label, const gchar *value,
732  gchar *setting_name)
733 {
734  TRACE_CALL(__func__);
735  return remmina_file_editor_create_text2(gfe, grid, row, col, label, value, 0, 40,
736  setting_name);
737 }
738 
739 static GtkWidget *remmina_file_editor_create_textarea(RemminaFileEditor *gfe, GtkWidget *grid,
740  gint row, gint col, const gchar *label, const gchar *value,
741  gchar *setting_name)
742 {
743  TRACE_CALL(__func__);
744  GtkWidget *widget;
745  GtkTextView *view;
746  GtkTextBuffer *buffer;
747  GtkTextIter start;
748 
749  widget = gtk_text_view_new();
750  view = GTK_TEXT_VIEW(widget);
751  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
752  gtk_text_view_set_top_margin(GTK_TEXT_VIEW(view), 20);
753  gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(view), 20);
754  gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 20);
755  gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 20);
756  gtk_text_view_set_monospace(view, TRUE);
757  if (setting_name)
758  gtk_widget_set_name(widget, setting_name);
759  if (value) {
760  buffer = gtk_text_view_get_buffer(view);
761  gtk_text_buffer_set_text(buffer, value, -1);
762  gtk_text_buffer_get_start_iter(buffer, &start);
763  gtk_text_buffer_place_cursor(buffer, &start);
764  }
765  gtk_widget_show(widget);
766  gtk_widget_set_hexpand(widget, TRUE);
767  gtk_widget_set_size_request(GTK_WIDGET(view), 320, 300);
768  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
769  return widget;
770 }
771 
772 static GtkWidget *remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid,
773  gint row, gint col, const gchar *label, const gpointer *list,
774  const gchar *value, gchar *setting_name)
775 {
776  TRACE_CALL(__func__);
777  GtkWidget *widget;
778 
779  widget = gtk_label_new(label);
780  gtk_widget_show(widget);
781  gtk_widget_set_valign(widget, GTK_ALIGN_START);
782  gtk_widget_set_halign(widget, GTK_ALIGN_START);
783  if (setting_name)
784  gtk_widget_set_name(widget, setting_name);
785  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
786 
787  widget = remmina_public_create_combo_map(list, value, FALSE, gfe->priv->plugin->domain);
788  gtk_widget_show(widget);
789  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
790 
791  return widget;
792 }
793 
794 static GtkWidget *remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid,
795  gint row, gint col, const gchar *label, const gchar *list,
796  const gchar *value, gchar *setting_name)
797 {
798  TRACE_CALL(__func__);
799  GtkWidget *widget;
800 
801  widget = gtk_label_new(label);
802  gtk_widget_show(widget);
803  gtk_widget_set_valign(widget, GTK_ALIGN_START);
804  gtk_widget_set_halign(widget, GTK_ALIGN_START);
805  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
806 
807  widget = remmina_public_create_combo_entry(list, value, FALSE);
808  gtk_widget_show(widget);
809  gtk_widget_set_hexpand(widget, TRUE);
810  if (setting_name)
811  gtk_widget_set_name(widget, setting_name);
812  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
813 
814  return widget;
815 }
816 
817 static GtkWidget *remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid,
818  gint row, gint top, const gchar *label, gboolean value,
819  gchar *setting_name)
820 {
821  TRACE_CALL(__func__);
822  GtkWidget *widget;
823  widget = gtk_check_button_new_with_label(label);
824  gtk_widget_show(widget);
825  if (setting_name)
826  gtk_widget_set_name(widget, setting_name);
827  gtk_grid_attach(GTK_GRID(grid), widget, top, row, 1, 1);
828 
829  if (value)
830  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
831 
832  return widget;
833 }
834 
844 static GtkWidget *
845 remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label,
846  const gchar *value, gint type, gchar *setting_name)
847 {
848  TRACE_CALL(__func__);
849  GtkWidget *check;
850  GtkWidget *widget;
851  GtkWidget *hbox;
852 
853  widget = gtk_label_new(label);
854  gtk_widget_show(widget);
855  gtk_widget_set_valign(widget, GTK_ALIGN_START);
856  gtk_widget_set_halign(widget, GTK_ALIGN_START);
857  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
858 
859  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
860  gtk_widget_show(hbox);
861  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
862 
863  check = gtk_check_button_new();
864  gtk_widget_show(check);
865  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), (value && value[0] == '/'));
866  gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
867 
868  widget = gtk_file_chooser_button_new(label, type);
869  if (setting_name)
870  gtk_widget_set_name(widget, setting_name);
871  gtk_widget_show(widget);
872  if (value)
873  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget), value);
874  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
875 
876  g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(remmina_file_editor_button_on_toggled), widget);
877  remmina_file_editor_button_on_toggled(GTK_TOGGLE_BUTTON(check), widget);
878 
879  return widget;
880 }
881 
882 // used to filter out invalid characters for REMMINA_PROTOCOL_SETTING_TYPE_INT
883 void remmina_file_editor_int_setting_filter(GtkEditable *editable, const gchar *text,
884  gint length, gint *position, gpointer data)
885 {
886  for (int i = 0; i < length; i++) {
887  if (!isdigit(text[i]) && text[i] != '-') {
888  g_signal_stop_emission_by_name(G_OBJECT(editable), "insert-text");
889  return;
890  }
891  }
892 }
893 
894 // used to filter out invalid characters for REMMINA_PROTOCOL_SETTING_TYPE_DOUBLE
895 // '.' and ',' can't be used interchangeably! It depends on the language setting
896 // of the user.
897 void remmina_file_editor_double_setting_filter(GtkEditable *editable, const gchar *text,
898  gint length, gint *position, gpointer data)
899 {
900  for (int i = 0; i < length; i++) {
901  if (!isdigit(text[i]) && text[i] != '-' && text[i] != '.' && text[i] != ',') {
902  g_signal_stop_emission_by_name(G_OBJECT(editable), "insert-text");
903  return;
904  }
905  }
906 }
907 
908 static GtkWidget *remmina_file_editor_create_int(RemminaFileEditor *gfe, GtkWidget *grid,
909  gint row, gint col, const gchar *label, const gint value,
910  gint left, gint right, gchar *setting_name)
911 {
912  TRACE_CALL(__func__);
913  GtkWidget *widget;
914 
915  widget = gtk_label_new(label);
916  gtk_widget_show(widget);
917 #if GTK_CHECK_VERSION(3, 12, 0)
918  gtk_widget_set_margin_start(widget, left);
919  gtk_widget_set_margin_end(widget, right);
920 #else
921  gtk_widget_set_margin_left(widget, left);
922  gtk_widget_set_margin_right(widget, right);
923 #endif
924  gtk_widget_set_valign(widget, GTK_ALIGN_START);
925  gtk_widget_set_halign(widget, GTK_ALIGN_START);
926  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
927 
928  widget = gtk_entry_new();
929  gtk_widget_show(widget);
930  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
931  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
932  gtk_widget_set_hexpand(widget, TRUE);
933  if (setting_name)
934  gtk_widget_set_name(widget, setting_name);
935 
936  // Convert int to str.
937  int length = snprintf(NULL, 0, "%d", value) + 1; // +1 '\0' byte
938  char *str = malloc(length);
939  snprintf(str, length, "%d", value);
940 
941  gtk_entry_set_text(GTK_ENTRY(widget), str);
942  free(str);
943 
944  g_signal_connect(G_OBJECT(widget), "insert-text",
945  G_CALLBACK(remmina_file_editor_int_setting_filter), NULL);
946 
947  return widget;
948 }
949 
951  GtkWidget *grid, gint row, gint col,
952  const gchar *label, gdouble value, gint left,
953  gint right, gchar *setting_name)
954 {
955  TRACE_CALL(__func__);
956  GtkWidget *widget;
957 
958  widget = gtk_label_new(label);
959  gtk_widget_show(widget);
960 #if GTK_CHECK_VERSION(3, 12, 0)
961  gtk_widget_set_margin_start(widget, left);
962  gtk_widget_set_margin_end(widget, right);
963 #else
964  gtk_widget_set_margin_left(widget, left);
965  gtk_widget_set_margin_right(widget, right);
966 #endif
967  gtk_widget_set_valign(widget, GTK_ALIGN_START);
968  gtk_widget_set_halign(widget, GTK_ALIGN_START);
969  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
970 
971  widget = gtk_entry_new();
972  gtk_widget_show(widget);
973  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
974  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
975  gtk_widget_set_hexpand(widget, TRUE);
976  if (setting_name)
977  gtk_widget_set_name(widget, setting_name);
978 
979  // Convert double to str.
980  int length = snprintf(NULL, 0, "%.8g", value) + 1; // +1 '\0' byte
981  char *str = malloc(length);
982  snprintf(str, length, "%f", value);
983 
984  gtk_entry_set_text(GTK_ENTRY(widget), str);
985  free(str);
986 
987  g_signal_connect(G_OBJECT(widget), "insert-text",
989 
990  return widget;
991 }
992 
993 
994 
995 static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid,
996  const RemminaProtocolSetting *settings)
997 {
998  TRACE_CALL(__func__);
999  RemminaFileEditorPriv *priv = gfe->priv;
1000  GtkWidget *widget;
1001  gint grid_row = 0;
1002  gint grid_column = 0;
1003  gchar **strarr;
1004  gchar *setting_name;
1005  const gchar *escaped;
1006 
1007  while (settings->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
1008  setting_name = (gchar *)(remmina_plugin_manager_get_canonical_setting_name(settings));
1009  switch (settings->type) {
1011  remmina_file_editor_create_server(gfe, settings, grid, grid_row);
1012  break;
1013 
1015  widget = remmina_file_editor_create_password(gfe, grid, grid_row, 0,
1016  g_dgettext(priv->plugin->domain, settings->label),
1017  remmina_file_get_string(priv->remmina_file, setting_name),
1018  setting_name);
1019  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1020  grid_row++;
1021  break;
1022 
1024  remmina_file_editor_create_resolution(gfe, settings, grid, grid_row);
1025  grid_row ++;
1026  break;
1027 
1029  remmina_file_editor_create_assistance(gfe, settings, grid, grid_row);
1030  grid_row += 3;
1031  break;
1032 
1034  strarr = remmina_pref_keymap_groups();
1035  priv->keymap_combo = remmina_file_editor_create_select(gfe, grid,
1036  grid_row + 1, 0,
1037  _("Keyboard mapping"), (const gpointer *)strarr,
1038  remmina_file_get_string(priv->remmina_file, "keymap"),
1039  setting_name);
1040  g_strfreev(strarr);
1041  grid_row++;
1042  break;
1043 
1045  widget = remmina_file_editor_create_text(gfe, grid, grid_row, 0,
1046  g_dgettext(priv->plugin->domain, settings->label),
1047  remmina_file_get_string(priv->remmina_file, setting_name),
1048  setting_name);
1049  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1050  if (settings->opt2)
1051  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1052  grid_row++;
1053  break;
1054 
1056  escaped = remmina_file_get_string(priv->remmina_file, setting_name);
1057  escaped = g_uri_unescape_string(escaped, NULL);
1058  widget = remmina_file_editor_create_textarea(gfe, grid, grid_row, 0,
1059  g_dgettext(priv->plugin->domain, settings->label), escaped,
1060  setting_name);
1061  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1062  grid_row++;
1063  break;
1064 
1066  widget = remmina_file_editor_create_select(gfe, grid, grid_row, 0,
1067  g_dgettext(priv->plugin->domain, settings->label),
1068  (const gpointer *)settings->opt1,
1069  remmina_file_get_string(priv->remmina_file, setting_name),
1070  setting_name);
1071  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1072  if (settings->opt2)
1073  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1074  break;
1075 
1077  widget = remmina_file_editor_create_combo(gfe, grid, grid_row, 0,
1078  g_dgettext(priv->plugin->domain, settings->label),
1079  (const gchar *)settings->opt1,
1080  remmina_file_get_string(priv->remmina_file, setting_name),
1081  setting_name);
1082  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1083  if (settings->opt2)
1084  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1085  break;
1086 
1088  widget = remmina_file_editor_create_check(gfe, grid, grid_row, grid_column,
1089  g_dgettext(priv->plugin->domain, settings->label),
1090  remmina_file_get_int(priv->remmina_file, setting_name, FALSE),
1091  setting_name);
1092  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1093  if (settings->opt2)
1094  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1095  break;
1096 
1098  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
1099  g_dgettext(priv->plugin->domain, settings->label),
1100  remmina_file_get_string(priv->remmina_file, setting_name),
1101  GTK_FILE_CHOOSER_ACTION_OPEN, setting_name);
1102  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1103  if (settings->opt2)
1104  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1105  break;
1106 
1108  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
1109  g_dgettext(priv->plugin->domain, settings->label),
1110  remmina_file_get_string(priv->remmina_file, setting_name),
1111  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1112  setting_name);
1113  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1114  if (settings->opt2)
1115  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1116  break;
1118  widget = remmina_file_editor_create_int(gfe, grid, grid_row, 0,
1119  g_dgettext(priv->plugin->domain, settings->label),
1120  remmina_file_get_int(priv->remmina_file, setting_name, 0),
1121  0, 40, setting_name);
1122  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1123  if (settings->opt2)
1124  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1125  grid_row++;
1126  break;
1128  widget = remmina_file_editor_create_double(gfe, grid, grid_row, 0,
1129  g_dgettext(priv->plugin->domain, settings->label),
1130  remmina_file_get_double(priv->remmina_file, setting_name, 0.0f),
1131  0, 40, setting_name);
1132  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1133  if (settings->opt2)
1134  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1135  grid_row++;
1136  break;
1137 
1138  default:
1139  break;
1140  }
1141  /* If the setting wants compactness, move to the next column */
1142  if (settings->compact)
1143  grid_column++;
1144  /* Add a new settings row and move to the first column
1145  * if the setting doesn’t want the compactness
1146  * or we already have two columns */
1147  if (!settings->compact || grid_column > 1) {
1148  grid_row++;
1149  grid_column = 0;
1150  }
1151  settings++;
1152  }
1153 }
1154 
1156 {
1157  TRACE_CALL(__func__);
1158  RemminaFileEditorPriv *priv = gfe->priv;
1159  GtkWidget *grid;
1160  GtkWidget *widget;
1161  const gchar *cs;
1162 
1163  /* The Behavior tab (implementation) */
1164  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Behavior"), 20, 2);
1165 
1166  /* Execute Command frame */
1167  remmina_public_create_group(GTK_GRID(grid), _("Execute a Command"), 0, 1, 2);
1168 
1169  /* PRE connection command */
1170  cs = remmina_file_get_string(priv->remmina_file, "precommand");
1171  widget = remmina_file_editor_create_text2(gfe, grid, 2, 0, _("Before connecting"), cs, 24, 26, "precommand");
1172  priv->behavior_precommand_entry = widget;
1173  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("command %h %u %t %U %p %g --option"));
1174  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1175 
1176  /* POST connection command */
1177  cs = remmina_file_get_string(priv->remmina_file, "postcommand");
1178  widget = remmina_file_editor_create_text2(gfe, grid, 3, 0, _("After connecting"), cs, 24, 16, "postcommand");
1179  priv->behavior_postcommand_entry = widget;
1180  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("/path/to/command -opt1 arg %h %u %t -opt2 %U %p %g"));
1181  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1182 
1183  /* Startup frame */
1184  remmina_public_create_group(GTK_GRID(grid), _("Start-up"), 4, 1, 2);
1185 
1186  /* Autostart profile option */
1187  priv->behavior_autostart_check = remmina_file_editor_create_check(gfe, grid, 6, 1, _("Auto-start this profile"),
1188  remmina_file_get_int(priv->remmina_file, "enable-autostart", FALSE), "enable-autostart");
1189 
1190  /* Startup frame */
1191  remmina_public_create_group(GTK_GRID(grid), _("Connection profile security"), 8, 1, 2);
1192 
1193  /* Autostart profile option */
1194  priv->behavior_lock_check = remmina_file_editor_create_check(gfe, grid, 10, 1, _("Require password to connect or edit the profile"),
1195  remmina_file_get_int(priv->remmina_file, "profile-lock", FALSE), "profile-lock");
1196 
1197  /* Startup frame */
1198  remmina_public_create_group(GTK_GRID(grid), _("Unexpected disconnect"), 12, 1, 2);
1199 
1200  /* Autostart profile option */
1201  priv->behavior_disconnect = remmina_file_editor_create_check(gfe, grid, 16, 1, _("Keep window from closing if not disconnected by Remmina"),
1202  remmina_file_get_int(priv->remmina_file, "disconnect-prompt", FALSE), "disconnect-prompt");
1203 }
1204 
1205 #ifdef HAVE_LIBSSH
1206 static gpointer ssh_tunnel_auth_list[] =
1207 {
1208  "0", N_("Password"),
1209  "1", N_("SSH identity file"),
1210  "2", N_("SSH agent"),
1211  "3", N_("Public key (automatic)"),
1212  "4", N_("Kerberos (GSSAPI)"),
1213  NULL
1214 };
1215 #endif
1216 
1218 {
1219  TRACE_CALL(__func__);
1220 #ifdef HAVE_LIBSSH
1221  RemminaFileEditorPriv *priv = gfe->priv;
1222  GtkWidget *grid;
1223  GtkWidget *widget;
1224  const gchar *cs;
1225  gchar *s;
1226  gchar *p;
1227  gint row = 0;
1228 
1229  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_NONE)
1230  return;
1231 
1232  /* The SSH tab (implementation) */
1233  grid = remmina_file_editor_create_notebook_tab(gfe, NULL,
1234  _("SSH Tunnel"), 9, 3);
1235  widget = gtk_toggle_button_new_with_label(_("Enable SSH tunnel"));
1236  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1237  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1238  g_signal_connect(G_OBJECT(widget), "toggled",
1240  priv->ssh_tunnel_enabled_check = widget;
1241 
1242  widget = gtk_check_button_new_with_label(_("Tunnel via loopback address"));
1243  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1244  priv->ssh_tunnel_loopback_check = widget;
1245 
1246  // 1
1247  row++;
1248  /* SSH Server group */
1249 
1250  switch (ssh_setting) {
1252  s = g_strdup_printf(_("Same server at port %i"), DEFAULT_SSH_PORT);
1253  widget = gtk_radio_button_new_with_label(NULL, s);
1254  g_free(s);
1255  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 3, 1);
1256  priv->ssh_tunnel_server_default_radio = widget;
1257  // 2
1258  row++;
1259 
1260  widget = gtk_radio_button_new_with_label_from_widget(
1261  GTK_RADIO_BUTTON(priv->ssh_tunnel_server_default_radio), _("Custom"));
1262  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1263  g_signal_connect(G_OBJECT(widget), "toggled",
1265  priv->ssh_tunnel_server_custom_radio = widget;
1266 
1267  widget = gtk_entry_new();
1268  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
1269  gtk_widget_set_tooltip_markup(widget, _(server_tips2));
1270  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1271  priv->ssh_tunnel_server_entry = widget;
1272  // 3
1273  row++;
1274  break;
1275 
1277  priv->ssh_tunnel_server_default_radio = NULL;
1278  priv->ssh_tunnel_server_custom_radio = NULL;
1279 
1280  priv->ssh_tunnel_server_entry = remmina_file_editor_create_text(gfe, grid, 1, 0,
1281  _("Server"), NULL, "ssh_reverse_tunnel_server");
1282  gtk_widget_set_tooltip_markup(priv->ssh_tunnel_server_entry, _(server_tips));
1283  // 2
1284  row++;
1285  break;
1288  priv->ssh_tunnel_server_default_radio = NULL;
1289  priv->ssh_tunnel_server_custom_radio = NULL;
1290  priv->ssh_tunnel_server_entry = NULL;
1291 
1292  break;
1293 
1294  default:
1295  break;
1296  }
1297 
1298  /* This is not used? */
1299  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
1300  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_SFTP) {
1301  widget = remmina_file_editor_create_text(gfe, grid, row, 1,
1302  _("Start-up path"), NULL, "start-up-path");
1303  cs = remmina_file_get_string(priv->remmina_file, "execpath");
1304  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
1305  g_hash_table_insert(priv->setting_widgets, "execpath", widget);
1306  // 2
1307  row++;
1308  }
1309 
1310  /* SSH Authentication frame */
1311  remmina_public_create_group(GTK_GRID(grid), _("SSH Authentication"), row, 6, 1);
1312  // 5
1313  row += 2;
1314 
1315  priv->ssh_tunnel_auth_combo = remmina_file_editor_create_select(gfe, grid, row, 0,
1316  _("Authentication type"),
1317  (const gpointer *)ssh_tunnel_auth_list,
1318  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_auth"), "ssh_tunnel_auth");
1319  row++;
1320 
1321  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL ||
1323  priv->ssh_tunnel_username_entry =
1324  remmina_file_editor_create_text(gfe, grid, row, 0,
1325  _("Username"), NULL, "ssh_tunnel_username");
1326  // 5
1327  row++;
1328  }
1329 
1330  widget = remmina_file_editor_create_password(gfe, grid, row, 0,
1331  _("Password"),
1332  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_password"),
1333  "ssh_tunnel_password");
1334  priv->ssh_tunnel_auth_password = widget;
1335  row++;
1336 
1337  priv->ssh_tunnel_privatekey_chooser = remmina_file_editor_create_chooser(gfe, grid, row, 0,
1338  _("SSH private key file"),
1339  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_privatekey"),
1340  GTK_FILE_CHOOSER_ACTION_OPEN, "ssh_tunnel_privatekey");
1341  row++;
1342 
1343  priv->ssh_tunnel_certfile_chooser = remmina_file_editor_create_chooser(gfe, grid, row, 0,
1344  _("SSH certificate file"),
1345  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_certfile"),
1346  GTK_FILE_CHOOSER_ACTION_OPEN, "ssh_tunnel_certfile");
1347  row++;
1348 
1349  widget = gtk_label_new(_("Password to unlock private key"));
1350  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1351  widget = gtk_entry_new();
1352  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1353  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
1354  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
1355  gtk_widget_set_hexpand(widget, TRUE);
1356  priv->ssh_tunnel_passphrase = widget;
1357  row++;
1358 
1359  /* Set the values */
1360  cs = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_server");
1361  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL) {
1362  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
1363  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
1364  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
1365  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
1366 
1367  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs ? priv->ssh_tunnel_server_custom_radio : priv->ssh_tunnel_server_default_radio), TRUE);
1368  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
1369  cs ? cs : "");
1370  } else if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_REVERSE_TUNNEL) {
1371  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
1372  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
1373  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
1374  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
1375  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
1376  cs ? cs : "");
1377  }
1378 
1380  gtk_widget_show_all(grid);
1381  g_free(p);
1382 #endif
1383 }
1384 
1386 {
1387  TRACE_CALL(__func__);
1388  RemminaFileEditorPriv *priv = gfe->priv;
1389  GtkWidget *grid;
1390 
1391  static const RemminaProtocolSetting notes_settings[] =
1392  {
1393  { REMMINA_PROTOCOL_SETTING_TYPE_TEXTAREA, "notes_text", NULL, FALSE, NULL, NULL },
1394  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
1395  };
1396 
1398 
1399  /* The Basic tab */
1400  if (priv->plugin->basic_settings) {
1401  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Basic"), 20, 2);
1402  remmina_file_editor_create_settings(gfe, grid, priv->plugin->basic_settings);
1403  }
1404 
1405  /* The Advanced tab */
1406  if (priv->plugin->advanced_settings) {
1407  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Advanced"), 20, 2);
1408  remmina_file_editor_create_settings(gfe, grid, priv->plugin->advanced_settings);
1409  }
1410 
1411  /* The Behavior tab */
1413 
1414  /* The SSH tab */
1415  remmina_file_editor_create_ssh_tunnel_tab(gfe, priv->plugin->ssh_setting);
1416 
1417  /* Notes tab */
1418  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Notes"), 1, 1);
1419  remmina_file_editor_create_settings(gfe, grid, notes_settings);
1420 }
1421 
1423 {
1424  TRACE_CALL(__func__);
1425  RemminaFileEditorPriv *priv = gfe->priv;
1426  gchar *protocol;
1427 
1428  if (priv->config_container) {
1429  gtk_widget_destroy(priv->config_container);
1430  priv->config_container = NULL;
1431  gtk_widget_destroy(priv->config_viewport);
1432  priv->config_viewport = NULL;
1433  gtk_widget_destroy(priv->config_scrollable);
1434  priv->config_scrollable = NULL;
1435  }
1436 
1437  priv->server_combo = NULL;
1438  priv->resolution_iws_radio = NULL;
1439  priv->resolution_auto_radio = NULL;
1440  priv->resolution_custom_radio = NULL;
1441  priv->resolution_custom_combo = NULL;
1442  priv->keymap_combo = NULL;
1443 
1444  priv->ssh_tunnel_enabled_check = NULL;
1445  priv->ssh_tunnel_loopback_check = NULL;
1446  priv->ssh_tunnel_server_default_radio = NULL;
1447  priv->ssh_tunnel_server_custom_radio = NULL;
1448  priv->ssh_tunnel_server_entry = NULL;
1449  priv->ssh_tunnel_username_entry = NULL;
1450  priv->ssh_tunnel_auth_combo = NULL;
1451  priv->ssh_tunnel_auth_password = NULL;
1452  priv->ssh_tunnel_privatekey_chooser = NULL;
1453  priv->ssh_tunnel_certfile_chooser = NULL;
1454 
1455  g_hash_table_remove_all(priv->setting_widgets);
1456 
1457  protocol = remmina_public_combo_get_active_text(combo);
1458  if (protocol) {
1460  protocol);
1461  g_free(protocol);
1463  }
1464 }
1465 
1467 {
1468  TRACE_CALL(__func__);
1469  RemminaFileEditorPriv *priv = gfe->priv;
1470 
1471  remmina_file_set_string(priv->remmina_file, "precommand", gtk_entry_get_text(GTK_ENTRY(priv->behavior_precommand_entry)));
1472  remmina_file_set_string(priv->remmina_file, "postcommand", gtk_entry_get_text(GTK_ENTRY(priv->behavior_postcommand_entry)));
1473 
1474  gboolean autostart_enabled = (priv->behavior_autostart_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_autostart_check)) : FALSE);
1475  remmina_file_set_int(priv->remmina_file, "enable-autostart", autostart_enabled);
1476  gboolean lock_enabled = (priv->behavior_lock_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_lock_check)) : FALSE);
1477  remmina_file_set_int(priv->remmina_file, "profile-lock", lock_enabled);
1478  gboolean disconect_prompt = (priv->behavior_disconnect ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_disconnect)) : FALSE);
1479  remmina_file_set_int(priv->remmina_file, "disconnect-prompt", disconect_prompt);
1480 }
1481 
1483 {
1484  TRACE_CALL(__func__);
1485  RemminaFileEditorPriv *priv = gfe->priv;
1486  gboolean ssh_tunnel_enabled;
1487  int ssh_tunnel_auth;
1488 
1489  ssh_tunnel_enabled = (priv->ssh_tunnel_enabled_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check)) : FALSE);
1490  remmina_file_set_int(priv->remmina_file,
1491  "ssh_tunnel_loopback",
1492  (priv->ssh_tunnel_loopback_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check)) : FALSE));
1493  remmina_file_set_int(priv->remmina_file, "ssh_tunnel_enabled", ssh_tunnel_enabled);
1494  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_auth",
1495  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->ssh_tunnel_auth_combo)));
1496  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_username",
1497  (ssh_tunnel_enabled ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_username_entry)) : NULL));
1499  priv->remmina_file,
1500  "ssh_tunnel_server",
1501  (ssh_tunnel_enabled && priv->ssh_tunnel_server_entry && (priv->ssh_tunnel_server_custom_radio == NULL || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_server_custom_radio))) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_server_entry)) : NULL));
1502 
1503  ssh_tunnel_auth = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->ssh_tunnel_auth_combo));
1504 
1506  priv->remmina_file,
1507  "ssh_tunnel_auth",
1508  ssh_tunnel_auth);
1509 
1510  // If box is unchecked for private key and certfile file choosers,
1511  // set the string to NULL in the remmina file
1512  if (gtk_widget_get_sensitive(priv->ssh_tunnel_privatekey_chooser)) {
1514  priv->remmina_file,
1515  "ssh_tunnel_privatekey",
1516  (priv->ssh_tunnel_privatekey_chooser ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_privatekey_chooser)) : NULL));
1517  }
1518  else {
1519  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_privatekey", NULL);
1520  }
1521 
1522  if (gtk_widget_get_sensitive(priv->ssh_tunnel_certfile_chooser)) {
1524  priv->remmina_file,
1525  "ssh_tunnel_certfile",
1526  (priv->ssh_tunnel_certfile_chooser ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_certfile_chooser)) : NULL));
1527  }
1528  else {
1529  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_certfile", NULL);
1530  }
1531 
1533  priv->remmina_file,
1534  "ssh_tunnel_password",
1535  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PASSWORD)) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_auth_password)) : NULL);
1536 
1538  priv->remmina_file,
1539  "ssh_tunnel_passphrase",
1540  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PUBLICKEY || ssh_tunnel_auth == SSH_AUTH_AUTO_PUBLICKEY)) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_passphrase)) : NULL);
1541 }
1542 
1544  gchar * setting_name_to_validate,
1545  gconstpointer value,
1546  GError ** err)
1547 {
1548  if (!setting_name_to_validate || !value || !gfe) {
1549  if (!setting_name_to_validate) {
1550  g_critical(_("(%s: %i): Can't validate setting '%s' since 'value' or 'gfe' "
1551  "are NULL!"),
1552  __func__, __LINE__, setting_name_to_validate);
1553  } else {
1554  g_critical(_("(%s: %i): Can't validate user input since "
1555  "'setting_name_to_validate', 'value' or 'gfe' are NULL!"),
1556  __func__, __LINE__);
1557  }
1558  g_set_error(err, 1, 1, _("Internal error."));
1559  return FALSE;
1560  }
1561 
1562  if (strcmp(setting_name_to_validate, "notes_text") == 0) {
1563  // Not a plugin setting. Bail out early.
1564  return TRUE;
1565  }
1566 
1567  const RemminaProtocolSetting *setting_iter;
1568  RemminaProtocolPlugin *protocol_plugin;
1569  RemminaFileEditorPriv *priv = gfe->priv;
1570  protocol_plugin = priv->plugin;
1571 
1572  setting_iter = protocol_plugin->basic_settings;
1573  if (setting_iter) {
1574  // gboolean found = FALSE;
1575  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
1576  if (setting_iter->name == NULL) {
1577  g_error("Internal error: a setting name in protocol plugin %s is "
1578  "null. Please fix RemminaProtocolSetting struct content.",
1579  protocol_plugin->name);
1580  } else if ((gchar *)setting_name_to_validate) {
1581  if (strcmp((gchar *)setting_name_to_validate, setting_iter->name) == 0) {
1582  // found = TRUE;
1583 
1584  gpointer validator_data = setting_iter->validator_data;
1585  GCallback validator = setting_iter->validator;
1586 
1587  // Default behaviour is that everything is valid,
1588  // except a validator is given and its returned GError is not NULL.
1589  GError *err_ret = NULL;
1590 
1591  g_debug("Checking setting '%s' for validation.", setting_iter->name);
1592  if (validator != NULL) {
1593  // Looks weird but it calls the setting's validator
1594  // function using setting_name_to_validate, value and
1595  // validator_data as parameters and it returns a GError*.
1596  err_ret = ((GError * (*)(gpointer, gconstpointer, gpointer)) validator)(setting_name_to_validate, value, validator_data);
1597  }
1598 
1599  if (err_ret) {
1600  g_debug("it has a validator function and it had an error!");
1601  // pass err (returned value) to function caller.
1602  *err = err_ret;
1603  return FALSE;
1604  }
1605 
1606  break;
1607  }
1608  }
1609  setting_iter++;
1610  }
1611 
1612  // if (!found) {
1613  // TOO VERBOSE:
1614  // g_warning("%s is not a plugin setting!", setting_name_to_validate);
1615  // }
1616  }
1617 
1618  return TRUE;
1619 }
1620 
1622  GtkWidget ** failed_widget)
1623 {
1624  TRACE_CALL(__func__);
1625  RemminaFileEditorPriv *priv = gfe->priv;
1626  GHashTableIter iter;
1627  gpointer key;
1628  gpointer widget;
1629  GtkTextBuffer *buffer;
1630  gchar *escaped, *unescaped;
1631  GtkTextIter start, end;
1632 
1633  GError *err = NULL;
1634  *failed_widget = NULL;
1635 
1636  g_hash_table_iter_init(&iter, priv->setting_widgets);
1637  while (g_hash_table_iter_next(&iter, &key, &widget)) {
1638 
1639  // We don't want to save or validate grayed-out settings.
1640  // If widget is a file chooser, it was made not sensitive because
1641  // the box was unchecked. In that case, don't continue. The
1642  // relevant file strings will be set to NULL in the remmina file.
1643  if (!gtk_widget_get_sensitive(GTK_WIDGET(widget)) && !GTK_IS_FILE_CHOOSER(widget)) {
1644  g_debug("Grayed-out setting-widget '%s' will not be saved.",
1645  gtk_widget_get_name(widget));
1646  continue;
1647  }
1648 
1649  if (GTK_IS_ENTRY(widget)) {
1650  const gchar *value = gtk_entry_get_text(GTK_ENTRY(widget));
1651 
1652  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1653  // Error while validating!
1654  // err should be set now.
1655  *failed_widget = widget;
1656  break;
1657  }
1658 
1659  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1660  } else if (GTK_IS_TEXT_VIEW(widget)) {
1661  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
1662  gtk_text_buffer_get_start_iter(buffer, &start);
1663  gtk_text_buffer_get_end_iter(buffer, &end);
1664  unescaped = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1665  escaped = g_uri_escape_string(unescaped, NULL, TRUE);
1666 
1667  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, escaped, &err)) {
1668  // Error while validating!
1669  // err should be set now.
1670  *failed_widget = widget;
1671  break;
1672  }
1673 
1674  remmina_file_set_string(priv->remmina_file, (gchar *)key, escaped);
1675  g_free(escaped);
1676  } else if (GTK_IS_COMBO_BOX(widget)) {
1677  gchar *value = remmina_public_combo_get_active_text(GTK_COMBO_BOX(widget));
1678 
1679  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1680  // Error while validating!
1681  // err should be set now.
1682  *failed_widget = widget;
1683  break;
1684  }
1685 
1686  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1687  } else if (GTK_IS_FILE_CHOOSER(widget)) {
1688  gchar *value = gtk_widget_get_sensitive(GTK_WIDGET(widget)) ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)) : NULL;
1689 
1690  if (!gtk_widget_get_sensitive(GTK_WIDGET(widget))) {
1691  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1692  continue;
1693  }
1694 
1695  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1696  // Error while validating!
1697  // err should be set now.
1698  g_free(value);
1699  *failed_widget = widget;
1700  break;
1701  }
1702 
1703  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1704  g_free(value);
1705  } else if (GTK_IS_TOGGLE_BUTTON(widget)) {
1706  gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
1707 
1708  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, &value, &err)) {
1709  // Error while validating!
1710  // err should be set now.
1711  *failed_widget = widget;
1712  break;
1713  }
1714 
1715  remmina_file_set_int(priv->remmina_file, (gchar *)key, value);
1716  }
1717  }
1718 
1719  if (err) {
1720  return err;
1721  }
1722 
1723  return NULL;
1724 }
1725 
1727  GtkWidget ** failed_widget)
1728 {
1729  TRACE_CALL(__func__);
1730  int res_w, res_h;
1731  gchar *custom_resolution;
1733 
1734  RemminaFileEditorPriv *priv = gfe->priv;
1735 
1736  remmina_file_set_string(priv->remmina_file, "name", gtk_entry_get_text(GTK_ENTRY(priv->name_entry)));
1737 
1738  remmina_file_set_string(priv->remmina_file, "labels", gtk_entry_get_text(GTK_ENTRY(priv->labels_entry)));
1739 
1740  remmina_file_set_string(priv->remmina_file, "group",
1741  (priv->group_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->group_combo)) : NULL));
1742 
1743  remmina_file_set_string(priv->remmina_file, "protocol",
1744  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo)));
1745 
1746  remmina_file_set_string(priv->remmina_file, "server",
1747  (priv->server_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->server_combo)) : NULL));
1748 
1749  if (priv->resolution_auto_radio) {
1750  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_auto_radio))) {
1751  /* Resolution is set to auto (which means: Use client fullscreen resolution, aka use client resolution) */
1752  res_w = res_h = 0;
1753  res_mode = RES_USE_CLIENT;
1754  } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_iws_radio))) {
1755  /* Resolution is set to initial window size */
1756  res_w = res_h = 0;
1757  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1758  } else {
1759  /* Resolution is set to a value from the list */
1760  custom_resolution = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->resolution_custom_combo));
1761  if (remmina_public_split_resolution_string(custom_resolution, &res_w, &res_h))
1762  res_mode = RES_USE_CUSTOM;
1763  else
1764  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1765  g_free(custom_resolution);
1766  }
1767  remmina_file_set_int(priv->remmina_file, "resolution_mode", res_mode);
1768  remmina_file_set_int(priv->remmina_file, "resolution_width", res_w);
1769  remmina_file_set_int(priv->remmina_file, "resolution_height", res_h);
1770  }
1771 
1772  if (priv->assistance_toggle){
1773  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->assistance_toggle))) {
1774  remmina_file_set_string(priv->remmina_file, "assistance_file", gtk_entry_get_text(GTK_ENTRY(priv->assistance_file)));
1775  remmina_file_set_string(priv->remmina_file, "assistance_pass", gtk_entry_get_text(GTK_ENTRY(priv->assistance_password)));
1776  remmina_file_set_int(priv->remmina_file, "assistance_mode", 1);
1777  }else{
1778  remmina_file_set_int(priv->remmina_file, "assistance_mode", 0);
1779  }
1780 
1781  }
1782 
1783  if (priv->keymap_combo)
1784  remmina_file_set_string(priv->remmina_file, "keymap",
1785  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->keymap_combo)));
1786 
1789  return remmina_file_editor_update_settings(gfe, failed_widget);
1790 }
1791 
1792 static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
1793 {
1794  TRACE_CALL(__func__);
1795  RemminaFile *gf;
1796  GtkWidget *dialog;
1797 
1798  GtkWidget *failed_widget = NULL;
1799  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1800  if (err) {
1801  g_warning(_("Couldn't validate user input. %s"), err->message);
1802  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1803  return;
1804  }
1805 
1806  gf = remmina_file_dup(gfe->priv->remmina_file);
1807 
1809 
1810  /* Clear properties that should never be default */
1811  remmina_file_set_string(gf, "name", NULL);
1812  remmina_file_set_string(gf, "server", NULL);
1813  remmina_file_set_string(gf, "password", NULL);
1814  remmina_file_set_string(gf, "precommand", NULL);
1815  remmina_file_set_string(gf, "postcommand", NULL);
1816 
1817  remmina_file_set_string(gf, "ssh_tunnel_server", NULL);
1818  remmina_file_set_string(gf, "ssh_tunnel_password", NULL);
1819  remmina_file_set_string(gf, "ssh_tunnel_passphrase", NULL);
1820 
1821  remmina_file_save(gf);
1822  remmina_file_free(gf);
1823 
1824  dialog = gtk_message_dialog_new(GTK_WINDOW(gfe), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
1825  GTK_BUTTONS_OK, _("Default settings saved."));
1826  gtk_dialog_run(GTK_DIALOG(dialog));
1827  gtk_widget_destroy(dialog);
1828 }
1829 
1830 static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
1831 {
1832  TRACE_CALL(__func__);
1833 
1834  GtkWidget *failed_widget = NULL;
1835  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1836  if (err) {
1837  g_warning(_("Couldn't validate user input. %s"), err->message);
1838  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1839  return;
1840  }
1841 
1843 
1844  remmina_file_save(gfe->priv->remmina_file);
1846 
1847  gtk_widget_destroy(GTK_WIDGET(gfe));
1848 }
1849 
1850 static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
1851 {
1852  TRACE_CALL(__func__);
1853  RemminaFile *gf;
1854 
1855  GtkWidget *failed_widget = NULL;
1856  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1857  if (err) {
1858  g_warning(_("Couldn't validate user input. %s"), err->message);
1859  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1860  return;
1861  }
1862 
1863  gf = remmina_file_dup(gfe->priv->remmina_file);
1864  /* Put server into name for "Quick Connect" */
1865  if (remmina_file_get_filename(gf) == NULL)
1866  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1867  gtk_widget_destroy(GTK_WIDGET(gfe));
1868  gf->prevent_saving = TRUE;
1869  rcw_open_from_file(gf);
1870 }
1871 
1872 static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
1873 {
1874  TRACE_CALL(__func__);
1876  RemminaFile *gf;
1877 
1878  GtkWidget *failed_widget = NULL;
1879  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1880  if (err) {
1881  g_warning(_("Couldn't validate user input. %s"), err->message);
1882  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1883  return;
1884  }
1885 
1887 
1888  remmina_file_save(gfe->priv->remmina_file);
1890 
1891  gf = remmina_file_dup(gfe->priv->remmina_file);
1892  /* Put server into name for Quick Connect */
1893  if (remmina_file_get_filename(gf) == NULL)
1894  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1895  gtk_widget_destroy(GTK_WIDGET(gfe));
1896  rcw_open_from_file(gf);
1897 }
1898 
1899 static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
1900 {
1901  TRACE_CALL(__func__);
1902  gtk_widget_destroy(GTK_WIDGET(gfe));
1903 }
1904 
1906 {
1907  TRACE_CALL(__func__);
1908  RemminaFileEditorPriv *priv;
1909  GtkWidget *widget;
1910 
1911  priv = g_new0(RemminaFileEditorPriv, 1);
1912  gfe->priv = priv;
1913 
1914  /* Create the editor dialog */
1915  gtk_window_set_title(GTK_WINDOW(gfe), _("Remote Connection Profile"));
1916 
1917  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Cancel")), GTK_RESPONSE_CANCEL);
1918  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_cancel), gfe);
1919 
1920  /* Default button */
1921  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Save as Default")), GTK_RESPONSE_OK);
1922  gtk_widget_set_tooltip_text(GTK_WIDGET(widget), _("Use the current settings as the default for all new connection profiles"));
1923  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_default), gfe);
1924 
1925  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save")), GTK_RESPONSE_APPLY);
1926  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save), gfe);
1927  gtk_widget_set_sensitive(widget, FALSE);
1928  priv->save_button = widget;
1929 
1930  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Connect")), GTK_RESPONSE_ACCEPT);
1931  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_connect), gfe);
1932 
1933  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save and Connect")), GTK_RESPONSE_OK);
1934  gtk_widget_set_can_default(widget, TRUE);
1935  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save_connect), gfe);
1936 
1937  gtk_dialog_set_default_response(GTK_DIALOG(gfe), GTK_RESPONSE_OK);
1938  gtk_window_set_default_size(GTK_WINDOW(gfe), 800, 600);
1939 
1940  g_signal_connect(G_OBJECT(gfe), "destroy", G_CALLBACK(remmina_file_editor_destroy), NULL);
1941  g_signal_connect(G_OBJECT(gfe), "realize", G_CALLBACK(remmina_file_editor_on_realize), NULL);
1942 
1943  priv->setting_widgets = g_hash_table_new(g_str_hash, g_str_equal);
1944 
1945  remmina_widget_pool_register(GTK_WIDGET(gfe));
1946 }
1947 
1948 static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
1949 {
1950  TRACE_CALL(__func__);
1951  RemminaFileEditor *gfe = REMMINA_FILE_EDITOR(data);
1952  GtkListStore *store;
1953  GtkTreeIter iter;
1954  gboolean first;
1955 
1956  store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gfe->priv->protocol_combo)));
1957 
1958  first = !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1959 
1960  gtk_list_store_append(store, &iter);
1961  gtk_list_store_set(store, &iter, 0, protocol, 1, g_dgettext(plugin->domain, plugin->description), 2,
1962  ((RemminaProtocolPlugin *)plugin)->icon_name, -1);
1963 
1964  if (first || g_strcmp0(protocol, remmina_file_get_string(gfe->priv->remmina_file, "protocol")) == 0)
1965  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(gfe->priv->protocol_combo), &iter);
1966 
1967  return FALSE;
1968 }
1969 
1971 {
1972  TRACE_CALL(__func__);
1973  RemminaFileEditorPriv *priv;
1974 
1975  priv = gfe->priv;
1976  gtk_widget_set_sensitive(priv->group_combo, TRUE);
1977  gtk_widget_set_sensitive(priv->save_button, TRUE);
1978 }
1979 
1980 static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
1981 {
1982  TRACE_CALL(__func__);
1983  RemminaFileEditorPriv *priv;
1984 
1985  priv = gfe->priv;
1986  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
1987  remmina_file_generate_filename(priv->remmina_file);
1988  /* TODO: Probably to be removed */
1990  } else {
1991  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
1992  remmina_file_generate_filename(priv->remmina_file);
1994  }
1995 }
1996 
1998 {
1999  TRACE_CALL(__func__);
2000  RemminaFileEditorPriv *priv;
2001 
2002  priv = gfe->priv;
2003  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
2004  remmina_file_generate_filename(priv->remmina_file);
2005  } else {
2006  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
2007  remmina_file_generate_filename(priv->remmina_file);
2008  }
2009 }
2010 
2012 {
2013  TRACE_CALL(__func__);
2014  RemminaFileEditor *gfe;
2015  RemminaFileEditorPriv *priv;
2016  GtkWidget *grid;
2017  GtkWidget *widget;
2018  gchar *groups;
2019  gchar *s;
2020  const gchar *cs;
2021 
2022  gfe = REMMINA_FILE_EDITOR(g_object_new(REMMINA_TYPE_FILE_EDITOR, NULL));
2023  priv = gfe->priv;
2024  priv->remmina_file = remminafile;
2025 
2026  if (remmina_file_get_filename(remminafile) == NULL)
2027  gtk_dialog_set_response_sensitive(GTK_DIALOG(gfe), GTK_RESPONSE_APPLY, FALSE);
2028 
2029  /* Create the "Profile" group on the top (for name and protocol) */
2030  grid = gtk_grid_new();
2031  gtk_widget_show(grid);
2032  gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
2033  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
2034  gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
2035  gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
2036  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), grid, FALSE, FALSE, 2);
2037 
2038  // remmina_public_create_group(GTK_GRID(grid), _("Profile"), 0, 4, 3);
2039 
2040  gboolean profile_file_exists = (remmina_file_get_filename(remminafile) != NULL);
2041 
2042  /* Profile: Name */
2043  widget = gtk_label_new(_("Name"));
2044  gtk_widget_show(widget);
2045  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2046  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2047  gtk_grid_attach(GTK_GRID(grid), widget, 0, 3, 2, 1);
2048  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
2049 
2050  widget = gtk_entry_new();
2051  gtk_widget_show(widget);
2052  gtk_grid_attach(GTK_GRID(grid), widget, 1, 3, 3, 1);
2053  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
2054  priv->name_entry = widget;
2055 
2056  if (!profile_file_exists) {
2057  gtk_entry_set_text(GTK_ENTRY(widget), _("Quick Connect"));
2058 #if GTK_CHECK_VERSION(3, 16, 0)
2059  gtk_entry_grab_focus_without_selecting(GTK_ENTRY(widget));
2060 #endif
2061  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_entry_on_changed), gfe);
2062  } else {
2063  cs = remmina_file_get_string(remminafile, "name");
2064  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
2065  }
2066 
2067  /* Profile: Group */
2068  widget = gtk_label_new(_("Group"));
2069  gtk_widget_show(widget);
2070  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2071  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2072  gtk_grid_attach(GTK_GRID(grid), widget, 0, 6, 2, 1);
2073 
2075  priv->group_combo = remmina_public_create_combo_entry(groups, remmina_file_get_string(remminafile, "group"), FALSE);
2076  g_free(groups);
2077  gtk_widget_show(priv->group_combo);
2078  gtk_grid_attach(GTK_GRID(grid), priv->group_combo, 1, 6, 3, 1);
2079  gtk_widget_set_sensitive(priv->group_combo, FALSE);
2080 
2081  s = g_strdup_printf(_("Use '%s' as subgroup delimiter"), "/");
2082  gtk_widget_set_tooltip_text(priv->group_combo, s);
2083  g_free(s);
2084 
2085  /* Profile: Labels */
2086  widget = gtk_label_new(_("Labels"));
2087  gtk_widget_show(widget);
2088  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2089  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2090  gtk_grid_attach(GTK_GRID(grid), widget, 0, 9, 2, 1);
2091  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
2092 
2093  widget = gtk_entry_new();
2094  gtk_widget_show(widget);
2095  gtk_grid_attach(GTK_GRID(grid), widget, 1, 9, 3, 1);
2096  gtk_entry_set_max_length(GTK_ENTRY(widget), 255);
2097  priv->labels_entry = widget;
2098 
2099  if (!profile_file_exists) {
2100  gtk_widget_set_tooltip_text(widget, _("Label1,Label2"));
2101 #if GTK_CHECK_VERSION(3, 16, 0)
2102  gtk_entry_grab_focus_without_selecting(GTK_ENTRY(widget));
2103 #endif
2104  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_entry_on_changed), gfe);
2105  } else {
2106  cs = remmina_file_get_string(remminafile, "labels");
2107  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
2108  }
2109 
2110  /* Profile: Protocol */
2111  widget = gtk_label_new(_("Protocol"));
2112  gtk_widget_show(widget);
2113  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2114  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2115  gtk_grid_attach(GTK_GRID(grid), widget, 0, 12, 2, 1);
2116 
2117  widget = remmina_public_create_combo(TRUE);
2118  gtk_widget_show(widget);
2119  gtk_grid_attach(GTK_GRID(grid), widget, 1, 12, 3, 1);
2120  priv->protocol_combo = widget;
2122  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_protocol_combo_on_changed), gfe);
2123 
2124  /* Create the "Preference" frame */
2125  widget = gtk_event_box_new();
2126  gtk_widget_show(widget);
2127  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), widget, TRUE, TRUE, 2);
2128  priv->config_box = widget;
2129 
2130  priv->config_container = NULL;
2131  priv->config_scrollable = NULL;
2132 
2133  remmina_file_editor_protocol_combo_on_changed(GTK_COMBO_BOX(priv->protocol_combo), gfe);
2134 
2136 
2137  return GTK_WIDGET(gfe);
2138 }
2139 
2140 GtkWidget *remmina_file_editor_new(void)
2141 {
2142  TRACE_CALL(__func__);
2143  return remmina_file_editor_new_full(NULL, NULL);
2144 }
2145 
2146 GtkWidget *remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
2147 {
2148  TRACE_CALL(__func__);
2149  RemminaFile *remminafile;
2150 
2151  remminafile = remmina_file_new();
2152  if (server)
2153  remmina_file_set_string(remminafile, "server", server);
2154  if (protocol)
2155  remmina_file_set_string(remminafile, "protocol", protocol);
2156 
2157  return remmina_file_editor_new_from_file(remminafile);
2158 }
2159 
2160 GtkWidget *remmina_file_editor_new_copy(const gchar *filename)
2161 {
2162  TRACE_CALL(__func__);
2163  RemminaFile *remminafile;
2164  GtkWidget *dialog;
2165 
2166  remminafile = remmina_file_copy(filename);
2167 
2168  if (remminafile) {
2169  return remmina_file_editor_new_from_file(remminafile);
2170  } else {
2171  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
2172  _("Could not find the file “%s”."), filename);
2173  gtk_dialog_run(GTK_DIALOG(dialog));
2174  gtk_widget_destroy(dialog);
2175  return NULL;
2176  }
2177 }
2178 
2179 GtkWidget *remmina_file_editor_new_from_filename(const gchar *filename)
2180 {
2181  TRACE_CALL(__func__);
2182  RemminaFile *remminafile;
2183 
2184  remminafile = remmina_file_manager_load_file(filename);
2185  if (remminafile) {
2186  if (remmina_file_get_int(remminafile, "profile-lock", FALSE) && remmina_unlock_new(remmina_main_get_window()) == 0)
2187  return NULL;
2188  return remmina_file_editor_new_from_file(remminafile);
2189  } else {
2190  GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
2191  _("Could not find the file “%s”."), filename);
2192  gtk_dialog_run(GTK_DIALOG(dialog));
2193  gtk_widget_destroy(dialog);
2194  return NULL;
2195  }
2196 }
+Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #include <ctype.h>
38 #include "config.h"
39 #ifdef HAVE_LIBAVAHI_UI
40 #include <avahi-ui/avahi-ui.h>
41 #endif
42 #include "remmina_public.h"
43 #include "remmina_pref.h"
44 #include "rcw.h"
46 #include "remmina_file.h"
47 #include "remmina_file_editor.h"
48 #include "remmina_file_manager.h"
49 #include "remmina_icon.h"
50 #include "remmina_main.h"
51 #include "remmina_plugin_manager.h"
52 #include "remmina_pref_dialog.h"
53 #include "remmina_ssh.h"
54 #include "remmina_string_list.h"
55 #include "remmina_unlock.h"
56 #include "remmina_widget_pool.h"
57 
58 G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
59 
60 static const gchar *server_tips = N_("<big>"
61  "Supported formats\n"
62  "• server\n"
63  "• server[:port]\n"
64  "VNC additional formats\n"
65  "• ID:repeater ID number\n"
66  "• unix:///path/socket.sock"
67  "</big>");
68 
69 static const gchar *cmd_tips = N_("<big>"
70  "• command in PATH args %h\n"
71  "• /path/to/foo -options %h %u\n"
72  "• %h is substituted with the server name\n"
73  "• %t is substituted with the SSH server name\n"
74  "• %u is substituted with the username\n"
75  "• %U is substituted with the SSH username\n"
76  "• %p is substituted with Remmina profile name\n"
77  "• %g is substituted with Remmina profile group name\n"
78  "• %d is substituted with local date and time in ISO 8601 format\n"
79  "Do not run in background if you want the command to be executed before connecting.\n"
80  "</big>");
81 
82 #ifdef HAVE_LIBSSH
83 static const gchar *server_tips2 = N_("<big>"
84  "Supported formats\n"
85  "• server\n"
86  "• server[:port]\n"
87  "• username@server[:port] (SSH protocol only)"
88  "</big>");
89 #endif
90 
91 struct _RemminaFileEditorPriv {
92  RemminaFile * remmina_file;
93  RemminaProtocolPlugin * plugin;
94  const gchar * avahi_service_type;
95 
96  GtkWidget * name_entry;
97  GtkWidget * labels_entry;
98  GtkWidget * group_combo;
99  GtkWidget * protocol_combo;
100  GtkWidget * save_button;
101 
102  GtkWidget * config_box;
103  GtkWidget * config_scrollable;
104  GtkWidget * config_viewport;
105  GtkWidget * config_container;
106 
107  GtkWidget * server_combo;
108  GtkWidget * resolution_iws_radio;
109  GtkWidget * resolution_auto_radio;
110  GtkWidget * resolution_custom_radio;
111  GtkWidget * resolution_custom_combo;
112  GtkWidget * keymap_combo;
113 
114  GtkWidget * assistance_toggle;
115  GtkWidget * assistance_file;
116  GtkWidget * assistance_password;
117  GtkWidget * assistance_file_label;
118  GtkWidget * assistance_password_label;
119 
120  GtkWidget * behavior_autostart_check;
121  GtkWidget * behavior_precommand_entry;
122  GtkWidget * behavior_postcommand_entry;
123  GtkWidget * behavior_lock_check;
124  GtkWidget * behavior_disconnect;
125 
126  GtkWidget * ssh_tunnel_enabled_check;
127  GtkWidget * ssh_tunnel_loopback_check;
128  GtkWidget * ssh_tunnel_server_default_radio;
129  GtkWidget * ssh_tunnel_server_custom_radio;
130  GtkWidget * ssh_tunnel_server_entry;
131  GtkWidget * ssh_tunnel_auth_agent_radio;
132  GtkWidget * ssh_tunnel_auth_password_radio;
133  GtkWidget * ssh_tunnel_auth_password;
134  GtkWidget * ssh_tunnel_passphrase;
135  GtkWidget * ssh_tunnel_auth_publickey_radio;
136  GtkWidget * ssh_tunnel_auth_auto_publickey_radio;
137  GtkWidget * ssh_tunnel_auth_combo;
138  GtkWidget * ssh_tunnel_username_entry;
139  GtkWidget * ssh_tunnel_privatekey_chooser;
140  GtkWidget * ssh_tunnel_certfile_chooser;
141 
142  GHashTable * setting_widgets;
143 };
144 
146 {
147  TRACE_CALL(__func__);
148 }
149 
166  GtkWidget * failed_widget,
167  GError * err)
168 {
169  if (!err) {
170  err = NULL; // g_set_error doesn't like overwriting errors.
171  g_set_error(&err, 1, 1, _("Input is invalid."));
172  }
173 
174  if (!gfe || !failed_widget) {
175  g_critical("(%s): Parameters RemminaFileEditor 'gfe' or "
176  "GtkWidget* 'failed_widget' are 'NULL'!",
177  __func__);
178  return;
179  }
180 
181  gint widget_width = gtk_widget_get_allocated_width(failed_widget);
182  gint widget_height = gtk_widget_get_allocated_height(failed_widget);
183 
184  GtkWidget *err_label = gtk_label_new("");
185  GtkWidget *alert_icon = NULL;
186  GtkWindow *err_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
187  GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
188  GdkWindow *window = gtk_widget_get_window(failed_widget);
189 
190  GtkAllocation allocation;
191  gint failed_widget_x, failed_widget_y;
192 
193  gchar *markup = g_strdup_printf("<span size='large'>%s</span>", err->message);
194 
195  // Setup err_window
196  gtk_window_set_decorated(err_window, FALSE);
197  gtk_window_set_type_hint(err_window, GDK_WINDOW_TYPE_HINT_TOOLTIP);
198  gtk_window_set_default_size(err_window, widget_width, widget_height);
199  gtk_window_set_title(err_window, "Error");
200  gtk_window_set_resizable(err_window, TRUE);
201 
202  // Move err_window under failed_widget
203  gtk_window_set_attached_to(err_window, failed_widget);
204  gtk_window_set_transient_for(err_window, GTK_WINDOW(gfe));
205  gdk_window_get_origin(GDK_WINDOW(window), &failed_widget_x, &failed_widget_y);
206  gtk_widget_get_allocation(failed_widget, &allocation);
207  failed_widget_x += allocation.x;
208  failed_widget_y += allocation.y + allocation.height;
209  gtk_window_move(err_window, failed_widget_x, failed_widget_y);
210 
211  // Setup label
212  gtk_label_set_selectable(GTK_LABEL(err_label), FALSE);
213  gtk_label_set_max_width_chars(GTK_LABEL(err_label), 1);
214  gtk_widget_set_hexpand(GTK_WIDGET(err_label), TRUE);
215  gtk_widget_set_vexpand(GTK_WIDGET(err_label), TRUE);
216  gtk_label_set_ellipsize(GTK_LABEL(err_label), PANGO_ELLIPSIZE_END);
217  gtk_label_set_line_wrap(GTK_LABEL(err_label), TRUE);
218  gtk_label_set_line_wrap_mode(GTK_LABEL(err_label), PANGO_WRAP_WORD_CHAR);
219  gtk_label_set_markup(GTK_LABEL(err_label), markup);
220 
221  alert_icon = gtk_image_new_from_icon_name("dialog-warning-symbolic",
222  GTK_ICON_SIZE_DND);
223 
224  // Fill icon and label into a box.
225  gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(alert_icon), FALSE, FALSE, 0);
226  gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(err_label), TRUE, TRUE, 5);
227 
228  // Attach box to err_window
229  gtk_container_add(GTK_CONTAINER(err_window), GTK_WIDGET(box));
230 
231  // Display everything.
232  gtk_widget_show_all(GTK_WIDGET(err_window));
233 
234  // Mouse click and focus-loss will delete the err_window.
235  g_signal_connect(G_OBJECT(err_window), "focus-out-event",
236  G_CALLBACK(gtk_window_close), NULL);
237  g_signal_connect(G_OBJECT(err_window), "button-press-event",
238  G_CALLBACK(gtk_window_close), NULL);
239 }
240 
241 #ifdef HAVE_LIBAVAHI_UI
242 
243 static void remmina_file_editor_browse_avahi(GtkWidget *button, RemminaFileEditor *gfe)
244 {
245  TRACE_CALL(__func__);
246  GtkWidget *dialog;
247  gchar *host;
248 
249  dialog = aui_service_dialog_new(_("Choose a Remote Desktop Server"),
250  GTK_WINDOW(gfe),
251  _("_Cancel"), GTK_RESPONSE_CANCEL,
252  _("_OK"), GTK_RESPONSE_ACCEPT,
253  NULL);
254 
255  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
256  aui_service_dialog_set_resolve_service(AUI_SERVICE_DIALOG(dialog), TRUE);
257  aui_service_dialog_set_resolve_host_name(AUI_SERVICE_DIALOG(dialog), TRUE);
258  aui_service_dialog_set_browse_service_types(AUI_SERVICE_DIALOG(dialog),
259  gfe->priv->avahi_service_type, NULL);
260 
261  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
262  host = g_strdup_printf("[%s]:%i",
263  aui_service_dialog_get_host_name(AUI_SERVICE_DIALOG(dialog)),
264  aui_service_dialog_get_port(AUI_SERVICE_DIALOG(dialog)));
265  } else {
266  host = NULL;
267  }
268  gtk_widget_destroy(dialog);
269 
270  if (host) {
271  gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gfe->priv->server_combo))), host);
272  g_free(host);
273  }
274 }
275 #endif
276 
277 static void remmina_file_editor_on_realize(GtkWidget *widget, gpointer user_data)
278 {
279  TRACE_CALL(__func__);
280  RemminaFileEditor *gfe;
281  GtkWidget *defaultwidget;
282 
283  gfe = REMMINA_FILE_EDITOR(widget);
284 
285  defaultwidget = gfe->priv->server_combo;
286 
287  if (defaultwidget) {
288  if (GTK_IS_EDITABLE(defaultwidget))
289  gtk_editable_select_region(GTK_EDITABLE(defaultwidget), 0, -1);
290  gtk_widget_grab_focus(defaultwidget);
291  }
292 }
293 
294 static void remmina_file_editor_destroy(GtkWidget *widget, gpointer data)
295 {
296  TRACE_CALL(__func__);
297  remmina_file_free(REMMINA_FILE_EDITOR(widget)->priv->remmina_file);
298  g_hash_table_destroy(REMMINA_FILE_EDITOR(widget)->priv->setting_widgets);
299  g_free(REMMINA_FILE_EDITOR(widget)->priv);
300 }
301 
302 static void remmina_file_editor_button_on_toggled(GtkToggleButton *togglebutton, GtkWidget *widget)
303 {
304  TRACE_CALL(__func__);
305  gtk_widget_set_sensitive(widget, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)));
306 }
307 
309 {
310  TRACE_CALL(__func__);
311  /* Create the notebook */
312  gfe->priv->config_container = gtk_notebook_new();
313  gfe->priv->config_viewport = gtk_viewport_new(NULL, NULL);
314  gfe->priv->config_scrollable = gtk_scrolled_window_new(NULL, NULL);
315  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_scrollable), 2);
316  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gfe->priv->config_scrollable),
317  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
318  gtk_widget_show(gfe->priv->config_scrollable);
319 
320  gtk_container_add(GTK_CONTAINER(gfe->priv->config_viewport), gfe->priv->config_container);
321  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_viewport), 2);
322  gtk_widget_show(gfe->priv->config_viewport);
323  gtk_container_add(GTK_CONTAINER(gfe->priv->config_scrollable), gfe->priv->config_viewport);
324  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_container), 2);
325  gtk_widget_show(gfe->priv->config_container);
326 
327  gtk_container_add(GTK_CONTAINER(gfe->priv->config_box), gfe->priv->config_scrollable);
328 }
329 
331  const gchar *stock_id, const gchar *label, gint rows, gint cols)
332 {
333  TRACE_CALL(__func__);
334  GtkWidget *tablabel;
335  GtkWidget *tabbody;
336  GtkWidget *grid;
337  GtkWidget *widget;
338 
339  tablabel = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
340  gtk_widget_show(tablabel);
341 
342  widget = gtk_image_new_from_icon_name(stock_id, GTK_ICON_SIZE_BUTTON);
343  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
344  gtk_widget_show(widget);
345 
346  widget = gtk_label_new(label);
347  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
348  gtk_widget_show(widget);
349 
350  tabbody = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
351  gtk_widget_show(tabbody);
352  gtk_notebook_append_page(GTK_NOTEBOOK(gfe->priv->config_container), tabbody, tablabel);
353 
354  grid = gtk_grid_new();
355  gtk_widget_show(grid);
356  gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
357  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
358  gtk_container_set_border_width(GTK_CONTAINER(grid), 15);
359  gtk_box_pack_start(GTK_BOX(tabbody), grid, FALSE, FALSE, 0);
360 
361  return grid;
362 }
363 
364 
365 static void remmina_file_editor_assistance_enabled_check_on_toggled(GtkToggleButton *togglebutton,
366  RemminaFileEditor *gfe)
367 {
368  TRACE_CALL(__func__);
369  gboolean enabled = TRUE;
370 
371  if (gfe->priv->assistance_toggle) {
372  enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->assistance_toggle));
373  if (gfe->priv->assistance_file)
374  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_file), enabled);
375  if (gfe->priv->assistance_password)
376  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_password), enabled);
377  if (gfe->priv->assistance_file_label)
378  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_file_label), enabled);
379  if (gfe->priv->assistance_password_label)
380  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->assistance_password_label), enabled);
381  }
382 }
383 
384 #ifdef HAVE_LIBSSH
385 
387 {
388  TRACE_CALL(__func__);
389  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_entry),
390  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check)) &&
391  (gfe->priv->ssh_tunnel_server_custom_radio == NULL ||
392  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_server_custom_radio))));
393 }
394 
395 
396 static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton,
398 {
399  TRACE_CALL(__func__);
400  RemminaFileEditorPriv *priv = gfe->priv;
401  gboolean enabled = TRUE;
402  gchar *p;
403  const gchar *cp;
404  const gchar *s = NULL;
405 
406  if (gfe->priv->ssh_tunnel_enabled_check) {
407  enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check));
408  if (gfe->priv->ssh_tunnel_loopback_check)
409  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_loopback_check), enabled);
410  if (gfe->priv->ssh_tunnel_server_default_radio)
411  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_default_radio), enabled);
412  if (gfe->priv->ssh_tunnel_server_custom_radio)
413  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_custom_radio), enabled);
415  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
416  // if (!(g_strcmp0(p, "SFTP") == 0 || g_strcmp0(p, "SSH") == 0)) {
417  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_username_entry), enabled);
418  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_password), enabled);
419  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_combo), enabled);
420  //}
421  g_free(p);
422  }
423  // remmina_file_editor_ssh_tunnel_auth_publickey_radio_on_toggled(NULL, gfe);
424  s = remmina_file_get_string(gfe->priv->remmina_file, "ssh_tunnel_privatekey");
425  if (s)
426  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gfe->priv->ssh_tunnel_privatekey_chooser), s);
427  s = remmina_file_get_string(gfe->priv->remmina_file, "ssh_tunnel_certfile");
428  if (s)
429  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gfe->priv->ssh_tunnel_certfile_chooser), s);
430 
431  if (gfe->priv->ssh_tunnel_username_entry)
432  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry))[0] == '\0') {
433  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_username");
434  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry), cp ? cp : "");
435  }
436 
437  if (gfe->priv->ssh_tunnel_auth_password) {
438  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password))[0] == '\0') {
439  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_password");
440  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password), cp ? cp : "");
441  }
442  }
443  if (gfe->priv->ssh_tunnel_passphrase) {
444  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase))[0] == '\0') {
445  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_passphrase");
446  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase), cp ? cp : "");
447  }
448  }
449 }
450 
451 #endif
452 
453 static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid,
454  gint row)
455 {
456  TRACE_CALL(__func__);
457  RemminaProtocolPlugin *plugin = gfe->priv->plugin;
458  GtkWidget *widget;
459 #ifdef HAVE_LIBAVAHI_UI
460  GtkWidget *hbox;
461 #endif
462  gchar *s;
463 
464  widget = gtk_label_new(_("Server"));
465  gtk_widget_show(widget);
466  gtk_widget_set_valign(widget, GTK_ALIGN_START);
467  gtk_widget_set_halign(widget, GTK_ALIGN_START);
468  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, row + 1);
469 
470  s = remmina_pref_get_recent(plugin->name);
471  widget = remmina_public_create_combo_entry(s, remmina_file_get_string(gfe->priv->remmina_file, "server"), TRUE);
472  gtk_widget_set_hexpand(widget, TRUE);
473  gtk_widget_show(widget);
474  gtk_widget_set_tooltip_markup(widget, _(server_tips));
475  gtk_entry_set_activates_default(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(widget))), TRUE);
476  gfe->priv->server_combo = widget;
477  g_free(s);
478 
479 #ifdef HAVE_LIBAVAHI_UI
480  if (setting->opt1) {
481  gfe->priv->avahi_service_type = (const gchar *)setting->opt1;
482 
483  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
484  gtk_widget_show(hbox);
485  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
486 
487  widget = gtk_button_new_with_label("…");
488  s = g_strdup_printf(_("Browse the network to find a %s server"), plugin->name);
489  gtk_widget_set_tooltip_text(widget, s);
490  g_free(s);
491  gtk_widget_show(widget);
492  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
493  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_avahi), gfe);
494 
495  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
496  } else
497 #endif
498  {
499  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
500  }
501 }
502 
503 
504 static GtkWidget *remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
505 {
506  TRACE_CALL(__func__);
507  GtkWidget *widget;
508 
509  widget = gtk_label_new(label);
510  gtk_widget_show(widget);
511 #if GTK_CHECK_VERSION(3, 12, 0)
512  gtk_widget_set_margin_end(widget, 40);
513 #else
514  gtk_widget_set_margin_right(widget, 40);
515 #endif
516  gtk_widget_set_valign(widget, GTK_ALIGN_START);
517  gtk_widget_set_halign(widget, GTK_ALIGN_START);
518  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
519 
520  widget = gtk_entry_new();
521  gtk_widget_show(widget);
522  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
523  gtk_entry_set_max_length(GTK_ENTRY(widget), 0);
524  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
525  gtk_widget_set_hexpand(widget, TRUE);
526  gtk_entry_set_activates_default(GTK_ENTRY(widget), TRUE);
527  if (setting_name)
528  gtk_widget_set_name(widget, setting_name);
529 
530  if (value)
531  gtk_entry_set_text(GTK_ENTRY(widget), value);
532  /* Password view Toogle*/
533  if (setting_name) {
534  gtk_entry_set_icon_from_icon_name(GTK_ENTRY(widget), GTK_ENTRY_ICON_SECONDARY, "org.remmina.Remmina-password-reveal-symbolic");
535  gtk_entry_set_icon_activatable(GTK_ENTRY(widget), GTK_ENTRY_ICON_SECONDARY, TRUE);
536  g_signal_connect(widget, "icon-press", G_CALLBACK(remmina_main_toggle_password_view), NULL);
537  }
538  return widget;
539 }
540 
541 static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
542 {
543  TRACE_CALL(__func__);
544  gchar *res_str;
545  res_str = g_strdup_printf("%dx%d",
546  remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", 0),
547  remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", 0));
548  remmina_public_load_combo_text_d(gfe->priv->resolution_custom_combo, remmina_pref.resolutions,
549  res_str, NULL);
550  g_free(res_str);
551 }
552 
553 static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
554 {
555  TRACE_CALL(__func__);
556 
557  GtkDialog *dialog = remmina_string_list_new(FALSE, NULL);
560  remmina_string_list_set_titles(_("Resolutions"), _("Configure the available resolutions"));
561  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
562  gtk_dialog_run(dialog);
563  g_free(remmina_pref.resolutions);
565  g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(remmina_file_editor_update_resolution), gfe);
566  gtk_widget_destroy(GTK_WIDGET(dialog));
567 }
568 
570  GtkWidget *grid, gint row)
571 {
572  TRACE_CALL(__func__);
573  GtkWidget *widget;
574  GtkWidget *hbox;
575  int resolution_w, resolution_h;
576  gchar *res_str;
578 
579  res_mode = remmina_file_get_int(gfe->priv->remmina_file, "resolution_mode", RES_INVALID);
580  resolution_w = remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", -1);
581  resolution_h = remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", -1);
582 
583  /* If resolution_mode is non-existent (-1), then we try to calculate it
584  * as we did before having resolution_mode */
585  if (res_mode == RES_INVALID) {
586  if (resolution_w <= 0 || resolution_h <= 0)
587  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
588  else
589  res_mode = RES_USE_CUSTOM;
590  }
591  if (res_mode == RES_USE_CUSTOM)
592  res_str = g_strdup_printf("%dx%d", resolution_w, resolution_h);
593  else
594  res_str = NULL;
595 
596  widget = gtk_label_new(_("Resolution"));
597  gtk_widget_show(widget);
598  gtk_widget_set_valign(widget, GTK_ALIGN_START);
599  gtk_widget_set_halign(widget, GTK_ALIGN_START);
600  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
601 
602  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
603  widget = gtk_radio_button_new_with_label(NULL, _("Use initial window size"));
604  gtk_widget_show(widget);
605  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
606  gfe->priv->resolution_iws_radio = widget;
607  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Use client resolution"));
608  gtk_widget_show(widget);
609  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
610  gfe->priv->resolution_auto_radio = widget;
611  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
612  gtk_widget_show(hbox);
613 
614  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
615  gtk_widget_show(hbox);
616  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row + 1, 1, 1);
617 
618  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Custom"));
619  gtk_widget_show(widget);
620  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
621  gfe->priv->resolution_custom_radio = widget;
622 
624  gtk_widget_show(widget);
625  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
626  gfe->priv->resolution_custom_combo = widget;
627 
628  widget = gtk_button_new_with_label("…");
629  gtk_widget_show(widget);
630  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
631  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_resolution), gfe);
632 
633  g_signal_connect(G_OBJECT(gfe->priv->resolution_custom_radio), "toggled",
634  G_CALLBACK(remmina_file_editor_button_on_toggled), gfe->priv->resolution_custom_combo);
635 
636  if (res_mode == RES_USE_CUSTOM)
637  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio), TRUE);
638  else if (res_mode == RES_USE_CLIENT)
639  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_auto_radio), TRUE);
640  else
641  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_iws_radio), TRUE);
642 
643  gtk_widget_set_sensitive(gfe->priv->resolution_custom_combo, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio)));
644 
645  g_free(res_str);
646 }
647 
648 
650  GtkWidget *grid, gint row)
651 {
652  TRACE_CALL(__func__);
653  GtkWidget *widget;
654 
655 
656 
657  widget = gtk_toggle_button_new_with_label(_("Assistance Mode"));
658  gtk_widget_set_halign(widget, GTK_ALIGN_START);
659  gtk_widget_show(widget);
660  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
661  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), remmina_file_get_int(gfe->priv->remmina_file, "assistance_mode", 0));
662  gfe->priv->assistance_toggle = widget;
663  g_signal_connect(widget, "toggled", G_CALLBACK(remmina_file_editor_assistance_enabled_check_on_toggled), gfe);
664 
665 
666  widget = gtk_label_new("Assistance file");
667  gtk_widget_set_halign(widget, GTK_ALIGN_END);
668  gtk_widget_show(widget);
669  gtk_grid_attach(GTK_GRID(grid), widget, 0, row+1, 1, 1);
670  gfe->priv->assistance_file_label = widget;
671 
672  widget = gtk_entry_new();
673  gtk_widget_set_halign(widget, GTK_ALIGN_START);
674  gtk_widget_show(widget);
675  gtk_entry_set_text(GTK_ENTRY(widget), remmina_file_get_string(gfe->priv->remmina_file, "assistance_file"));
676  gtk_grid_attach(GTK_GRID(grid), widget, 1, row+1, 1, 1);
677  gfe->priv->assistance_file = widget;
678 
679  widget = gtk_label_new("Assistance Password");
680  gtk_widget_set_halign(widget, GTK_ALIGN_END);
681  gtk_widget_show(widget);
682  gtk_grid_attach(GTK_GRID(grid), widget, 0, row+2, 1, 1);
683  gfe->priv->assistance_password_label = widget;
684 
685  widget = gtk_entry_new();
686  gtk_widget_set_halign(widget, GTK_ALIGN_START);
687  gtk_widget_show(widget);
688  gtk_entry_set_text(GTK_ENTRY(widget), remmina_file_get_string(gfe->priv->remmina_file, "assistance_pass"));
689  gtk_grid_attach(GTK_GRID(grid), widget, 1, row+2, 1, 1);
690  gfe->priv->assistance_password = widget;
691 
693 
694 }
695 
696 
697 static GtkWidget *remmina_file_editor_create_text2(RemminaFileEditor *gfe, GtkWidget *grid,
698  gint row, gint col, const gchar *label, const gchar *value, gint left,
699  gint right, gchar *setting_name)
700 {
701  TRACE_CALL(__func__);
702  GtkWidget *widget;
703 
704  widget = gtk_label_new(label);
705  gtk_widget_show(widget);
706 #if GTK_CHECK_VERSION(3, 12, 0)
707  gtk_widget_set_margin_start(widget, left);
708  gtk_widget_set_margin_end(widget, right);
709 #else
710  gtk_widget_set_margin_left(widget, left);
711  gtk_widget_set_margin_right(widget, right);
712 #endif
713  gtk_widget_set_valign(widget, GTK_ALIGN_START);
714  gtk_widget_set_halign(widget, GTK_ALIGN_START);
715  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
716 
717  widget = gtk_entry_new();
718  gtk_widget_show(widget);
719  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
720  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
721  gtk_widget_set_hexpand(widget, TRUE);
722  if (setting_name)
723  gtk_widget_set_name(widget, setting_name);
724 
725  if (value)
726  gtk_entry_set_text(GTK_ENTRY(widget), value);
727 
728  return widget;
729 }
730 
731 static GtkWidget *remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid,
732  gint row, gint col, const gchar *label, const gchar *value,
733  gchar *setting_name)
734 {
735  TRACE_CALL(__func__);
736  return remmina_file_editor_create_text2(gfe, grid, row, col, label, value, 0, 40,
737  setting_name);
738 }
739 
740 static GtkWidget *remmina_file_editor_create_textarea(RemminaFileEditor *gfe, GtkWidget *grid,
741  gint row, gint col, const gchar *label, const gchar *value,
742  gchar *setting_name)
743 {
744  TRACE_CALL(__func__);
745  GtkWidget *widget;
746  GtkTextView *view;
747  GtkTextBuffer *buffer;
748  GtkTextIter start;
749 
750  widget = gtk_text_view_new();
751  view = GTK_TEXT_VIEW(widget);
752  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
753  gtk_text_view_set_top_margin(GTK_TEXT_VIEW(view), 20);
754  gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(view), 20);
755  gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 20);
756  gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 20);
757  gtk_text_view_set_monospace(view, TRUE);
758  if (setting_name)
759  gtk_widget_set_name(widget, setting_name);
760  if (value) {
761  buffer = gtk_text_view_get_buffer(view);
762  gtk_text_buffer_set_text(buffer, value, -1);
763  gtk_text_buffer_get_start_iter(buffer, &start);
764  gtk_text_buffer_place_cursor(buffer, &start);
765  }
766  gtk_widget_show(widget);
767  gtk_widget_set_hexpand(widget, TRUE);
768  gtk_widget_set_size_request(GTK_WIDGET(view), 320, 300);
769  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
770  return widget;
771 }
772 
773 static GtkWidget *remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid,
774  gint row, gint col, const gchar *label, const gpointer *list,
775  const gchar *value, gchar *setting_name)
776 {
777  TRACE_CALL(__func__);
778  GtkWidget *widget;
779 
780  widget = gtk_label_new(label);
781  gtk_widget_show(widget);
782  gtk_widget_set_valign(widget, GTK_ALIGN_START);
783  gtk_widget_set_halign(widget, GTK_ALIGN_START);
784  if (setting_name)
785  gtk_widget_set_name(widget, setting_name);
786  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
787 
788  widget = remmina_public_create_combo_map(list, value, FALSE, gfe->priv->plugin->domain);
789  gtk_widget_show(widget);
790  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
791 
792  return widget;
793 }
794 
795 static GtkWidget *remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid,
796  gint row, gint col, const gchar *label, const gchar *list,
797  const gchar *value, gchar *setting_name)
798 {
799  TRACE_CALL(__func__);
800  GtkWidget *widget;
801 
802  widget = gtk_label_new(label);
803  gtk_widget_show(widget);
804  gtk_widget_set_valign(widget, GTK_ALIGN_START);
805  gtk_widget_set_halign(widget, GTK_ALIGN_START);
806  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
807 
808  widget = remmina_public_create_combo_entry(list, value, FALSE);
809  gtk_widget_show(widget);
810  gtk_widget_set_hexpand(widget, TRUE);
811  if (setting_name)
812  gtk_widget_set_name(widget, setting_name);
813  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
814 
815  return widget;
816 }
817 
818 static GtkWidget *remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid,
819  gint row, gint top, const gchar *label, gboolean value,
820  gchar *setting_name)
821 {
822  TRACE_CALL(__func__);
823  GtkWidget *widget;
824  widget = gtk_check_button_new_with_label(label);
825  gtk_widget_show(widget);
826  if (setting_name)
827  gtk_widget_set_name(widget, setting_name);
828  gtk_grid_attach(GTK_GRID(grid), widget, top, row, 1, 1);
829 
830  if (value)
831  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
832 
833  return widget;
834 }
835 
845 static GtkWidget *
846 remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label,
847  const gchar *value, gint type, gchar *setting_name)
848 {
849  TRACE_CALL(__func__);
850  GtkWidget *check;
851  GtkWidget *widget;
852  GtkWidget *hbox;
853 
854  widget = gtk_label_new(label);
855  gtk_widget_show(widget);
856  gtk_widget_set_valign(widget, GTK_ALIGN_START);
857  gtk_widget_set_halign(widget, GTK_ALIGN_START);
858  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
859 
860  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
861  gtk_widget_show(hbox);
862  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
863 
864  check = gtk_check_button_new();
865  gtk_widget_show(check);
866  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), (value && value[0] == '/'));
867  gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
868 
869  widget = gtk_file_chooser_button_new(label, type);
870  if (setting_name)
871  gtk_widget_set_name(widget, setting_name);
872  gtk_widget_show(widget);
873  if (value)
874  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget), value);
875  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
876 
877  g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(remmina_file_editor_button_on_toggled), widget);
878  remmina_file_editor_button_on_toggled(GTK_TOGGLE_BUTTON(check), widget);
879 
880  return widget;
881 }
882 
883 // used to filter out invalid characters for REMMINA_PROTOCOL_SETTING_TYPE_INT
884 void remmina_file_editor_int_setting_filter(GtkEditable *editable, const gchar *text,
885  gint length, gint *position, gpointer data)
886 {
887  for (int i = 0; i < length; i++) {
888  if (!isdigit(text[i]) && text[i] != '-') {
889  g_signal_stop_emission_by_name(G_OBJECT(editable), "insert-text");
890  return;
891  }
892  }
893 }
894 
895 // used to filter out invalid characters for REMMINA_PROTOCOL_SETTING_TYPE_DOUBLE
896 // '.' and ',' can't be used interchangeably! It depends on the language setting
897 // of the user.
898 void remmina_file_editor_double_setting_filter(GtkEditable *editable, const gchar *text,
899  gint length, gint *position, gpointer data)
900 {
901  for (int i = 0; i < length; i++) {
902  if (!isdigit(text[i]) && text[i] != '-' && text[i] != '.' && text[i] != ',') {
903  g_signal_stop_emission_by_name(G_OBJECT(editable), "insert-text");
904  return;
905  }
906  }
907 }
908 
909 static GtkWidget *remmina_file_editor_create_int(RemminaFileEditor *gfe, GtkWidget *grid,
910  gint row, gint col, const gchar *label, const gint value,
911  gint left, gint right, gchar *setting_name)
912 {
913  TRACE_CALL(__func__);
914  GtkWidget *widget;
915 
916  widget = gtk_label_new(label);
917  gtk_widget_show(widget);
918 #if GTK_CHECK_VERSION(3, 12, 0)
919  gtk_widget_set_margin_start(widget, left);
920  gtk_widget_set_margin_end(widget, right);
921 #else
922  gtk_widget_set_margin_left(widget, left);
923  gtk_widget_set_margin_right(widget, right);
924 #endif
925  gtk_widget_set_valign(widget, GTK_ALIGN_START);
926  gtk_widget_set_halign(widget, GTK_ALIGN_START);
927  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
928 
929  widget = gtk_entry_new();
930  gtk_widget_show(widget);
931  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
932  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
933  gtk_widget_set_hexpand(widget, TRUE);
934  if (setting_name)
935  gtk_widget_set_name(widget, setting_name);
936 
937  // Convert int to str.
938  int length = snprintf(NULL, 0, "%d", value) + 1; // +1 '\0' byte
939  char *str = malloc(length);
940  snprintf(str, length, "%d", value);
941 
942  gtk_entry_set_text(GTK_ENTRY(widget), str);
943  free(str);
944 
945  g_signal_connect(G_OBJECT(widget), "insert-text",
946  G_CALLBACK(remmina_file_editor_int_setting_filter), NULL);
947 
948  return widget;
949 }
950 
952  GtkWidget *grid, gint row, gint col,
953  const gchar *label, gdouble value, gint left,
954  gint right, gchar *setting_name)
955 {
956  TRACE_CALL(__func__);
957  GtkWidget *widget;
958 
959  widget = gtk_label_new(label);
960  gtk_widget_show(widget);
961 #if GTK_CHECK_VERSION(3, 12, 0)
962  gtk_widget_set_margin_start(widget, left);
963  gtk_widget_set_margin_end(widget, right);
964 #else
965  gtk_widget_set_margin_left(widget, left);
966  gtk_widget_set_margin_right(widget, right);
967 #endif
968  gtk_widget_set_valign(widget, GTK_ALIGN_START);
969  gtk_widget_set_halign(widget, GTK_ALIGN_START);
970  gtk_grid_attach(GTK_GRID(grid), widget, col, row, 1, 1);
971 
972  widget = gtk_entry_new();
973  gtk_widget_show(widget);
974  gtk_grid_attach(GTK_GRID(grid), widget, col + 1, row, 1, 1);
975  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
976  gtk_widget_set_hexpand(widget, TRUE);
977  if (setting_name)
978  gtk_widget_set_name(widget, setting_name);
979 
980  // Convert double to str.
981  int length = snprintf(NULL, 0, "%.8g", value) + 1; // +1 '\0' byte
982  char *str = malloc(length);
983  snprintf(str, length, "%f", value);
984 
985  gtk_entry_set_text(GTK_ENTRY(widget), str);
986  free(str);
987 
988  g_signal_connect(G_OBJECT(widget), "insert-text",
990 
991  return widget;
992 }
993 
994 
995 
996 static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid,
997  const RemminaProtocolSetting *settings)
998 {
999  TRACE_CALL(__func__);
1000  RemminaFileEditorPriv *priv = gfe->priv;
1001  GtkWidget *widget;
1002  gint grid_row = 0;
1003  gint grid_column = 0;
1004  gchar **strarr;
1005  gchar *setting_name;
1006  const gchar *escaped;
1007 
1008  while (settings->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
1009  setting_name = (gchar *)(remmina_plugin_manager_get_canonical_setting_name(settings));
1010  switch (settings->type) {
1012  remmina_file_editor_create_server(gfe, settings, grid, grid_row);
1013  break;
1014 
1016  widget = remmina_file_editor_create_password(gfe, grid, grid_row, 0,
1017  g_dgettext(priv->plugin->domain, settings->label),
1018  remmina_file_get_string(priv->remmina_file, setting_name),
1019  setting_name);
1020  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1021  grid_row++;
1022  break;
1023 
1025  remmina_file_editor_create_resolution(gfe, settings, grid, grid_row);
1026  grid_row ++;
1027  break;
1028 
1030  remmina_file_editor_create_assistance(gfe, settings, grid, grid_row);
1031  grid_row += 3;
1032  break;
1033 
1035  strarr = remmina_pref_keymap_groups();
1036  priv->keymap_combo = remmina_file_editor_create_select(gfe, grid,
1037  grid_row + 1, 0,
1038  _("Keyboard mapping"), (const gpointer *)strarr,
1039  remmina_file_get_string(priv->remmina_file, "keymap"),
1040  setting_name);
1041  g_strfreev(strarr);
1042  grid_row++;
1043  break;
1044 
1046  widget = remmina_file_editor_create_text(gfe, grid, grid_row, 0,
1047  g_dgettext(priv->plugin->domain, settings->label),
1048  remmina_file_get_string(priv->remmina_file, setting_name),
1049  setting_name);
1050  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1051  if (settings->opt2)
1052  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1053  grid_row++;
1054  break;
1055 
1057  escaped = remmina_file_get_string(priv->remmina_file, setting_name);
1058  escaped = g_uri_unescape_string(escaped, NULL);
1059  widget = remmina_file_editor_create_textarea(gfe, grid, grid_row, 0,
1060  g_dgettext(priv->plugin->domain, settings->label), escaped,
1061  setting_name);
1062  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1063  grid_row++;
1064  break;
1065 
1067  widget = remmina_file_editor_create_select(gfe, grid, grid_row, 0,
1068  g_dgettext(priv->plugin->domain, settings->label),
1069  (const gpointer *)settings->opt1,
1070  remmina_file_get_string(priv->remmina_file, setting_name),
1071  setting_name);
1072  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1073  if (settings->opt2)
1074  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1075  break;
1076 
1078  widget = remmina_file_editor_create_combo(gfe, grid, grid_row, 0,
1079  g_dgettext(priv->plugin->domain, settings->label),
1080  (const gchar *)settings->opt1,
1081  remmina_file_get_string(priv->remmina_file, setting_name),
1082  setting_name);
1083  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1084  if (settings->opt2)
1085  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1086  break;
1087 
1089  widget = remmina_file_editor_create_check(gfe, grid, grid_row, grid_column,
1090  g_dgettext(priv->plugin->domain, settings->label),
1091  remmina_file_get_int(priv->remmina_file, setting_name, FALSE),
1092  setting_name);
1093  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1094  if (settings->opt2)
1095  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1096  break;
1097 
1099  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
1100  g_dgettext(priv->plugin->domain, settings->label),
1101  remmina_file_get_string(priv->remmina_file, setting_name),
1102  GTK_FILE_CHOOSER_ACTION_OPEN, setting_name);
1103  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1104  if (settings->opt2)
1105  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1106  break;
1107 
1109  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
1110  g_dgettext(priv->plugin->domain, settings->label),
1111  remmina_file_get_string(priv->remmina_file, setting_name),
1112  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1113  setting_name);
1114  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1115  if (settings->opt2)
1116  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1117  break;
1119  widget = remmina_file_editor_create_int(gfe, grid, grid_row, 0,
1120  g_dgettext(priv->plugin->domain, settings->label),
1121  remmina_file_get_int(priv->remmina_file, setting_name, 0),
1122  0, 40, setting_name);
1123  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1124  if (settings->opt2)
1125  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1126  grid_row++;
1127  break;
1129  widget = remmina_file_editor_create_double(gfe, grid, grid_row, 0,
1130  g_dgettext(priv->plugin->domain, settings->label),
1131  remmina_file_get_double(priv->remmina_file, setting_name, 0.0f),
1132  0, 40, setting_name);
1133  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
1134  if (settings->opt2)
1135  gtk_widget_set_tooltip_text(widget, _((const gchar *)settings->opt2));
1136  grid_row++;
1137  break;
1138 
1139  default:
1140  break;
1141  }
1142  /* If the setting wants compactness, move to the next column */
1143  if (settings->compact)
1144  grid_column++;
1145  /* Add a new settings row and move to the first column
1146  * if the setting doesn’t want the compactness
1147  * or we already have two columns */
1148  if (!settings->compact || grid_column > 1) {
1149  grid_row++;
1150  grid_column = 0;
1151  }
1152  settings++;
1153  }
1154 }
1155 
1157 {
1158  TRACE_CALL(__func__);
1159  RemminaFileEditorPriv *priv = gfe->priv;
1160  GtkWidget *grid;
1161  GtkWidget *widget;
1162  const gchar *cs;
1163 
1164  /* The Behavior tab (implementation) */
1165  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Behavior"), 20, 2);
1166 
1167  /* Execute Command frame */
1168  remmina_public_create_group(GTK_GRID(grid), _("Execute a Command"), 0, 1, 2);
1169 
1170  /* PRE connection command */
1171  cs = remmina_file_get_string(priv->remmina_file, "precommand");
1172  widget = remmina_file_editor_create_text2(gfe, grid, 2, 0, _("Before connecting"), cs, 24, 26, "precommand");
1173  priv->behavior_precommand_entry = widget;
1174  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("command %h %u %t %U %p %g --option"));
1175  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1176 
1177  /* POST connection command */
1178  cs = remmina_file_get_string(priv->remmina_file, "postcommand");
1179  widget = remmina_file_editor_create_text2(gfe, grid, 3, 0, _("After connecting"), cs, 24, 16, "postcommand");
1180  priv->behavior_postcommand_entry = widget;
1181  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("/path/to/command -opt1 arg %h %u %t -opt2 %U %p %g"));
1182  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1183 
1184  /* Startup frame */
1185  remmina_public_create_group(GTK_GRID(grid), _("Start-up"), 4, 1, 2);
1186 
1187  /* Autostart profile option */
1188  priv->behavior_autostart_check = remmina_file_editor_create_check(gfe, grid, 6, 1, _("Auto-start this profile"),
1189  remmina_file_get_int(priv->remmina_file, "enable-autostart", FALSE), "enable-autostart");
1190 
1191  /* Startup frame */
1192  remmina_public_create_group(GTK_GRID(grid), _("Connection profile security"), 8, 1, 2);
1193 
1194  /* Autostart profile option */
1195  priv->behavior_lock_check = remmina_file_editor_create_check(gfe, grid, 10, 1, _("Require password to connect or edit the profile"),
1196  remmina_file_get_int(priv->remmina_file, "profile-lock", FALSE), "profile-lock");
1197 
1198  /* Startup frame */
1199  remmina_public_create_group(GTK_GRID(grid), _("Unexpected disconnect"), 12, 1, 2);
1200 
1201  /* Autostart profile option */
1202  priv->behavior_disconnect = remmina_file_editor_create_check(gfe, grid, 16, 1, _("Keep window from closing if not disconnected by Remmina"),
1203  remmina_file_get_int(priv->remmina_file, "disconnect-prompt", FALSE), "disconnect-prompt");
1204 }
1205 
1206 #ifdef HAVE_LIBSSH
1207 static gpointer ssh_tunnel_auth_list[] =
1208 {
1209  "0", N_("Password"),
1210  "1", N_("SSH identity file"),
1211  "2", N_("SSH agent"),
1212  "3", N_("Public key (automatic)"),
1213  "4", N_("Kerberos (GSSAPI)"),
1214  NULL
1215 };
1216 #endif
1217 
1219 {
1220  TRACE_CALL(__func__);
1221 #ifdef HAVE_LIBSSH
1222  RemminaFileEditorPriv *priv = gfe->priv;
1223  GtkWidget *grid;
1224  GtkWidget *widget;
1225  const gchar *cs;
1226  gchar *s;
1227  gchar *p;
1228  gint row = 0;
1229 
1230  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_NONE)
1231  return;
1232 
1233  /* The SSH tab (implementation) */
1234  grid = remmina_file_editor_create_notebook_tab(gfe, NULL,
1235  _("SSH Tunnel"), 9, 3);
1236  widget = gtk_toggle_button_new_with_label(_("Enable SSH tunnel"));
1237  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1238  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1239  g_signal_connect(G_OBJECT(widget), "toggled",
1241  priv->ssh_tunnel_enabled_check = widget;
1242 
1243  widget = gtk_check_button_new_with_label(_("Tunnel via loopback address"));
1244  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1245  priv->ssh_tunnel_loopback_check = widget;
1246 
1247  // 1
1248  row++;
1249  /* SSH Server group */
1250 
1251  switch (ssh_setting) {
1253  s = g_strdup_printf(_("Same server at port %i"), DEFAULT_SSH_PORT);
1254  widget = gtk_radio_button_new_with_label(NULL, s);
1255  g_free(s);
1256  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 3, 1);
1257  priv->ssh_tunnel_server_default_radio = widget;
1258  // 2
1259  row++;
1260 
1261  widget = gtk_radio_button_new_with_label_from_widget(
1262  GTK_RADIO_BUTTON(priv->ssh_tunnel_server_default_radio), _("Custom"));
1263  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1264  g_signal_connect(G_OBJECT(widget), "toggled",
1266  priv->ssh_tunnel_server_custom_radio = widget;
1267 
1268  widget = gtk_entry_new();
1269  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
1270  gtk_widget_set_tooltip_markup(widget, _(server_tips2));
1271  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1272  priv->ssh_tunnel_server_entry = widget;
1273  // 3
1274  row++;
1275  break;
1276 
1278  priv->ssh_tunnel_server_default_radio = NULL;
1279  priv->ssh_tunnel_server_custom_radio = NULL;
1280 
1281  priv->ssh_tunnel_server_entry = remmina_file_editor_create_text(gfe, grid, 1, 0,
1282  _("Server"), NULL, "ssh_reverse_tunnel_server");
1283  gtk_widget_set_tooltip_markup(priv->ssh_tunnel_server_entry, _(server_tips));
1284  // 2
1285  row++;
1286  break;
1289  priv->ssh_tunnel_server_default_radio = NULL;
1290  priv->ssh_tunnel_server_custom_radio = NULL;
1291  priv->ssh_tunnel_server_entry = NULL;
1292 
1293  break;
1294 
1295  default:
1296  break;
1297  }
1298 
1299  /* This is not used? */
1300  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
1301  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_SFTP) {
1302  widget = remmina_file_editor_create_text(gfe, grid, row, 1,
1303  _("Start-up path"), NULL, "start-up-path");
1304  cs = remmina_file_get_string(priv->remmina_file, "execpath");
1305  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
1306  g_hash_table_insert(priv->setting_widgets, "execpath", widget);
1307  // 2
1308  row++;
1309  }
1310 
1311  /* SSH Authentication frame */
1312  remmina_public_create_group(GTK_GRID(grid), _("SSH Authentication"), row, 6, 1);
1313  // 5
1314  row += 2;
1315 
1316  priv->ssh_tunnel_auth_combo = remmina_file_editor_create_select(gfe, grid, row, 0,
1317  _("Authentication type"),
1318  (const gpointer *)ssh_tunnel_auth_list,
1319  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_auth"), "ssh_tunnel_auth");
1320  row++;
1321 
1322  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL ||
1324  priv->ssh_tunnel_username_entry =
1325  remmina_file_editor_create_text(gfe, grid, row, 0,
1326  _("Username"), NULL, "ssh_tunnel_username");
1327  // 5
1328  row++;
1329  }
1330 
1331  widget = remmina_file_editor_create_password(gfe, grid, row, 0,
1332  _("Password"),
1333  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_password"),
1334  "ssh_tunnel_password");
1335  priv->ssh_tunnel_auth_password = widget;
1336  row++;
1337 
1338  priv->ssh_tunnel_privatekey_chooser = remmina_file_editor_create_chooser(gfe, grid, row, 0,
1339  _("SSH private key file"),
1340  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_privatekey"),
1341  GTK_FILE_CHOOSER_ACTION_OPEN, "ssh_tunnel_privatekey");
1342  row++;
1343 
1344  priv->ssh_tunnel_certfile_chooser = remmina_file_editor_create_chooser(gfe, grid, row, 0,
1345  _("SSH certificate file"),
1346  remmina_file_get_string(priv->remmina_file, "ssh_tunnel_certfile"),
1347  GTK_FILE_CHOOSER_ACTION_OPEN, "ssh_tunnel_certfile");
1348  row++;
1349 
1350  widget = gtk_label_new(_("Password to unlock private key"));
1351  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
1352  widget = gtk_entry_new();
1353  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
1354  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
1355  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
1356  gtk_widget_set_hexpand(widget, TRUE);
1357  priv->ssh_tunnel_passphrase = widget;
1358  row++;
1359 
1360  /* Set the values */
1361  cs = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_server");
1362  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL) {
1363  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
1364  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
1365  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
1366  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
1367 
1368  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs ? priv->ssh_tunnel_server_custom_radio : priv->ssh_tunnel_server_default_radio), TRUE);
1369  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
1370  cs ? cs : "");
1371  } else if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_REVERSE_TUNNEL) {
1372  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
1373  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
1374  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
1375  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
1376  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
1377  cs ? cs : "");
1378  }
1379 
1381  gtk_widget_show_all(grid);
1382  g_free(p);
1383 #endif
1384 }
1385 
1387 {
1388  TRACE_CALL(__func__);
1389  RemminaFileEditorPriv *priv = gfe->priv;
1390  GtkWidget *grid;
1391 
1392  static const RemminaProtocolSetting notes_settings[] =
1393  {
1394  { REMMINA_PROTOCOL_SETTING_TYPE_TEXTAREA, "notes_text", NULL, FALSE, NULL, NULL },
1395  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
1396  };
1397 
1399 
1400  /* The Basic tab */
1401  if (priv->plugin->basic_settings) {
1402  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Basic"), 20, 2);
1403  remmina_file_editor_create_settings(gfe, grid, priv->plugin->basic_settings);
1404  }
1405 
1406  /* The Advanced tab */
1407  if (priv->plugin->advanced_settings) {
1408  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Advanced"), 20, 2);
1409  remmina_file_editor_create_settings(gfe, grid, priv->plugin->advanced_settings);
1410  }
1411 
1412  /* The Behavior tab */
1414 
1415  /* The SSH tab */
1416  remmina_file_editor_create_ssh_tunnel_tab(gfe, priv->plugin->ssh_setting);
1417 
1418  /* Notes tab */
1419  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Notes"), 1, 1);
1420  remmina_file_editor_create_settings(gfe, grid, notes_settings);
1421 }
1422 
1424 {
1425  TRACE_CALL(__func__);
1426  RemminaFileEditorPriv *priv = gfe->priv;
1427  gchar *protocol;
1428 
1429  if (priv->config_container) {
1430  gtk_widget_destroy(priv->config_container);
1431  priv->config_container = NULL;
1432  gtk_widget_destroy(priv->config_viewport);
1433  priv->config_viewport = NULL;
1434  gtk_widget_destroy(priv->config_scrollable);
1435  priv->config_scrollable = NULL;
1436  }
1437 
1438  priv->server_combo = NULL;
1439  priv->resolution_iws_radio = NULL;
1440  priv->resolution_auto_radio = NULL;
1441  priv->resolution_custom_radio = NULL;
1442  priv->resolution_custom_combo = NULL;
1443  priv->keymap_combo = NULL;
1444 
1445  priv->ssh_tunnel_enabled_check = NULL;
1446  priv->ssh_tunnel_loopback_check = NULL;
1447  priv->ssh_tunnel_server_default_radio = NULL;
1448  priv->ssh_tunnel_server_custom_radio = NULL;
1449  priv->ssh_tunnel_server_entry = NULL;
1450  priv->ssh_tunnel_username_entry = NULL;
1451  priv->ssh_tunnel_auth_combo = NULL;
1452  priv->ssh_tunnel_auth_password = NULL;
1453  priv->ssh_tunnel_privatekey_chooser = NULL;
1454  priv->ssh_tunnel_certfile_chooser = NULL;
1455 
1456  g_hash_table_remove_all(priv->setting_widgets);
1457 
1458  protocol = remmina_public_combo_get_active_text(combo);
1459  if (protocol) {
1461  protocol);
1462  g_free(protocol);
1464  }
1465 }
1466 
1468 {
1469  TRACE_CALL(__func__);
1470  RemminaFileEditorPriv *priv = gfe->priv;
1471 
1472  remmina_file_set_string(priv->remmina_file, "precommand", gtk_entry_get_text(GTK_ENTRY(priv->behavior_precommand_entry)));
1473  remmina_file_set_string(priv->remmina_file, "postcommand", gtk_entry_get_text(GTK_ENTRY(priv->behavior_postcommand_entry)));
1474 
1475  gboolean autostart_enabled = (priv->behavior_autostart_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_autostart_check)) : FALSE);
1476  remmina_file_set_int(priv->remmina_file, "enable-autostart", autostart_enabled);
1477  gboolean lock_enabled = (priv->behavior_lock_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_lock_check)) : FALSE);
1478  remmina_file_set_int(priv->remmina_file, "profile-lock", lock_enabled);
1479  gboolean disconect_prompt = (priv->behavior_disconnect ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->behavior_disconnect)) : FALSE);
1480  remmina_file_set_int(priv->remmina_file, "disconnect-prompt", disconect_prompt);
1481 }
1482 
1484 {
1485  TRACE_CALL(__func__);
1486  RemminaFileEditorPriv *priv = gfe->priv;
1487  gboolean ssh_tunnel_enabled;
1488  int ssh_tunnel_auth;
1489 
1490  ssh_tunnel_enabled = (priv->ssh_tunnel_enabled_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check)) : FALSE);
1491  remmina_file_set_int(priv->remmina_file,
1492  "ssh_tunnel_loopback",
1493  (priv->ssh_tunnel_loopback_check ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check)) : FALSE));
1494  remmina_file_set_int(priv->remmina_file, "ssh_tunnel_enabled", ssh_tunnel_enabled);
1495  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_auth",
1496  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->ssh_tunnel_auth_combo)));
1497  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_username",
1498  (ssh_tunnel_enabled ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_username_entry)) : NULL));
1500  priv->remmina_file,
1501  "ssh_tunnel_server",
1502  (ssh_tunnel_enabled && priv->ssh_tunnel_server_entry && (priv->ssh_tunnel_server_custom_radio == NULL || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_server_custom_radio))) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_server_entry)) : NULL));
1503 
1504  ssh_tunnel_auth = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->ssh_tunnel_auth_combo));
1505 
1507  priv->remmina_file,
1508  "ssh_tunnel_auth",
1509  ssh_tunnel_auth);
1510 
1511  // If box is unchecked for private key and certfile file choosers,
1512  // set the string to NULL in the remmina file
1513  if (gtk_widget_get_sensitive(priv->ssh_tunnel_privatekey_chooser)) {
1515  priv->remmina_file,
1516  "ssh_tunnel_privatekey",
1517  (priv->ssh_tunnel_privatekey_chooser ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_privatekey_chooser)) : NULL));
1518  }
1519  else {
1520  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_privatekey", NULL);
1521  }
1522 
1523  if (gtk_widget_get_sensitive(priv->ssh_tunnel_certfile_chooser)) {
1525  priv->remmina_file,
1526  "ssh_tunnel_certfile",
1527  (priv->ssh_tunnel_certfile_chooser ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_certfile_chooser)) : NULL));
1528  }
1529  else {
1530  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_certfile", NULL);
1531  }
1532 
1534  priv->remmina_file,
1535  "ssh_tunnel_password",
1536  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PASSWORD)) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_auth_password)) : NULL);
1537 
1539  priv->remmina_file,
1540  "ssh_tunnel_passphrase",
1541  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PUBLICKEY || ssh_tunnel_auth == SSH_AUTH_AUTO_PUBLICKEY)) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_passphrase)) : NULL);
1542 }
1543 
1545  gchar * setting_name_to_validate,
1546  gconstpointer value,
1547  GError ** err)
1548 {
1549  if (!setting_name_to_validate || !value || !gfe) {
1550  if (!setting_name_to_validate) {
1551  g_critical(_("(%s: %i): Can't validate setting '%s' since 'value' or 'gfe' "
1552  "are NULL!"),
1553  __func__, __LINE__, setting_name_to_validate);
1554  } else {
1555  g_critical(_("(%s: %i): Can't validate user input since "
1556  "'setting_name_to_validate', 'value' or 'gfe' are NULL!"),
1557  __func__, __LINE__);
1558  }
1559  g_set_error(err, 1, 1, _("Internal error."));
1560  return FALSE;
1561  }
1562 
1563  if (strcmp(setting_name_to_validate, "notes_text") == 0) {
1564  // Not a plugin setting. Bail out early.
1565  return TRUE;
1566  }
1567 
1568  const RemminaProtocolSetting *setting_iter;
1569  RemminaProtocolPlugin *protocol_plugin;
1570  RemminaFileEditorPriv *priv = gfe->priv;
1571  protocol_plugin = priv->plugin;
1572 
1573  setting_iter = protocol_plugin->basic_settings;
1574  if (setting_iter) {
1575  // gboolean found = FALSE;
1576  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
1577  if (setting_iter->name == NULL) {
1578  g_error("Internal error: a setting name in protocol plugin %s is "
1579  "null. Please fix RemminaProtocolSetting struct content.",
1580  protocol_plugin->name);
1581  } else if ((gchar *)setting_name_to_validate) {
1582  if (strcmp((gchar *)setting_name_to_validate, setting_iter->name) == 0) {
1583  // found = TRUE;
1584 
1585  gpointer validator_data = setting_iter->validator_data;
1586  GCallback validator = setting_iter->validator;
1587 
1588  // Default behaviour is that everything is valid,
1589  // except a validator is given and its returned GError is not NULL.
1590  GError *err_ret = NULL;
1591 
1592  g_debug("Checking setting '%s' for validation.", setting_iter->name);
1593  if (validator != NULL) {
1594  // Looks weird but it calls the setting's validator
1595  // function using setting_name_to_validate, value and
1596  // validator_data as parameters and it returns a GError*.
1597  err_ret = ((GError * (*)(gpointer, gconstpointer, gpointer)) validator)(setting_name_to_validate, value, validator_data);
1598  }
1599 
1600  if (err_ret) {
1601  g_debug("it has a validator function and it had an error!");
1602  // pass err (returned value) to function caller.
1603  *err = err_ret;
1604  return FALSE;
1605  }
1606 
1607  break;
1608  }
1609  }
1610  setting_iter++;
1611  }
1612 
1613  // if (!found) {
1614  // TOO VERBOSE:
1615  // g_warning("%s is not a plugin setting!", setting_name_to_validate);
1616  // }
1617  }
1618 
1619  return TRUE;
1620 }
1621 
1623  GtkWidget ** failed_widget)
1624 {
1625  TRACE_CALL(__func__);
1626  RemminaFileEditorPriv *priv = gfe->priv;
1627  GHashTableIter iter;
1628  gpointer key;
1629  gpointer widget;
1630  GtkTextBuffer *buffer;
1631  gchar *escaped, *unescaped;
1632  GtkTextIter start, end;
1633 
1634  GError *err = NULL;
1635  *failed_widget = NULL;
1636 
1637  g_hash_table_iter_init(&iter, priv->setting_widgets);
1638  while (g_hash_table_iter_next(&iter, &key, &widget)) {
1639 
1640  // We don't want to save or validate grayed-out settings.
1641  // If widget is a file chooser, it was made not sensitive because
1642  // the box was unchecked. In that case, don't continue. The
1643  // relevant file strings will be set to NULL in the remmina file.
1644  if (!gtk_widget_get_sensitive(GTK_WIDGET(widget)) && !GTK_IS_FILE_CHOOSER(widget)) {
1645  g_debug("Grayed-out setting-widget '%s' will not be saved.",
1646  gtk_widget_get_name(widget));
1647  continue;
1648  }
1649 
1650  if (GTK_IS_ENTRY(widget)) {
1651  const gchar *value = gtk_entry_get_text(GTK_ENTRY(widget));
1652 
1653  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1654  // Error while validating!
1655  // err should be set now.
1656  *failed_widget = widget;
1657  break;
1658  }
1659 
1660  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1661  } else if (GTK_IS_TEXT_VIEW(widget)) {
1662  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
1663  gtk_text_buffer_get_start_iter(buffer, &start);
1664  gtk_text_buffer_get_end_iter(buffer, &end);
1665  unescaped = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1666  escaped = g_uri_escape_string(unescaped, NULL, TRUE);
1667 
1668  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, escaped, &err)) {
1669  // Error while validating!
1670  // err should be set now.
1671  *failed_widget = widget;
1672  break;
1673  }
1674 
1675  remmina_file_set_string(priv->remmina_file, (gchar *)key, escaped);
1676  g_free(escaped);
1677  } else if (GTK_IS_COMBO_BOX(widget)) {
1678  gchar *value = remmina_public_combo_get_active_text(GTK_COMBO_BOX(widget));
1679 
1680  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1681  // Error while validating!
1682  // err should be set now.
1683  *failed_widget = widget;
1684  break;
1685  }
1686 
1687  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1688  } else if (GTK_IS_FILE_CHOOSER(widget)) {
1689  gchar *value = gtk_widget_get_sensitive(GTK_WIDGET(widget)) ? gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)) : NULL;
1690 
1691  if (!gtk_widget_get_sensitive(GTK_WIDGET(widget))) {
1692  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1693  continue;
1694  }
1695 
1696  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, value, &err)) {
1697  // Error while validating!
1698  // err should be set now.
1699  g_free(value);
1700  *failed_widget = widget;
1701  break;
1702  }
1703 
1704  remmina_file_set_string(priv->remmina_file, (gchar *)key, value);
1705  g_free(value);
1706  } else if (GTK_IS_TOGGLE_BUTTON(widget)) {
1707  gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
1708 
1709  if (!remmina_file_editor_validate_settings(gfe, (gchar *)key, &value, &err)) {
1710  // Error while validating!
1711  // err should be set now.
1712  *failed_widget = widget;
1713  break;
1714  }
1715 
1716  remmina_file_set_int(priv->remmina_file, (gchar *)key, value);
1717  }
1718  }
1719 
1720  if (err) {
1721  return err;
1722  }
1723 
1724  return NULL;
1725 }
1726 
1728  GtkWidget ** failed_widget)
1729 {
1730  TRACE_CALL(__func__);
1731  int res_w, res_h;
1732  gchar *custom_resolution;
1734 
1735  RemminaFileEditorPriv *priv = gfe->priv;
1736 
1737  remmina_file_set_string(priv->remmina_file, "name", gtk_entry_get_text(GTK_ENTRY(priv->name_entry)));
1738 
1739  remmina_file_set_string(priv->remmina_file, "labels", gtk_entry_get_text(GTK_ENTRY(priv->labels_entry)));
1740 
1741  remmina_file_set_string(priv->remmina_file, "group",
1742  (priv->group_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->group_combo)) : NULL));
1743 
1744  remmina_file_set_string(priv->remmina_file, "protocol",
1745  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo)));
1746 
1747  remmina_file_set_string(priv->remmina_file, "server",
1748  (priv->server_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->server_combo)) : NULL));
1749 
1750  if (priv->resolution_auto_radio) {
1751  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_auto_radio))) {
1752  /* Resolution is set to auto (which means: Use client fullscreen resolution, aka use client resolution) */
1753  res_w = res_h = 0;
1754  res_mode = RES_USE_CLIENT;
1755  } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_iws_radio))) {
1756  /* Resolution is set to initial window size */
1757  res_w = res_h = 0;
1758  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1759  } else {
1760  /* Resolution is set to a value from the list */
1761  custom_resolution = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->resolution_custom_combo));
1762  if (remmina_public_split_resolution_string(custom_resolution, &res_w, &res_h))
1763  res_mode = RES_USE_CUSTOM;
1764  else
1765  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1766  g_free(custom_resolution);
1767  }
1768  remmina_file_set_int(priv->remmina_file, "resolution_mode", res_mode);
1769  remmina_file_set_int(priv->remmina_file, "resolution_width", res_w);
1770  remmina_file_set_int(priv->remmina_file, "resolution_height", res_h);
1771  }
1772 
1773  if (priv->assistance_toggle){
1774  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->assistance_toggle))) {
1775  remmina_file_set_string(priv->remmina_file, "assistance_file", gtk_entry_get_text(GTK_ENTRY(priv->assistance_file)));
1776  remmina_file_set_string(priv->remmina_file, "assistance_pass", gtk_entry_get_text(GTK_ENTRY(priv->assistance_password)));
1777  remmina_file_set_int(priv->remmina_file, "assistance_mode", 1);
1778  }else{
1779  remmina_file_set_int(priv->remmina_file, "assistance_mode", 0);
1780  }
1781 
1782  }
1783 
1784  if (priv->keymap_combo)
1785  remmina_file_set_string(priv->remmina_file, "keymap",
1786  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->keymap_combo)));
1787 
1790  return remmina_file_editor_update_settings(gfe, failed_widget);
1791 }
1792 
1793 static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
1794 {
1795  TRACE_CALL(__func__);
1796  RemminaFile *gf;
1797  GtkWidget *dialog;
1798 
1799  GtkWidget *failed_widget = NULL;
1800  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1801  if (err) {
1802  g_warning(_("Couldn't validate user input. %s"), err->message);
1803  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1804  return;
1805  }
1806 
1807  gf = remmina_file_dup(gfe->priv->remmina_file);
1808 
1810 
1811  /* Clear properties that should never be default */
1812  remmina_file_set_string(gf, "name", NULL);
1813  remmina_file_set_string(gf, "server", NULL);
1814  remmina_file_set_string(gf, "password", NULL);
1815  remmina_file_set_string(gf, "precommand", NULL);
1816  remmina_file_set_string(gf, "postcommand", NULL);
1817 
1818  remmina_file_set_string(gf, "ssh_tunnel_server", NULL);
1819  remmina_file_set_string(gf, "ssh_tunnel_password", NULL);
1820  remmina_file_set_string(gf, "ssh_tunnel_passphrase", NULL);
1821 
1822  remmina_file_save(gf);
1823  remmina_file_free(gf);
1824 
1825  dialog = gtk_message_dialog_new(GTK_WINDOW(gfe), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
1826  GTK_BUTTONS_OK, _("Default settings saved."));
1827  gtk_dialog_run(GTK_DIALOG(dialog));
1828  gtk_widget_destroy(dialog);
1829 }
1830 
1831 static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
1832 {
1833  TRACE_CALL(__func__);
1834 
1835  GtkWidget *failed_widget = NULL;
1836  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1837  if (err) {
1838  g_warning(_("Couldn't validate user input. %s"), err->message);
1839  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1840  return;
1841  }
1842 
1844 
1845  remmina_file_save(gfe->priv->remmina_file);
1847 
1848  gtk_widget_destroy(GTK_WIDGET(gfe));
1849 }
1850 
1851 static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
1852 {
1853  TRACE_CALL(__func__);
1854  RemminaFile *gf;
1855 
1856  GtkWidget *failed_widget = NULL;
1857  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1858  if (err) {
1859  g_warning(_("Couldn't validate user input. %s"), err->message);
1860  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1861  return;
1862  }
1863 
1864  gf = remmina_file_dup(gfe->priv->remmina_file);
1865  /* Put server into name for "Quick Connect" */
1866  if (remmina_file_get_filename(gf) == NULL)
1867  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1868  gtk_widget_destroy(GTK_WIDGET(gfe));
1869  gf->prevent_saving = TRUE;
1870  rcw_open_from_file(gf);
1871 }
1872 
1873 static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
1874 {
1875  TRACE_CALL(__func__);
1877  RemminaFile *gf;
1878 
1879  GtkWidget *failed_widget = NULL;
1880  GError *err = remmina_file_editor_update(gfe, &failed_widget);
1881  if (err) {
1882  g_warning(_("Couldn't validate user input. %s"), err->message);
1883  remmina_file_editor_show_validation_error_popup(gfe, failed_widget, err);
1884  return;
1885  }
1886 
1888 
1889  remmina_file_save(gfe->priv->remmina_file);
1891 
1892  gf = remmina_file_dup(gfe->priv->remmina_file);
1893  /* Put server into name for Quick Connect */
1894  if (remmina_file_get_filename(gf) == NULL)
1895  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1896  gtk_widget_destroy(GTK_WIDGET(gfe));
1897  rcw_open_from_file(gf);
1898 }
1899 
1900 static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
1901 {
1902  TRACE_CALL(__func__);
1903  gtk_widget_destroy(GTK_WIDGET(gfe));
1904 }
1905 
1907 {
1908  TRACE_CALL(__func__);
1909  RemminaFileEditorPriv *priv;
1910  GtkWidget *widget;
1911 
1912  priv = g_new0(RemminaFileEditorPriv, 1);
1913  gfe->priv = priv;
1914 
1915  /* Create the editor dialog */
1916  gtk_window_set_title(GTK_WINDOW(gfe), _("Remote Connection Profile"));
1917 
1918  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Cancel")), GTK_RESPONSE_CANCEL);
1919  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_cancel), gfe);
1920 
1921  /* Default button */
1922  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Save as Default")), GTK_RESPONSE_OK);
1923  gtk_widget_set_tooltip_text(GTK_WIDGET(widget), _("Use the current settings as the default for all new connection profiles"));
1924  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_default), gfe);
1925 
1926  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save")), GTK_RESPONSE_APPLY);
1927  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save), gfe);
1928  gtk_widget_set_sensitive(widget, FALSE);
1929  priv->save_button = widget;
1930 
1931  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Connect")), GTK_RESPONSE_ACCEPT);
1932  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_connect), gfe);
1933 
1934  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save and Connect")), GTK_RESPONSE_OK);
1935  gtk_widget_set_can_default(widget, TRUE);
1936  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save_connect), gfe);
1937 
1938  gtk_dialog_set_default_response(GTK_DIALOG(gfe), GTK_RESPONSE_OK);
1939  gtk_window_set_default_size(GTK_WINDOW(gfe), 800, 600);
1940 
1941  g_signal_connect(G_OBJECT(gfe), "destroy", G_CALLBACK(remmina_file_editor_destroy), NULL);
1942  g_signal_connect(G_OBJECT(gfe), "realize", G_CALLBACK(remmina_file_editor_on_realize), NULL);
1943 
1944  priv->setting_widgets = g_hash_table_new(g_str_hash, g_str_equal);
1945 
1946  remmina_widget_pool_register(GTK_WIDGET(gfe));
1947 }
1948 
1949 static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
1950 {
1951  TRACE_CALL(__func__);
1952  RemminaFileEditor *gfe = REMMINA_FILE_EDITOR(data);
1953  GtkListStore *store;
1954  GtkTreeIter iter;
1955  gboolean first;
1956 
1957  store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gfe->priv->protocol_combo)));
1958 
1959  first = !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1960 
1961  gtk_list_store_append(store, &iter);
1962  gtk_list_store_set(store, &iter, 0, protocol, 1, g_dgettext(plugin->domain, plugin->description), 2,
1963  ((RemminaProtocolPlugin *)plugin)->icon_name, -1);
1964 
1965  if (first || g_strcmp0(protocol, remmina_file_get_string(gfe->priv->remmina_file, "protocol")) == 0)
1966  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(gfe->priv->protocol_combo), &iter);
1967 
1968  return FALSE;
1969 }
1970 
1972 {
1973  TRACE_CALL(__func__);
1974  RemminaFileEditorPriv *priv;
1975 
1976  priv = gfe->priv;
1977  gtk_widget_set_sensitive(priv->group_combo, TRUE);
1978  gtk_widget_set_sensitive(priv->save_button, TRUE);
1979 }
1980 
1981 static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
1982 {
1983  TRACE_CALL(__func__);
1984  RemminaFileEditorPriv *priv;
1985 
1986  priv = gfe->priv;
1987  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
1988  remmina_file_generate_filename(priv->remmina_file);
1989  /* TODO: Probably to be removed */
1991  } else {
1992  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
1993  remmina_file_generate_filename(priv->remmina_file);
1995  }
1996 }
1997 
1999 {
2000  TRACE_CALL(__func__);
2001  RemminaFileEditorPriv *priv;
2002 
2003  priv = gfe->priv;
2004  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
2005  remmina_file_generate_filename(priv->remmina_file);
2006  } else {
2007  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
2008  remmina_file_generate_filename(priv->remmina_file);
2009  }
2010 }
2011 
2013 {
2014  TRACE_CALL(__func__);
2015  RemminaFileEditor *gfe;
2016  RemminaFileEditorPriv *priv;
2017  GtkWidget *grid;
2018  GtkWidget *widget;
2019  gchar *groups;
2020  gchar *s;
2021  const gchar *cs;
2022 
2023  gfe = REMMINA_FILE_EDITOR(g_object_new(REMMINA_TYPE_FILE_EDITOR, NULL));
2024  priv = gfe->priv;
2025  priv->remmina_file = remminafile;
2026 
2027  if (remmina_file_get_filename(remminafile) == NULL)
2028  gtk_dialog_set_response_sensitive(GTK_DIALOG(gfe), GTK_RESPONSE_APPLY, FALSE);
2029 
2030  /* Create the "Profile" group on the top (for name and protocol) */
2031  grid = gtk_grid_new();
2032  gtk_widget_show(grid);
2033  gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
2034  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
2035  gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
2036  gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
2037  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), grid, FALSE, FALSE, 2);
2038 
2039  // remmina_public_create_group(GTK_GRID(grid), _("Profile"), 0, 4, 3);
2040 
2041  gboolean profile_file_exists = (remmina_file_get_filename(remminafile) != NULL);
2042 
2043  /* Profile: Name */
2044  widget = gtk_label_new(_("Name"));
2045  gtk_widget_show(widget);
2046  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2047  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2048  gtk_grid_attach(GTK_GRID(grid), widget, 0, 3, 2, 1);
2049  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
2050 
2051  widget = gtk_entry_new();
2052  gtk_widget_show(widget);
2053  gtk_grid_attach(GTK_GRID(grid), widget, 1, 3, 3, 1);
2054  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
2055  priv->name_entry = widget;
2056 
2057  if (!profile_file_exists) {
2058  gtk_entry_set_text(GTK_ENTRY(widget), _("Quick Connect"));
2059 #if GTK_CHECK_VERSION(3, 16, 0)
2060  gtk_entry_grab_focus_without_selecting(GTK_ENTRY(widget));
2061 #endif
2062  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_entry_on_changed), gfe);
2063  } else {
2064  cs = remmina_file_get_string(remminafile, "name");
2065  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
2066  }
2067 
2068  /* Profile: Group */
2069  widget = gtk_label_new(_("Group"));
2070  gtk_widget_show(widget);
2071  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2072  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2073  gtk_grid_attach(GTK_GRID(grid), widget, 0, 6, 2, 1);
2074 
2076  priv->group_combo = remmina_public_create_combo_entry(groups, remmina_file_get_string(remminafile, "group"), FALSE);
2077  g_free(groups);
2078  gtk_widget_show(priv->group_combo);
2079  gtk_grid_attach(GTK_GRID(grid), priv->group_combo, 1, 6, 3, 1);
2080  gtk_widget_set_sensitive(priv->group_combo, FALSE);
2081 
2082  s = g_strdup_printf(_("Use '%s' as subgroup delimiter"), "/");
2083  gtk_widget_set_tooltip_text(priv->group_combo, s);
2084  g_free(s);
2085 
2086  /* Profile: Labels */
2087  widget = gtk_label_new(_("Labels"));
2088  gtk_widget_show(widget);
2089  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2090  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2091  gtk_grid_attach(GTK_GRID(grid), widget, 0, 9, 2, 1);
2092  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
2093 
2094  widget = gtk_entry_new();
2095  gtk_widget_show(widget);
2096  gtk_grid_attach(GTK_GRID(grid), widget, 1, 9, 3, 1);
2097  gtk_entry_set_max_length(GTK_ENTRY(widget), 255);
2098  priv->labels_entry = widget;
2099 
2100  if (!profile_file_exists) {
2101  gtk_widget_set_tooltip_text(widget, _("Label1,Label2"));
2102 #if GTK_CHECK_VERSION(3, 16, 0)
2103  gtk_entry_grab_focus_without_selecting(GTK_ENTRY(widget));
2104 #endif
2105  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_entry_on_changed), gfe);
2106  } else {
2107  cs = remmina_file_get_string(remminafile, "labels");
2108  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
2109  }
2110 
2111  /* Profile: Protocol */
2112  widget = gtk_label_new(_("Protocol"));
2113  gtk_widget_show(widget);
2114  gtk_widget_set_valign(widget, GTK_ALIGN_START);
2115  gtk_widget_set_halign(widget, GTK_ALIGN_START);
2116  gtk_grid_attach(GTK_GRID(grid), widget, 0, 12, 2, 1);
2117 
2118  widget = remmina_public_create_combo(TRUE);
2119  gtk_widget_show(widget);
2120  gtk_grid_attach(GTK_GRID(grid), widget, 1, 12, 3, 1);
2121  priv->protocol_combo = widget;
2123  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_protocol_combo_on_changed), gfe);
2124 
2125  /* Create the "Preference" frame */
2126  widget = gtk_event_box_new();
2127  gtk_widget_show(widget);
2128  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), widget, TRUE, TRUE, 2);
2129  priv->config_box = widget;
2130 
2131  priv->config_container = NULL;
2132  priv->config_scrollable = NULL;
2133 
2134  remmina_file_editor_protocol_combo_on_changed(GTK_COMBO_BOX(priv->protocol_combo), gfe);
2135 
2137 
2138  return GTK_WIDGET(gfe);
2139 }
2140 
2141 GtkWidget *remmina_file_editor_new(void)
2142 {
2143  TRACE_CALL(__func__);
2144  return remmina_file_editor_new_full(NULL, NULL);
2145 }
2146 
2147 GtkWidget *remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
2148 {
2149  TRACE_CALL(__func__);
2150  RemminaFile *remminafile;
2151 
2152  remminafile = remmina_file_new();
2153  if (server)
2154  remmina_file_set_string(remminafile, "server", server);
2155  if (protocol)
2156  remmina_file_set_string(remminafile, "protocol", protocol);
2157 
2158  return remmina_file_editor_new_from_file(remminafile);
2159 }
2160 
2161 GtkWidget *remmina_file_editor_new_copy(const gchar *filename)
2162 {
2163  TRACE_CALL(__func__);
2164  RemminaFile *remminafile;
2165  GtkWidget *dialog;
2166 
2167  remminafile = remmina_file_copy(filename);
2168 
2169  if (remminafile) {
2170  return remmina_file_editor_new_from_file(remminafile);
2171  } else {
2172  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
2173  _("Could not find the file “%s”."), filename);
2174  gtk_dialog_run(GTK_DIALOG(dialog));
2175  gtk_widget_destroy(dialog);
2176  return NULL;
2177  }
2178 }
2179 
2180 GtkWidget *remmina_file_editor_new_from_filename(const gchar *filename)
2181 {
2182  TRACE_CALL(__func__);
2183  RemminaFile *remminafile;
2184 
2185  remminafile = remmina_file_manager_load_file(filename);
2186  if (remminafile) {
2187  if (remmina_file_get_int(remminafile, "profile-lock", FALSE) && remmina_unlock_new(remmina_main_get_window()) == 0)
2188  return NULL;
2189  return remmina_file_editor_new_from_file(remminafile);
2190  } else {
2191  GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
2192  _("Could not find the file “%s”."), filename);
2193  gtk_dialog_run(GTK_DIALOG(dialog));
2194  gtk_widget_destroy(dialog);
2195  return NULL;
2196  }
2197 }
void remmina_public_create_group(GtkGrid *grid, const gchar *group, gint row, gint rows, gint cols)
const gchar * remmina_plugin_manager_get_canonical_setting_name(const RemminaProtocolSetting *setting)
GtkDialog * remmina_string_list_new(gboolean two_columns, const gchar *fields_separator)
@@ -95,15 +95,15 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:516
gchar ** remmina_pref_keymap_groups(void)
-
static void remmina_file_editor_create_resolution(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
+
static void remmina_file_editor_create_resolution(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
-
static GtkWidget * remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *list, const gchar *value, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *list, const gchar *value, gchar *setting_name)
RemminaFile * remmina_file_dup(RemminaFile *remminafile)
Definition: remmina_file.c:865
GtkWidget * remmina_public_create_combo_entry(const gchar *text, const gchar *def, gboolean descending)
-
static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
+
static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
gchar * remmina_pref_file
Definition: rcw.c:78
GtkWindow * remmina_main_get_window()
@@ -112,13 +112,13 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
-
static GtkWidget * remmina_file_editor_create_int(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gint value, gint left, gint right, gchar *setting_name)
-
static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
+
static GtkWidget * remmina_file_editor_create_int(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gint value, gint left, gint right, gchar *setting_name)
+
static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
const gchar * remmina_file_get_filename(RemminaFile *remminafile)
Definition: remmina_file.c:210
-
static GtkWidget * remmina_file_editor_create_double(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, gdouble value, gint left, gint right, gchar *setting_name)
-
static GtkWidget * remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gpointer *list, const gchar *value, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_double(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, gdouble value, gint left, gint right, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gpointer *list, const gchar *value, gchar *setting_name)
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
-
static void remmina_file_editor_protocol_combo_on_changed(GtkComboBox *combo, RemminaFileEditor *gfe)
+
static void remmina_file_editor_protocol_combo_on_changed(GtkComboBox *combo, RemminaFileEditor *gfe)
void remmina_plugin_manager_for_each_plugin(RemminaPluginType type, RemminaPluginFunc func, gpointer data)
void remmina_widget_pool_register(GtkWidget *widget)
@@ -132,12 +132,12 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
const gchar * domain
Definition: plugin.h:60
gchar * remmina_pref_get_recent(const gchar *protocol)
Definition: remmina_pref.c:980
-
static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
+
static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
void remmina_icon_populate_menu(void)
Definition: remmina_icon.c:256
-
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
+
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
gdouble remmina_file_get_double(RemminaFile *remminafile, const gchar *setting, gdouble default_value)
Definition: remmina_file.c:629
-
static void remmina_file_editor_init(RemminaFileEditor *gfe)
+
static void remmina_file_editor_init(RemminaFileEditor *gfe)
gchar * resolutions
Definition: remmina_pref.h:145
void remmina_file_generate_filename(RemminaFile *remminafile)
Generate a new Remmina connection profile file name.
Definition: remmina_file.c:114
@@ -149,17 +149,17 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
RemminaProtocolWidgetResolutionMode
Definition: types.h:148
static void remmina_file_editor_show_validation_error_popup(RemminaFileEditor *gfe, GtkWidget *failed_widget, GError *err)
Shows a tooltip-like window which tells the user what they did wrong to trigger the validation functi...
GtkWidget * remmina_public_create_combo_map(const gpointer *key_value_list, const gchar *def, gboolean use_icon, const gchar *domain)
-
static GtkWidget * remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gint type, gchar *setting_name)
Create checkbox + gtk_file_chooser for open files and select folders.
+
static GtkWidget * remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gint type, gchar *setting_name)
Create checkbox + gtk_file_chooser for open files and select folders.
-
static GtkWidget * remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
void remmina_file_set_filename(RemminaFile *remminafile, const gchar *filename)
Definition: remmina_file.c:182
-
static gpointer ssh_tunnel_auth_list[]
+
static gpointer ssh_tunnel_auth_list[]
-
static GError * remmina_file_editor_update_settings(RemminaFileEditor *gfe, GtkWidget **failed_widget)
+
static GError * remmina_file_editor_update_settings(RemminaFileEditor *gfe, GtkWidget **failed_widget)
-
void remmina_file_editor_check_profile(RemminaFileEditor *gfe)
+
void remmina_file_editor_check_profile(RemminaFileEditor *gfe)
GtkWidget * remmina_public_create_combo_text_d(const gchar *text, const gchar *def, const gchar *empty_choice)
struct _RemminaFileEditorPriv RemminaFileEditorPriv
static GtkWidget * remmina_file_editor_create_notebook_tab(RemminaFileEditor *gfe, const gchar *stock_id, const gchar *label, gint rows, gint cols)
@@ -170,24 +170,24 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
void remmina_file_set_int(RemminaFile *remminafile, const gchar *setting, gint value)
Definition: remmina_file.c:585
void remmina_file_delete(const gchar *filename)
Definition: remmina_file.c:911
-
static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
-
static GtkWidget * remmina_file_editor_create_text2(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gint left, gint right, gchar *setting_name)
+
static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
+
static GtkWidget * remmina_file_editor_create_text2(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gint left, gint right, gchar *setting_name)
const RemminaProtocolSetting * basic_settings
Definition: plugin.h:74
-
static GtkWidget * remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint top, const gchar *label, gboolean value, gchar *setting_name)
-
static void remmina_file_editor_create_all_settings(RemminaFileEditor *gfe)
+
static GtkWidget * remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint top, const gchar *label, gboolean value, gchar *setting_name)
+
static void remmina_file_editor_create_all_settings(RemminaFileEditor *gfe)
static void remmina_file_editor_create_notebook_container(RemminaFileEditor *gfe)
-
GtkWidget * remmina_file_editor_new_from_file(RemminaFile *remminafile)
+
GtkWidget * remmina_file_editor_new_from_file(RemminaFile *remminafile)
gpointer validator_data
Definition: types.h:124
-
void remmina_file_editor_int_setting_filter(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data)
+
void remmina_file_editor_int_setting_filter(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data)
void remmina_string_list_set_text(const gchar *text, const gboolean clear_data)
-
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
-
static void remmina_file_editor_create_ssh_tunnel_tab(RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
+
static void remmina_file_editor_create_ssh_tunnel_tab(RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
RemminaProtocolSettingType type
Definition: types.h:118
@@ -196,58 +196,58 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
RemminaFile * remmina_file_new(void)
Definition: remmina_file.c:93
void remmina_string_list_set_titles(gchar *title1, gchar *title2)
GCallback validator
Definition: types.h:125
-
static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid, const RemminaProtocolSetting *settings)
-
static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
+
static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid, const RemminaProtocolSetting *settings)
+
static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
void rcw_open_from_file(RemminaFile *remminafile)
Definition: rcw.c:4470
RemminaPref remmina_pref
Definition: rcw.c:79
-
void remmina_file_editor_file_save(RemminaFileEditor *gfe)
+
void remmina_file_editor_file_save(RemminaFileEditor *gfe)
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: remmina_file.c:603
-
GtkWidget * remmina_file_editor_new(void)
+
GtkWidget * remmina_file_editor_new(void)
static void remmina_file_editor_on_realize(GtkWidget *widget, gpointer user_data)
static void remmina_file_editor_button_on_toggled(GtkToggleButton *togglebutton, GtkWidget *widget)
-
static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
+
static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
-
static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
-
static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
-
static void remmina_file_editor_assistance_enabled_check_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
+
static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
+
static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
+
static void remmina_file_editor_assistance_enabled_check_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
const gchar * name
Definition: plugin.h:67
void remmina_main_toggle_password_view(GtkWidget *widget, gpointer data)
-
void remmina_file_editor_double_setting_filter(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data)
+
void remmina_file_editor_double_setting_filter(GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data)
gchar * remmina_file_manager_get_groups(void)
-
static GtkWidget * remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: remmina_file.c:469
-
static void remmina_file_editor_save_behavior_tab(RemminaFileEditor *gfe)
-
static void remmina_file_editor_create_behavior_tab(RemminaFileEditor *gfe)
+
static void remmina_file_editor_save_behavior_tab(RemminaFileEditor *gfe)
+
static void remmina_file_editor_create_behavior_tab(RemminaFileEditor *gfe)
void remmina_file_save(RemminaFile *remminafile)
Definition: remmina_file.c:730
-
static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
-
static gboolean remmina_file_editor_validate_settings(RemminaFileEditor *gfe, gchar *setting_name_to_validate, gconstpointer value, GError **err)
-
static void remmina_file_editor_ssh_tunnel_server_custom_radio_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
+
static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
+
static gboolean remmina_file_editor_validate_settings(RemminaFileEditor *gfe, gchar *setting_name_to_validate, gconstpointer value, GError **err)
+
static void remmina_file_editor_ssh_tunnel_server_custom_radio_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
RemminaFile * remmina_file_copy(const gchar *filename)
Definition: remmina_file.c:217
-
static void remmina_file_editor_create_assistance(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
+
static void remmina_file_editor_create_assistance(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
RemminaFile * remmina_file_manager_load_file(const gchar *filename)
-
static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
-
static GError * remmina_file_editor_update(RemminaFileEditor *gfe, GtkWidget **failed_widget)
+
static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
+
static GError * remmina_file_editor_update(RemminaFileEditor *gfe, GtkWidget **failed_widget)
-
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
RemminaFileEditorPriv * priv
-
static GtkWidget * remmina_file_editor_create_textarea(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
+
static GtkWidget * remmina_file_editor_create_textarea(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gchar *setting_name)
static void remmina_file_editor_browse_avahi(GtkWidget *button, RemminaFileEditor *gfe)
gint remmina_unlock_new(GtkWindow *parent)
void remmina_public_load_combo_text_d(GtkWidget *combo, const gchar *text, const gchar *def, const gchar *empty_choice)
-
static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
+
static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
static void remmina_file_editor_class_init(RemminaFileEditorClass *klass)
const gchar * label
Definition: types.h:120
-
static void remmina_file_editor_save_ssh_tunnel_tab(RemminaFileEditor *gfe)
+
static void remmina_file_editor_save_ssh_tunnel_tab(RemminaFileEditor *gfe)
gchar * remmina_string_list_get_text(void)
const gchar * name
Definition: types.h:119
diff --git a/public/remmina__file__editor_8h.html b/public/remmina__file__editor_8h.html index ca3890473..554982706 100644 --- a/public/remmina__file__editor_8h.html +++ b/public/remmina__file__editor_8h.html @@ -190,7 +190,7 @@ Functions
-

Definition at line 1970 of file remmina_file_editor.c.

+

Definition at line 1971 of file remmina_file_editor.c.

@@ -210,7 +210,7 @@ Functions
-

Definition at line 1997 of file remmina_file_editor.c.

+

Definition at line 1998 of file remmina_file_editor.c.

@@ -248,7 +248,7 @@ Functions
-

Definition at line 2140 of file remmina_file_editor.c.

+

Definition at line 2141 of file remmina_file_editor.c.

@@ -268,7 +268,7 @@ Functions
-

Definition at line 2160 of file remmina_file_editor.c.

+

Definition at line 2161 of file remmina_file_editor.c.

@@ -288,7 +288,7 @@ Functions
-

Definition at line 2011 of file remmina_file_editor.c.

+

Definition at line 2012 of file remmina_file_editor.c.

@@ -308,7 +308,7 @@ Functions
-

Definition at line 2179 of file remmina_file_editor.c.

+

Definition at line 2180 of file remmina_file_editor.c.

@@ -338,7 +338,7 @@ Functions
-

Definition at line 2146 of file remmina_file_editor.c.

+

Definition at line 2147 of file remmina_file_editor.c.

diff --git a/public/remmina__file__editor_8h_source.html b/public/remmina__file__editor_8h_source.html index b7215604d..25e7e1816 100644 --- a/public/remmina__file__editor_8h_source.html +++ b/public/remmina__file__editor_8h_source.html @@ -89,19 +89,19 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8h_source.html', Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #pragma once
38 
39 #include <stdarg.h>
40 #include <glib/gi18n.h>
41 #include <gtk/gtk.h>
42 
43 #include "remmina_file.h"
44 
45 G_BEGIN_DECLS
46 
47 #define REMMINA_TYPE_FILE_EDITOR (remmina_file_editor_get_type())
48 #define REMMINA_FILE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), REMMINA_TYPE_FILE_EDITOR, RemminaFileEditor))
49 #define REMMINA_FILE_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), REMMINA_TYPE_FILE_EDITOR, RemminaFileEditorClass))
50 #define REMMINA_IS_FILE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), REMMINA_TYPE_FILE_EDITOR))
51 #define REMMINA_IS_FILE_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), REMMINA_TYPE_FILE_EDITOR))
52 #define REMMINA_FILE_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), REMMINA_TYPE_FILE_EDITOR, RemminaFileEditorClass))
53 
54 typedef struct _RemminaFileEditorPriv RemminaFileEditorPriv;
55 
56 typedef struct _RemminaFileEditor {
57  GtkDialog dialog;
58 
61 
62 typedef struct _RemminaFileEditorClass {
63  GtkDialogClass parent_class;
65 
67 G_GNUC_CONST;
68 
69 /* Base constructor */
70 GtkWidget *remmina_file_editor_new_from_file(RemminaFile *remminafile);
71 /* Create new file */
72 GtkWidget *remmina_file_editor_new(void);
73 GtkWidget *remmina_file_editor_new_full(const gchar *server, const gchar *protocol);
74 GtkWidget *remmina_file_editor_new_copy(const gchar *filename);
75 /* Open existing file */
76 GtkWidget *remmina_file_editor_new_from_filename(const gchar *filename);
79 
80 G_END_DECLS
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
struct _RemminaFileEditor RemminaFileEditor
-
void remmina_file_editor_check_profile(RemminaFileEditor *gfe)
+
void remmina_file_editor_check_profile(RemminaFileEditor *gfe)
struct _RemminaFileEditorPriv RemminaFileEditorPriv
-
void remmina_file_editor_file_save(RemminaFileEditor *gfe)
-
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
+
void remmina_file_editor_file_save(RemminaFileEditor *gfe)
+
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
struct _RemminaFileEditorClass RemminaFileEditorClass
-
GtkWidget * remmina_file_editor_new(void)
+
GtkWidget * remmina_file_editor_new(void)
GType remmina_file_editor_get_type(void) G_GNUC_CONST
-
GtkWidget * remmina_file_editor_new_from_file(RemminaFile *remminafile)
-
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
-
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
+
GtkWidget * remmina_file_editor_new_from_file(RemminaFile *remminafile)
+
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
RemminaFileEditorPriv * priv
diff --git a/public/remmina__main_8c_source.html b/public/remmina__main_8c_source.html index 5745ce701..aa550fd39 100644 --- a/public/remmina__main_8c_source.html +++ b/public/remmina__main_8c_source.html @@ -234,7 +234,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gint view_file_mode
Definition: remmina_pref.h:214
RemminaStringArray * remmina_string_array_new(void)
void remmina_file_touch(RemminaFile *remminafile)
Update the atime and mtime of a given filename.
-
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
Definition: remmina_main.c:79
static void remmina_main_save_expanded_group_func(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data)
Definition: remmina_main.c:150
void remmina_main_on_show(GtkWidget *w, gpointer user_data)
@@ -261,7 +261,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: remmina_file.c:603
void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_about_open(GtkWindow *parent)
Definition: remmina_about.c:44
-
GtkWidget * remmina_file_editor_new(void)
+
GtkWidget * remmina_file_editor_new(void)
Definition: remmina_pref.h:55
Definition: remmina_exec.h:60
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
@@ -292,7 +292,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
static GtkTargetEntry remmina_drop_types[]
Definition: remmina_main.c:126
GtkSearchBar * search_bar
Definition: remmina_main.h:67
static RemminaMain * remminamain
Definition: remmina_main.c:69
-
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
+
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
GtkEntry * entry_quick_connect_server
Definition: remmina_main.h:71
gint remmina_unlock_new(GtkWindow *parent)
-- cgit v1.2.3