From b907c1023f99c685576b443229f680427eb6ce09 Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Wed, 14 Jun 2023 12:38:12 +0000 Subject: Automatic doc build by remmina-ci --- public/rcw_8c_source.html | 2 +- public/remmina__exec_8c_source.html | 4 +- public/remmina__file_8c_source.html | 4 +- public/remmina__file__editor_8c_source.html | 2 +- public/remmina__main_8c.html | 110 ++++++++++++------------- public/remmina__main_8c_source.html | 80 +++++++++--------- public/remmina__main_8h.html | 42 +++++----- public/remmina__main_8h_source.html | 42 +++++----- public/remmina__mpchange_8c_source.html | 2 +- public/remmina__plugin__manager_8c_source.html | 4 +- 10 files changed, 146 insertions(+), 146 deletions(-) (limited to 'public') diff --git a/public/rcw_8c_source.html b/public/rcw_8c_source.html index 803cbde92..c1c243be1 100644 --- a/public/rcw_8c_source.html +++ b/public/rcw_8c_source.html @@ -117,7 +117,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
gchar * remmina_pref_file
Definition: rcw.c:78
static void rcw_toolbar_fullscreen(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
Definition: rcw.c:1351
static void rcw_on_switch_page(GtkNotebook *notebook, GtkWidget *newpage, guint page_num, RemminaConnectionWindow *cnnwin)
Definition: rcw.c:3653
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
static gboolean rcw_hostkey_func(RemminaProtocolWidget *gp, guint keyval, gboolean release)
Definition: rcw.c:4053
void remmina_scrolled_viewport_remove_motion(RemminaScrolledViewport *gsv)
diff --git a/public/remmina__exec_8c_source.html b/public/remmina__exec_8c_source.html index c47f3d0fa..57ee93e9a 100644 --- a/public/remmina__exec_8c_source.html +++ b/public/remmina__exec_8c_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('remmina__exec_8c_source.html','');}); Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010 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 "config.h"
38 #include "buildflags.h"
39 #include <glib/gi18n.h>
40 #include <stdlib.h>
41 #include "remmina.h"
42 #include "remmina_main.h"
43 #include "remmina_log.h"
44 #include "remmina_pref.h"
45 #include "remmina_widget_pool.h"
46 #include "remmina_unlock.h"
47 #include "remmina_pref_dialog.h"
48 #include "remmina_file.h"
49 #include "remmina_file_manager.h"
50 #include "remmina_file_editor.h"
51 #include "rcw.h"
52 #include "remmina_about.h"
53 #include "remmina_plugin_manager.h"
54 #include "remmina_exec.h"
56 #include "remmina_file_manager.h"
57 #include "remmina_crypt.h"
58 
59 #include "remmina_icon.h"
60 
61 #ifdef SNAP_BUILD
62 # define ISSNAP "- SNAP Build -"
63 #else
64 # define ISSNAP "-"
65 #endif
66 
67 static gboolean cb_closewidget(GtkWidget *widget, gpointer data)
68 {
69  TRACE_CALL(__func__);
70  /* The correct way to close a rcw is to send
71  * it a "delete-event" signal. Simply destroying it will not close
72  * all network connections */
73  if (REMMINA_IS_CONNECTION_WINDOW(widget))
74  return rcw_delete(RCW(widget));
75  return TRUE;
76 }
77 
79 {
80  static const gchar build_config[] =
81  "Build configuration: " BUILD_CONFIG "\n"
82  "Build type: " BUILD_TYPE "\n"
83  "CFLAGS: " CFLAGS "\n"
84  "Compiler: " COMPILER_ID ", " COMPILER_VERSION "\n"
85  "Target architecture: " TARGET_ARCH "\n";
86  return build_config;
87 }
88 
90 {
91  TRACE_CALL(__func__);
92 
93  /* Save main window state/position */
95 
96  /* Delete all widgets, main window not included */
98 
99 #ifdef HAVE_LIBAPPINDICATOR
100  /* Remove systray menu */
102 #endif
103 
104  /* close/destroy main window struct and window */
106 
107  /* Exit from Remmina */
108  g_application_quit(g_application_get_default());
109 }
110 
111 static gboolean disable_rcw_delete_confirm_cb(GtkWidget *widget, gpointer data)
112 {
113  TRACE_CALL(__func__);
115 
116  if (REMMINA_IS_CONNECTION_WINDOW(widget)) {
117  rcw = (RemminaConnectionWindow*)widget;
119  }
120  return TRUE;
121 }
122 
124 {
125  TRACE_CALL(__func__);
126 
127  /* Exit remmina only if there are no interesting windows left:
128  * no main window, no systray menu, no connection window.
129  * This function is usually called after a disconnection */
130 
131  switch (why) {
133  // A connection has disconnected, should we exit remmina ?
136  break;
138  /* If we are in Kiosk mode, we just exit */
139  if (kioskmode && kioskmode == TRUE)
141  // Main window has been deleted
144  break;
146  // Quit command has been sent from main window or appindicator/systray menu
147  // quit means QUIT.
150  break;
151  }
152 }
153 
154 
155 static void newline_remove(char *s)
156 {
157  char c;
158  while((c = *s) != 0 && c != '\r' && c != '\n')
159  s++;
160  *s = 0;
161 }
162 
163 /* used for commandline parameter --update-profile X --set-option Y --set-option Z
164  * return a status code for exit()
165  */
166 int remmina_exec_set_setting(gchar *profilefilename, gchar **settings)
167 {
168  RemminaFile *remminafile;
169  int i;
170  gchar **tk, *value = NULL;
171  char *line = NULL;
172  size_t len = 0;
173  ssize_t read;
174  gboolean abort = FALSE;
175 
176  remminafile = remmina_file_manager_load_file(profilefilename);
177 
178  if (!remminafile) {
179  g_print("Unable to open profile file %s\n", profilefilename);
180  return 2;
181  }
182 
183  for(i = 0; settings[i] != NULL && !abort; i++) {
184  if (strlen(settings[i]) > 0) {
185  tk = g_strsplit(settings[i], "=", 2);
186  if (tk[1] == NULL) {
187  read = getline(&line, &len, stdin);
188  if (read > 0) {
189  newline_remove(line);
190  value = line;
191  } else {
192  g_print("Error: an extra line of standard input is needed\n");
193  abort = TRUE;
194  }
195  } else
196  value = tk[1];
197  remmina_file_set_string(remminafile, tk[0], value);
198  g_strfreev(tk);
199  }
200  }
201 
202  if (line) free(line);
203 
204  if (!abort) remmina_file_save(remminafile);
205 
206  return 0;
207 
208 }
209 
210 static void remmina_exec_autostart_cb(RemminaFile *remminafile, gpointer user_data)
211 {
212  TRACE_CALL(__func__);
213 
214  if (remmina_file_get_int(remminafile, "enable-autostart", FALSE)) {
215  REMMINA_DEBUG ("Profile %s is set to autostart", remminafile->filename);
216  rcw_open_from_filename(remminafile->filename);
217  }
218 
219 }
220 
221 static void remmina_exec_connect(const gchar *data)
222 {
223  TRACE_CALL(__func__);
224 
225  gchar *protocol;
226  gchar **protocolserver;
227  gchar *server;
228  RemminaFile *remminafile;
229  gchar **userat;
230  gchar **userpass;
231  gchar *user;
232  gchar *password;
233  gchar **domainuser;
234  gchar **serverquery;
235  gchar **querystring;
236  gchar **querystringpart;
237  gchar **querystringpartkv;
238  gchar *value;
239  gchar *temp;
240  GError *error = NULL;
241 
242  protocol = NULL;
243  if (strncmp("rdp://", data, 6) == 0 || strncmp("RDP://", data, 6) == 0)
244  protocol = "RDP";
245  else if (strncmp("vnc://", data, 6) == 0 || strncmp("VNC://", data, 6) == 0)
246  protocol = "VNC";
247  else if (strncmp("ssh://", data, 6) == 0 || strncmp("SSH://", data, 6) == 0)
248  protocol = "SSH";
249  else if (strncmp("spice://", data, 8) == 0 || strncmp("SPICE://", data, 8) == 0)
250  protocol = "SPICE";
251 
252  if (strncmp("file://", data, 6) == 0) {
253  gchar *filename = g_filename_from_uri (data, NULL, &error);
254  if (filename != NULL) {
255  rcw_open_from_filename(filename);
256  } else
257  REMMINA_DEBUG ("Opening URI %s failed with error %s", data, error->message);
258  g_error_free(error);
259  return;
260  }
261 
262  if (protocol == NULL) {
264  return;
265  }
266 
267  protocolserver = g_strsplit(data, "://", 2);
268  server = g_strdup(protocolserver[1]);
269 
270  // Support loading .remmina files using handler
271  if ((temp = strrchr(server, '.')) != NULL && g_strcmp0(temp + 1, "remmina") == 0) {
272  g_strfreev(protocolserver);
273  temp = g_uri_unescape_string(server, NULL);
274  g_free(server);
275  server = temp;
276  rcw_open_from_filename(server);
277  return;
278  }
279 
280  remminafile = remmina_file_new();
281 
282  // Check for username@server
283  if ((strcmp(protocol, "RDP") == 0 || strcmp(protocol, "VNC") == 0 || strcmp(protocol, "SSH") == 0) && strstr(server, "@") != NULL) {
284  userat = g_strsplit(server, "@", 2);
285 
286  // Check for username:password
287  if (strstr(userat[0], ":") != NULL) {
288  userpass = g_strsplit(userat[0], ":", 2);
289  user = g_uri_unescape_string(userpass[0], NULL);
290  password = g_uri_unescape_string(userpass[1], NULL);
291 
292  // Try to decrypt the password field if it contains =
293  temp = password != NULL && strrchr(password, '=') != NULL ? remmina_crypt_decrypt(password) : NULL;
294  if (temp != NULL) {
295  g_free(password);
296  password = temp;
297  }
298  remmina_file_set_string(remminafile, "password", password);
299  g_free(password);
300  g_strfreev(userpass);
301  } else {
302  user = g_uri_unescape_string(userat[0], NULL);
303  }
304 
305  // Check for domain\user for RDP connections
306  if (strcmp(protocol, "RDP") == 0 && strstr(user, "\\") != NULL) {
307  domainuser = g_strsplit(user, "\\", 2);
308  remmina_file_set_string(remminafile, "domain", domainuser[0]);
309  g_free(user);
310  user = g_strdup(domainuser[1]);
311  }
312 
313  remmina_file_set_string(remminafile, "username", user);
314  g_free(user);
315  g_free(server);
316  server = g_strdup(userat[1]);
317  g_strfreev(userat);
318  }
319 
320  if (strcmp(protocol, "VNC") == 0 && strstr(server, "?") != NULL) {
321  // https://tools.ietf.org/html/rfc7869
322  // VncUsername, VncPassword and ColorLevel supported for vnc-params
323 
324  // Check for query string parameters
325  serverquery = g_strsplit(server, "?", 2);
326  querystring = g_strsplit(serverquery[1], "&", -1);
327  for (querystringpart = querystring; *querystringpart; querystringpart++) {
328  if (strstr(*querystringpart, "=") == NULL)
329  continue;
330  querystringpartkv = g_strsplit(*querystringpart, "=", 2);
331  value = g_uri_unescape_string(querystringpartkv[1], NULL);
332  if (strcmp(querystringpartkv[0], "VncPassword") == 0) {
333  // Try to decrypt password field if it contains =
334  temp = value != NULL && strrchr(value, '=') != NULL ? remmina_crypt_decrypt(value) : NULL;
335  if (temp != NULL) {
336  g_free(value);
337  value = temp;
338  }
339  remmina_file_set_string(remminafile, "password", value);
340  } else if (strcmp(querystringpartkv[0], "VncUsername") == 0) {
341  remmina_file_set_string(remminafile, "username", value);
342  } else if (strcmp(querystringpartkv[0], "ColorLevel") == 0) {
343  remmina_file_set_string(remminafile, "colordepth", value);
344  }
345  g_free(value);
346  g_strfreev(querystringpartkv);
347  }
348  g_strfreev(querystring);
349  g_free(server);
350  server = g_strdup(serverquery[0]);
351  g_strfreev(serverquery);
352  }
353 
354  // Unescape server
355  temp = g_uri_unescape_string(server, NULL);
356  g_free(server);
357  server = temp;
358 
359  remmina_file_set_string(remminafile, "server", server);
360  remmina_file_set_string(remminafile, "name", server);
361  remmina_file_set_string(remminafile, "sound", "off");
362  remmina_file_set_string(remminafile, "protocol", protocol);
363  g_free(server);
364  g_strfreev(protocolserver);
365  rcw_open_from_file(remminafile);
366 }
367 
368 void remmina_exec_command(RemminaCommandType command, const gchar* data)
369 {
370  TRACE_CALL(__func__);
371  gchar *s1;
372  gchar *s2;
373  gchar *temp;
374  GtkWidget *widget;
375  GtkWindow *mainwindow;
376  GtkWidget *prefdialog;
377  RemminaEntryPlugin *plugin;
378  int i;
379  int ch;
380  mainwindow = remmina_main_get_window();
381 
382  switch (command) {
385  break;
386 
388  if (mainwindow) {
389  gtk_window_present(mainwindow);
390  gtk_window_deiconify(GTK_WINDOW(mainwindow));
391  }else {
392  widget = remmina_main_new();
393  gtk_widget_show(widget);
394  }
395  break;
396 
398  if (remmina_pref_get_boolean("use_primary_password")
399  && remmina_unlock_new(mainwindow) == 0)
400  break;
401  prefdialog = remmina_pref_dialog_get_dialog();
402  if (prefdialog) {
403  gtk_window_present(GTK_WINDOW(prefdialog));
404  gtk_window_deiconify(GTK_WINDOW(prefdialog));
405  }else {
406  /* Create a new preference dialog */
407  widget = remmina_pref_dialog_new(atoi(data), NULL);
408  gtk_widget_show(widget);
409  }
410  break;
411 
412  case REMMINA_COMMAND_NEW:
413  if (remmina_pref_get_boolean("lock_edit")
414  && remmina_pref_get_boolean("use_primary_password"))
415  if (remmina_unlock_new(mainwindow) == 0)
416  break;
417  s1 = (data ? strchr(data, ',') : NULL);
418  if (s1) {
419  s1 = g_strdup(data);
420  s2 = strchr(s1, ',');
421  *s2++ = '\0';
422  widget = remmina_file_editor_new_full(s2, s1);
423  g_free(s1);
424  }else {
425  widget = remmina_file_editor_new_full(NULL, data);
426  }
427  gtk_widget_show(widget);
428  break;
429 
431  REMMINA_DEBUG ("Initiating connection");
436  if (remmina_pref_get_boolean("lock_connect")
437  && remmina_pref_get_boolean("use_primary_password"))
438  if (remmina_unlock_new(mainwindow) == 0)
439  break;
440  remmina_exec_connect(data);
441  break;
442 
444  if (remmina_pref_get_boolean("lock_edit")
445  && remmina_pref_get_boolean("use_primary_password"))
446  if (remmina_unlock_new(mainwindow) == 0)
447  break;
449  if (widget)
450  gtk_widget_show(widget);
451  break;
452 
454  remmina_about_open(NULL);
455  break;
456 
458  mainwindow = remmina_main_get_window();
459  if (mainwindow) {
460  remmina_about_open(NULL);
461  }else {
462  g_print("%s %s %s (git %s)\n", g_get_application_name(), ISSNAP, VERSION, REMMINA_GIT_REVISION);
463  /* As we do not use the "handle-local-options" signal, we have to exit Remmina */
465  }
466 
467  break;
468 
470  mainwindow = remmina_main_get_window();
471  if (mainwindow) {
472  /* Show th widget with the list of plugins and versions */
473  remmina_plugin_manager_show(mainwindow);
474  }else {
475  g_print("\n%s %s %s (git %s)\n\n", g_get_application_name(), ISSNAP, VERSION, REMMINA_GIT_REVISION);
476 
478  g_print("\n%s\n", remmina_exec_get_build_config());
480  }
481 
482  break;
483 
484 
487  if (plugin) {
488  plugin->entry_func(plugin);
489  }else {
490  widget = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
491  _("Plugin %s is not registered."), data);
492  g_signal_connect(G_OBJECT(widget), "response", G_CALLBACK(gtk_widget_destroy), NULL);
493  gtk_widget_show(widget);
495  }
496  break;
497 
499  i = 0;
500  g_print("Enter the password you want to encrypt: ");
501  temp = (char *)g_malloc(255 * sizeof(char));
502  while ((ch = getchar()) != EOF && ch != '\n') {
503  if (i < 254) {
504  temp[i] = ch;
505  i++;
506  }
507  }
508  temp[i] = '\0';
509  s1 = remmina_crypt_encrypt(temp);
510  s2 = g_uri_escape_string(s1, NULL, TRUE);
511  g_print("\nEncrypted password: %s\n\n", s1);
512  g_print("Usage:\n");
513  g_print("rdp://username:%s@server\n", s1);
514  g_print("vnc://username:%s@server\n", s1);
515  g_print("vnc://server?VncUsername=user\\&VncPassword=%s\n", s2);
516  g_free(s1);
517  g_free(s2);
518  g_free(temp);
520  break;
521 
525  break;
526 
527  default:
528  break;
529  }
530 }
int remmina_exec_set_setting(gchar *profilefilename, gchar **settings)
Definition: remmina_exec.c:166
RemminaCondExitType
Definition: remmina_exec.h:58
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
gchar * remmina_crypt_decrypt(const gchar *str)
@@ -105,7 +105,7 @@ $(document).ready(function(){initNavTree('remmina__exec_8c_source.html','');});
gboolean remmina_icon_is_available(void)
Determine whenever the Remmina icon is available.
Definition: remmina_icon.c:318
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
-
GtkWidget * remmina_main_new(void)
+
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
diff --git a/public/remmina__file_8c_source.html b/public/remmina__file_8c_source.html index 1e91d358e..012815b5d 100644 --- a/public/remmina__file_8c_source.html +++ b/public/remmina__file_8c_source.html @@ -122,7 +122,7 @@ $(document).ready(function(){initNavTree('remmina__file_8c_source.html','');});
gchar * remmina_file_format_properties(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:561
const RemminaProtocolSetting * find_protocol_setting(const gchar *name, RemminaProtocolPlugin *protocol_plugin)
Definition: remmina_file.c:235
-
void remmina_main_update_file_datetime(RemminaFile *file)
+
void remmina_main_update_file_datetime(RemminaFile *file)
const gchar * icon_name_ssh
Definition: plugin.h:73
gint remmina_file_get_state_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: remmina_file.c:615
void remmina_file_state_last_success(RemminaFile *remminafile)
Definition: remmina_file.c:946
@@ -135,7 +135,7 @@ $(document).ready(function(){initNavTree('remmina__file_8c_source.html','');});
gchar * remmina_crypt_encrypt(const gchar *str)
Definition: remmina_crypt.c:93
gdouble remmina_file_get_state_double(RemminaFile *remminafile, const gchar *setting, gdouble default_value)
Definition: remmina_file.c:655
-
void remmina_main_show_warning_dialog(const gchar *message)
+
void remmina_main_show_warning_dialog(const gchar *message)
void remmina_file_set_int(RemminaFile *remminafile, const gchar *setting, gint value)
Definition: remmina_file.c:585
static GKeyFile * remmina_file_get_keyfile(RemminaFile *remminafile)
Definition: remmina_file.c:680
diff --git a/public/remmina__file__editor_8c_source.html b/public/remmina__file__editor_8c_source.html index 12d7bf00c..7a334ebe7 100644 --- a/public/remmina__file__editor_8c_source.html +++ b/public/remmina__file__editor_8c_source.html @@ -106,7 +106,7 @@ $(document).ready(function(){initNavTree('remmina__file__editor_8c_source.html',
static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
gchar * remmina_pref_file
Definition: rcw.c:78
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
void remmina_string_list_set_validation_func(RemminaStringListValidationFunc func)
G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
diff --git a/public/remmina__main_8c.html b/public/remmina__main_8c.html index 40c1d1c9e..64a3eef00 100644 --- a/public/remmina__main_8c.html +++ b/public/remmina__main_8c.html @@ -342,7 +342,7 @@ Variables
-

Definition at line 1312 of file remmina_main.c.

+

Definition at line 1315 of file remmina_main.c.

@@ -386,7 +386,7 @@ Variables
-

Definition at line 1201 of file remmina_main.c.

+

Definition at line 1204 of file remmina_main.c.

@@ -430,7 +430,7 @@ Variables
-

Definition at line 1532 of file remmina_main.c.

+

Definition at line 1534 of file remmina_main.c.

@@ -638,7 +638,7 @@ Variables
-

Definition at line 1448 of file remmina_main.c.

+

Definition at line 1450 of file remmina_main.c.

@@ -674,7 +674,7 @@ Variables
-

Definition at line 1471 of file remmina_main.c.

+

Definition at line 1473 of file remmina_main.c.

@@ -716,7 +716,7 @@ Variables
-

Definition at line 1430 of file remmina_main.c.

+

Definition at line 1432 of file remmina_main.c.

@@ -818,7 +818,7 @@ Variables
-

Definition at line 1716 of file remmina_main.c.

+

Definition at line 1718 of file remmina_main.c.

@@ -866,7 +866,7 @@ Variables
-

Definition at line 1158 of file remmina_main.c.

+

Definition at line 1161 of file remmina_main.c.

@@ -895,7 +895,7 @@ Variables
Todo:
Set entry_quick_connect_server as default search entry. Weirdly. This does not work yet.
-

Definition at line 1551 of file remmina_main.c.

+

Definition at line 1553 of file remmina_main.c.

@@ -1170,7 +1170,7 @@ Variables
-

Definition at line 1632 of file remmina_main.c.

+

Definition at line 1634 of file remmina_main.c.

@@ -1226,7 +1226,7 @@ Variables
-

Definition at line 1417 of file remmina_main.c.

+

Definition at line 1419 of file remmina_main.c.

@@ -1262,7 +1262,7 @@ Variables
-

Definition at line 1306 of file remmina_main.c.

+

Definition at line 1309 of file remmina_main.c.

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

Definition at line 1260 of file remmina_main.c.

+

Definition at line 1263 of file remmina_main.c.

@@ -1334,7 +1334,7 @@ Variables
-

Definition at line 1112 of file remmina_main.c.

+

Definition at line 1115 of file remmina_main.c.

@@ -1406,7 +1406,7 @@ Variables
-

Definition at line 1254 of file remmina_main.c.

+

Definition at line 1257 of file remmina_main.c.

@@ -1442,7 +1442,7 @@ Variables
-

Definition at line 1086 of file remmina_main.c.

+

Definition at line 1091 of file remmina_main.c.

@@ -1478,7 +1478,7 @@ Variables
-

Definition at line 1140 of file remmina_main.c.

+

Definition at line 1143 of file remmina_main.c.

@@ -1514,7 +1514,7 @@ Variables
-

Definition at line 1393 of file remmina_main.c.

+

Definition at line 1396 of file remmina_main.c.

@@ -1802,7 +1802,7 @@ Variables
-

Definition at line 1423 of file remmina_main.c.

+

Definition at line 1425 of file remmina_main.c.

@@ -1838,7 +1838,7 @@ Variables
-

Definition at line 1288 of file remmina_main.c.

+

Definition at line 1291 of file remmina_main.c.

@@ -1874,7 +1874,7 @@ Variables
-

Definition at line 1300 of file remmina_main.c.

+

Definition at line 1303 of file remmina_main.c.

@@ -1910,7 +1910,7 @@ Variables
-

Definition at line 1294 of file remmina_main.c.

+

Definition at line 1297 of file remmina_main.c.

@@ -1946,7 +1946,7 @@ Variables
-

Definition at line 1276 of file remmina_main.c.

+

Definition at line 1279 of file remmina_main.c.

@@ -1982,7 +1982,7 @@ Variables
-

Definition at line 1282 of file remmina_main.c.

+

Definition at line 1285 of file remmina_main.c.

@@ -2018,7 +2018,7 @@ Variables
-

Definition at line 1399 of file remmina_main.c.

+

Definition at line 1402 of file remmina_main.c.

@@ -2054,7 +2054,7 @@ Variables
-

Definition at line 1225 of file remmina_main.c.

+

Definition at line 1228 of file remmina_main.c.

@@ -2090,7 +2090,7 @@ Variables
-

Definition at line 1213 of file remmina_main.c.

+

Definition at line 1216 of file remmina_main.c.

@@ -2109,7 +2109,7 @@ Variables
-

Definition at line 1148 of file remmina_main.c.

+

Definition at line 1151 of file remmina_main.c.

@@ -2233,7 +2233,7 @@ Variables
-

Definition at line 1513 of file remmina_main.c.

+

Definition at line 1515 of file remmina_main.c.

@@ -2263,7 +2263,7 @@ Variables
-

Definition at line 1623 of file remmina_main.c.

+

Definition at line 1625 of file remmina_main.c.

@@ -2318,7 +2318,7 @@ Variables
-

Definition at line 1544 of file remmina_main.c.

+

Definition at line 1546 of file remmina_main.c.

@@ -2348,7 +2348,7 @@ Variables
-

Definition at line 1387 of file remmina_main.c.

+

Definition at line 1390 of file remmina_main.c.

@@ -2378,7 +2378,7 @@ Variables
-

Definition at line 1493 of file remmina_main.c.

+

Definition at line 1495 of file remmina_main.c.

@@ -2420,7 +2420,7 @@ Variables
-

Definition at line 1486 of file remmina_main.c.

+

Definition at line 1488 of file remmina_main.c.

@@ -2448,7 +2448,7 @@ Variables
-

Definition at line 1324 of file remmina_main.c.

+

Definition at line 1327 of file remmina_main.c.

@@ -2478,7 +2478,7 @@ Variables
-

Definition at line 1378 of file remmina_main.c.

+

Definition at line 1381 of file remmina_main.c.

@@ -2786,7 +2786,7 @@ Variables
-

Definition at line 1735 of file remmina_main.c.

+

Definition at line 1737 of file remmina_main.c.

@@ -2833,7 +2833,7 @@ Variables
-

Definition at line 1745 of file remmina_main.c.

+

Definition at line 1747 of file remmina_main.c.

@@ -2903,7 +2903,7 @@ Variables
-

Definition at line 1728 of file remmina_main.c.

+

Definition at line 1730 of file remmina_main.c.

@@ -2927,18 +2927,18 @@ Variables
-Initial value:
= {
{ "about", remmina_main_on_action_application_about, NULL, NULL, NULL },
{ "default", remmina_main_on_action_application_default, NULL, NULL, NULL },
{ "mpchange", remmina_main_on_action_application_mpchange, NULL, NULL, NULL },
{ "plugins", remmina_main_on_action_application_plugins, NULL, NULL, NULL },
{ "preferences", remmina_main_on_action_application_preferences, "i", NULL, NULL },
{ "dark", remmina_main_on_action_application_dark_theme, NULL, NULL, NULL },
{ "debug", remmina_main_on_action_help_debug, NULL, NULL, NULL },
{ "community", remmina_main_on_action_help_community, NULL, NULL, NULL },
{ "donations", remmina_main_on_action_help_donations, NULL, NULL, NULL },
{ "homepage", remmina_main_on_action_help_homepage, NULL, NULL, NULL },
{ "wiki", remmina_main_on_action_help_wiki, NULL, NULL, NULL },
{ "quit", remmina_main_on_action_application_quit, NULL, NULL, NULL },
}
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
+Initial value:
= {
{ "about", remmina_main_on_action_application_about, NULL, NULL, NULL },
{ "default", remmina_main_on_action_application_default, NULL, NULL, NULL },
{ "mpchange", remmina_main_on_action_application_mpchange, NULL, NULL, NULL },
{ "plugins", remmina_main_on_action_application_plugins, NULL, NULL, NULL },
{ "preferences", remmina_main_on_action_application_preferences, "i", NULL, NULL },
{ "dark", remmina_main_on_action_application_dark_theme, NULL, NULL, NULL },
{ "debug", remmina_main_on_action_help_debug, NULL, NULL, NULL },
{ "community", remmina_main_on_action_help_community, NULL, NULL, NULL },
{ "donations", remmina_main_on_action_help_donations, NULL, NULL, NULL },
{ "homepage", remmina_main_on_action_help_homepage, NULL, NULL, NULL },
{ "wiki", remmina_main_on_action_help_wiki, NULL, NULL, NULL },
{ "quit", remmina_main_on_action_application_quit, NULL, NULL, NULL },
}
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:814
-
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)

Definition at line 96 of file remmina_main.c.

@@ -2964,17 +2964,17 @@ Variables
Initial value:
= {
{ "connect", remmina_main_on_action_connection_connect, NULL, NULL, NULL },
{ "copy", remmina_main_on_action_connection_copy, NULL, NULL, NULL },
{ "delete", remmina_main_on_action_connection_delete, NULL, NULL, NULL },
{ "delete_multiple", remmina_main_on_action_connection_delete_multiple, NULL, NULL, NULL },
{ "edit", remmina_main_on_action_connection_edit, NULL, NULL, NULL },
{ "exttools", remmina_main_on_action_connection_external_tools, NULL, NULL, NULL },
{ "new", remmina_main_on_action_connection_new, NULL, NULL, NULL },
{ "export", remmina_main_on_action_tools_export, NULL, NULL, NULL },
{ "import", remmina_main_on_action_tools_import, NULL, NULL, NULL },
{ "expand", remmina_main_on_action_expand, NULL, NULL, NULL },
{ "collapse", remmina_main_on_action_collapse, NULL, NULL, NULL },
{ "search", remmina_main_on_action_search_toggle, NULL, NULL, NULL },
}
void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:768
-
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:910
-
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:851
void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:977
void remmina_main_on_action_connection_external_tools(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:796
void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:946
-
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)

Definition at line 111 of file remmina_main.c.

diff --git a/public/remmina__main_8c_source.html b/public/remmina__main_8c_source.html index c46d17d00..faa948a8b 100644 --- a/public/remmina__main_8c_source.html +++ b/public/remmina__main_8c_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
remmina_main.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-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #include "config.h"
39 #include <ctype.h>
40 #include <gio/gio.h>
41 #ifndef __APPLE__
42 #include <gio/gdesktopappinfo.h>
43 #endif
44 #include <gdk/gdkkeysyms.h>
45 #include <glib/gi18n.h>
46 #include <gtk/gtk.h>
47 
48 #include "remmina.h"
49 #include "remmina_string_array.h"
50 #include "remmina_public.h"
51 #include "remmina_file.h"
52 #include "remmina_file_manager.h"
53 #include "remmina_file_editor.h"
54 #include "rcw.h"
55 #include "remmina_about.h"
56 #include "remmina_pref.h"
57 #include "remmina_pref_dialog.h"
58 #include "remmina_widget_pool.h"
59 #include "remmina_plugin_manager.h"
60 #include "remmina_log.h"
61 #include "remmina_icon.h"
62 #include "remmina_main.h"
63 #include "remmina_exec.h"
64 #include "remmina_mpchange.h"
65 #include "remmina_external_tools.h"
66 #include "remmina_unlock.h"
68 
70 
71 #define RM_GET_OBJECT(object_name) gtk_builder_get_object(remminamain->builder, object_name)
72 
73 enum {
84 };
85 
86 static
87 const gchar *supported_mime_types[] = {
88  "x-scheme-handler/rdp",
89  "x-scheme-handler/spice",
90  "x-scheme-handler/vnc",
91  "x-scheme-handler/remmina",
92  "application/x-remmina",
93  NULL
94 };
95 
96 static GActionEntry app_actions[] = {
97  { "about", remmina_main_on_action_application_about, NULL, NULL, NULL },
98  { "default", remmina_main_on_action_application_default, NULL, NULL, NULL },
99  { "mpchange", remmina_main_on_action_application_mpchange, NULL, NULL, NULL },
100  { "plugins", remmina_main_on_action_application_plugins, NULL, NULL, NULL },
101  { "preferences", remmina_main_on_action_application_preferences, "i", NULL, NULL },
102  { "dark", remmina_main_on_action_application_dark_theme, NULL, NULL, NULL },
103  { "debug", remmina_main_on_action_help_debug, NULL, NULL, NULL },
104  { "community", remmina_main_on_action_help_community, NULL, NULL, NULL },
105  { "donations", remmina_main_on_action_help_donations, NULL, NULL, NULL },
106  { "homepage", remmina_main_on_action_help_homepage, NULL, NULL, NULL },
107  { "wiki", remmina_main_on_action_help_wiki, NULL, NULL, NULL },
108  { "quit", remmina_main_on_action_application_quit, NULL, NULL, NULL },
109 };
110 
111 static GActionEntry main_actions[] = {
112  { "connect", remmina_main_on_action_connection_connect, NULL, NULL, NULL },
113  { "copy", remmina_main_on_action_connection_copy, NULL, NULL, NULL },
114  { "delete", remmina_main_on_action_connection_delete, NULL, NULL, NULL },
115  { "delete_multiple", remmina_main_on_action_connection_delete_multiple, NULL, NULL, NULL },
116  { "edit", remmina_main_on_action_connection_edit, NULL, NULL, NULL },
117  { "exttools", remmina_main_on_action_connection_external_tools, NULL, NULL, NULL },
118  { "new", remmina_main_on_action_connection_new, NULL, NULL, NULL },
119  { "export", remmina_main_on_action_tools_export, NULL, NULL, NULL },
120  { "import", remmina_main_on_action_tools_import, NULL, NULL, NULL },
121  { "expand", remmina_main_on_action_expand, NULL, NULL, NULL },
122  { "collapse", remmina_main_on_action_collapse, NULL, NULL, NULL },
123  { "search", remmina_main_on_action_search_toggle, NULL, NULL, NULL },
124 };
125 
126 static GtkTargetEntry remmina_drop_types[] =
127 {
128  { "text/uri-list", 0, 1 }
129 };
130 
132 {
133  "RDP", "VNC", "SSH", "NX", "SPICE", "X2GO"
134 };
135 
139 static void remmina_main_save_size(void)
140 {
141  TRACE_CALL(__func__);
142  if ((gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(remminamain->window))) & GDK_WINDOW_STATE_MAXIMIZED) == 0) {
143  gtk_window_get_size(remminamain->window, &remmina_pref.main_width, &remmina_pref.main_height);
144  remmina_pref.main_maximize = FALSE;
145  } else {
147  }
148 }
149 
150 static void remmina_main_save_expanded_group_func(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data)
151 {
152  TRACE_CALL(__func__);
153  GtkTreeIter iter;
154  gchar *group;
155 
156  gtk_tree_model_get_iter(remminamain->priv->file_model_sort, &iter, path);
157  gtk_tree_model_get(remminamain->priv->file_model_sort, &iter, GROUP_COLUMN, &group, -1);
158  if (group) {
159  remmina_string_array_add(remminamain->priv->expanded_group, group);
160  g_free(group);
161  }
162 }
163 
165 {
166  TRACE_CALL(__func__);
167  if (GTK_IS_TREE_STORE(remminamain->priv->file_model)) {
168  if (remminamain->priv->expanded_group)
170  remminamain->priv->expanded_group = remmina_string_array_new();
171  gtk_tree_view_map_expanded_rows(remminamain->tree_files_list,
172  (GtkTreeViewMappingFunc)remmina_main_save_expanded_group_func, NULL);
173  }
174 }
175 
181 {
182  TRACE_CALL(__func__);
183  if (!remminamain || !remminamain->window)
184  return;
185 
191 }
192 
194 {
195  TRACE_CALL(__func__);
196 
197  if (remminamain) {
198  if (remminamain->window)
199  gtk_widget_destroy(GTK_WIDGET(remminamain->window));
200 
201  g_object_unref(remminamain->builder);
203  remminamain->priv->expanded_group = NULL;
204  if (remminamain->priv->file_model)
205  g_object_unref(G_OBJECT(remminamain->priv->file_model));
206  g_object_unref(G_OBJECT(remminamain->priv->file_model_filter));
207  g_free(remminamain->priv->selected_filename);
208  g_free(remminamain->priv->selected_name);
209  g_free(remminamain->priv);
210  g_free(remminamain);
211  remminamain = NULL;
212  }
213 }
214 
218 static gboolean remmina_main_dexit(gpointer data)
219 {
220  TRACE_CALL(__func__);
222  return FALSE;
223 }
224 
225 gboolean remmina_main_on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
226 {
227  TRACE_CALL(__func__);
229 
230  g_idle_add(remmina_main_dexit, NULL);
231 
232  return FALSE;
233 }
234 
235 gboolean remmina_main_idle_destroy(gpointer data)
236 {
237  TRACE_CALL(__func__);
238 
239  if (remminamain)
241 
242  return G_SOURCE_REMOVE;
243 }
244 
249 {
250  TRACE_CALL(__func__);
251 
252  if (remminamain) {
253  /* Invalidate remminamain->window to avoid multiple destructions */
254  remminamain->window = NULL;
255  /* Destroy remminamain struct, later. We can't destroy
256  * important objects like the builder now */
257  g_idle_add(remmina_main_idle_destroy, NULL);
258  }
259 }
260 
262 {
263  TRACE_CALL(__func__);
264  g_free(remminamain->priv->selected_filename);
265  g_free(remminamain->priv->selected_name);
266  remminamain->priv->selected_filename = NULL;
267  remminamain->priv->selected_name = NULL;
268 }
269 
270 #ifdef SNAP_BUILD
271 
273 {
274  GtkBuilder *dlgbuilder = NULL;
275  GtkWidget *dlg;
276  GtkWindow *parent;
277  int result;
278  static gboolean shown_once = FALSE;
279  gboolean need_snap_interface_connections = FALSE;
280  GtkWidget *dsa;
282 
283  if (shown_once)
284  return;
285  else
286  shown_once = TRUE;
287 
288  g_print("Remmina is compiled as a SNAP package.\n");
289  remmina_secret_plugin = remmina_plugin_manager_get_secret_plugin();
290  if (remmina_secret_plugin == NULL) {
291  g_print(" but we can’t find the secret plugin inside the SNAP.\n");
292  need_snap_interface_connections = TRUE;
293  } else {
294  if (!remmina_secret_plugin->is_service_available(remmina_secret_plugin)) {
295  g_print(" but we can’t access a secret service. Secret service or SNAP interface connection is missing.\n");
296  need_snap_interface_connections = TRUE;
297  }
298  }
299 
300  if (need_snap_interface_connections && !remmina_pref.prevent_snap_welcome_message) {
301  dlgbuilder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_snap_info_dialog.glade");
302  dsa = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "dontshowagain"));
303  if (dlgbuilder) {
304  parent = remmina_main_get_window();
305  dlg = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "SnapInfoDlg"));
306  if (parent)
307  gtk_window_set_transient_for(GTK_WINDOW(dlg), parent);
308  gtk_builder_connect_signals(dlgbuilder, NULL);
309  result = gtk_dialog_run(GTK_DIALOG(dlg));
310  if (result == 1) {
311  remmina_pref.prevent_snap_welcome_message = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dsa));
313  }
314  gtk_widget_destroy(dlg);
315  g_object_unref(dlgbuilder);
316  }
317  }
318 }
319 #endif
320 
321 
322 static gboolean remmina_main_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path,
323  gboolean path_currently_selected, gpointer user_data)
324 {
325  TRACE_CALL(__func__);
326  guint context_id;
327  GtkTreeIter iter;
328  gchar buf[1000];
329 
330  if (path_currently_selected)
331  return TRUE;
332 
333  if (!gtk_tree_model_get_iter(model, &iter, path))
334  return TRUE;
335 
337 
338  gtk_tree_model_get(model, &iter,
339  NAME_COLUMN, &remminamain->priv->selected_name,
340  FILENAME_COLUMN, &remminamain->priv->selected_filename,
341  -1);
342 
343  context_id = gtk_statusbar_get_context_id(remminamain->statusbar_main, "status");
344  gtk_statusbar_pop(remminamain->statusbar_main, context_id);
345  if (remminamain->priv->selected_filename) {
346  g_snprintf(buf, sizeof(buf), "%s (%s)", remminamain->priv->selected_name, remminamain->priv->selected_filename);
347  gtk_statusbar_push(remminamain->statusbar_main, context_id, buf);
348  } else {
349  gtk_statusbar_push(remminamain->statusbar_main, context_id, remminamain->priv->selected_name);
350  }
351 
352  return TRUE;
353 }
354 
355 static void remmina_main_load_file_list_callback(RemminaFile *remminafile, gpointer user_data)
356 {
357  TRACE_CALL(__func__);
358  GtkTreeIter iter;
359  GtkListStore *store;
360 
361  store = GTK_LIST_STORE(user_data);
362  gchar *datetime;
363 
364  datetime = remmina_file_get_datetime(remminafile);
365  gtk_list_store_append(store, &iter);
366  gtk_list_store_set(store, &iter,
368  NAME_COLUMN, remmina_file_get_string(remminafile, "name"),
369  NOTES_COLUMN, g_uri_unescape_string(remmina_file_get_string(remminafile, "notes_text"), NULL),
370  GROUP_COLUMN, remmina_file_get_string(remminafile, "group"),
371  SERVER_COLUMN, remmina_file_get_string(remminafile, "server"),
372  PLUGIN_COLUMN, remmina_file_get_string(remminafile, "protocol"),
373  DATE_COLUMN, datetime,
375  LABELS_COLUMN, remmina_file_get_string(remminafile, "labels"),
376  -1);
377  g_free(datetime);
378 }
379 
380 static gboolean remmina_main_load_file_tree_traverse(GNode *node, GtkTreeStore *store, GtkTreeIter *parent)
381 {
382  TRACE_CALL(__func__);
383  GtkTreeIter *iter;
384  RemminaGroupData *data;
385  GNode *child;
386 
387  iter = NULL;
388  if (node->data) {
389  data = (RemminaGroupData *)node->data;
390  iter = g_new0(GtkTreeIter, 1);
391  gtk_tree_store_append(store, iter, parent);
392  gtk_tree_store_set(store, iter,
393  PROTOCOL_COLUMN, "folder-symbolic",
394  NAME_COLUMN, data->name,
395  GROUP_COLUMN, data->group,
396  DATE_COLUMN, data->datetime,
397  FILENAME_COLUMN, NULL,
398  LABELS_COLUMN, data->labels,
399  -1);
400  }
401  for (child = g_node_first_child(node); child; child = g_node_next_sibling(child))
402  remmina_main_load_file_tree_traverse(child, store, iter);
403  g_free(iter);
404  return FALSE;
405 }
406 
407 static void remmina_main_load_file_tree_group(GtkTreeStore *store)
408 {
409  TRACE_CALL(__func__);
410  GNode *root;
411 
413  remmina_main_load_file_tree_traverse(root, store, NULL);
415 }
416 
417 static void remmina_main_expand_group_traverse(GtkTreeIter *iter)
418 {
419  TRACE_CALL(__func__);
420  GtkTreeModel *tree;
421  gboolean ret;
422  gchar *group, *filename;
423  GtkTreeIter child;
424  GtkTreePath *path;
425 
426  tree = remminamain->priv->file_model_sort;
427  ret = TRUE;
428  while (ret) {
429  gtk_tree_model_get(tree, iter, GROUP_COLUMN, &group, FILENAME_COLUMN, &filename, -1);
430  if (filename == NULL) {
431  if (remmina_string_array_find(remminamain->priv->expanded_group, group) >= 0) {
432  path = gtk_tree_model_get_path(tree, iter);
433  gtk_tree_view_expand_row(remminamain->tree_files_list, path, FALSE);
434  gtk_tree_path_free(path);
435  }
436  if (gtk_tree_model_iter_children(tree, &child, iter))
438  }
439  g_free(group);
440  g_free(filename);
441 
442  ret = gtk_tree_model_iter_next(tree, iter);
443  }
444 }
445 
446 static void remmina_main_expand_group(void)
447 {
448  TRACE_CALL(__func__);
449  GtkTreeIter iter;
450 
451  if (gtk_tree_model_get_iter_first(remminamain->priv->file_model_sort, &iter))
453 }
454 
455 static gboolean remmina_main_load_file_tree_find(GtkTreeModel *tree, GtkTreeIter *iter, const gchar *match_group)
456 {
457  TRACE_CALL(__func__);
458  gboolean ret, match;
459  gchar *group, *filename;
460  GtkTreeIter child;
461 
462  match = FALSE;
463  ret = TRUE;
464  while (ret) {
465  gtk_tree_model_get(tree, iter, GROUP_COLUMN, &group, FILENAME_COLUMN, &filename, -1);
466  match = (filename == NULL && g_strcmp0(group, match_group) == 0);
467  g_free(group);
468  g_free(filename);
469  if (match)
470  break;
471  if (gtk_tree_model_iter_children(tree, &child, iter)) {
472  match = remmina_main_load_file_tree_find(tree, &child, match_group);
473  if (match) {
474  memcpy(iter, &child, sizeof(GtkTreeIter));
475  break;
476  }
477  }
478  ret = gtk_tree_model_iter_next(tree, iter);
479  }
480  return match;
481 }
482 
483 static void remmina_main_load_file_tree_callback(RemminaFile *remminafile, gpointer user_data)
484 {
485  TRACE_CALL(__func__);
486  GtkTreeIter iter, child;
487  GtkTreeStore *store;
488  gboolean found;
489  gchar *datetime = NULL;
490 
491  store = GTK_TREE_STORE(user_data);
492 
493  found = FALSE;
494  if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
495  found = remmina_main_load_file_tree_find(GTK_TREE_MODEL(store), &iter,
496  remmina_file_get_string(remminafile, "group"));
497 
498  datetime = remmina_file_get_datetime(remminafile);
499  //REMMINA_DEBUG("The date is %s", datetime);
500  gtk_tree_store_append(store, &child, (found ? &iter : NULL));
501  gtk_tree_store_set(store, &child,
503  NAME_COLUMN, remmina_file_get_string(remminafile, "name"),
504  NOTES_COLUMN, g_uri_unescape_string(remmina_file_get_string(remminafile, "notes_text"), NULL),
505  GROUP_COLUMN, remmina_file_get_string(remminafile, "group"),
506  SERVER_COLUMN, remmina_file_get_string(remminafile, "server"),
507  PLUGIN_COLUMN, remmina_file_get_string(remminafile, "protocol"),
508  DATE_COLUMN, datetime,
510  LABELS_COLUMN, remmina_file_get_string(remminafile, "labels"),
511  -1);
512  g_free(datetime);
513 }
514 
515 static void remmina_main_file_model_on_sort(GtkTreeSortable *sortable, gpointer user_data)
516 {
517  TRACE_CALL(__func__);
518  gint columnid;
519  GtkSortType order;
520 
521  gtk_tree_sortable_get_sort_column_id(sortable, &columnid, &order);
525 }
526 
527 static gboolean remmina_main_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
528 {
529  TRACE_CALL(__func__);
530  gchar *text;
531  gchar *protocol, *name, *labels, *group, *server, *plugin, *date, *s;
532  gboolean result = TRUE;
533 
534  text = g_ascii_strdown(gtk_entry_get_text(remminamain->entry_quick_connect_server), -1);
535  if (text && text[0]) {
536  gtk_tree_model_get(model, iter,
537  PROTOCOL_COLUMN, &protocol,
538  NAME_COLUMN, &name,
539  GROUP_COLUMN, &group,
540  SERVER_COLUMN, &server,
541  PLUGIN_COLUMN, &plugin,
542  DATE_COLUMN, &date,
543  LABELS_COLUMN, &labels,
544  -1);
545  if (g_strcmp0(protocol, "folder-symbolic") != 0) {
546  s = g_ascii_strdown(name ? name : "", -1);
547  g_free(name);
548  name = s;
549  s = g_ascii_strdown(group ? group : "", -1);
550  g_free(group);
551  group = s;
552  s = g_ascii_strdown(server ? server : "", -1);
553  g_free(server);
554  server = s;
555  s = g_ascii_strdown(plugin ? plugin : "", -1);
556  g_free(plugin);
557  plugin = s;
558  s = g_ascii_strdown(date ? date : "", -1);
559  g_free(date);
560  date = s;
561  result = (strstr(name, text) || strstr(group, text) || strstr(server, text) || strstr(plugin, text) || strstr(date, text));
562 
563  // Filter by labels
564 
565  s = g_ascii_strdown(labels ? labels : "", -1);
566  g_free(labels);
567  labels = s;
568 
569  if (strlen(labels) > 0) {
570  gboolean labels_result = TRUE;
571  gchar **labels_array = g_strsplit(labels, ",", -1);
572  gchar **text_array = g_strsplit(text, ",", -1);
573 
574  for (int t = 0; (NULL != text_array[t]); t++) {
575  if (0 == strlen(text_array[t])) {
576  continue;
577  }
578 
579  gboolean text_result = FALSE;
580 
581  for (int l = 0; (NULL != labels_array[l]); l++) {
582  if (0 == strlen(labels_array[l])) {
583  continue;
584  }
585 
586  text_result = (text_result || strstr(labels_array[l], text_array[t]));
587 
588  if (text_result) {
589  break;
590  }
591  }
592 
593  labels_result = (labels_result && text_result);
594 
595  if (!labels_result) {
596  break;
597  }
598  }
599 
600  result = (result || labels_result);
601 
602  g_strfreev(labels_array);
603  g_strfreev(text_array);
604  }
605  }
606  g_free(protocol);
607  g_free(name);
608  g_free(labels);
609  g_free(group);
610  g_free(server);
611  g_free(plugin);
612  g_free(date);
613  }
614  g_free(text);
615  return result;
616 }
617 
618 static void remmina_main_select_file(const gchar *filename)
619 {
620  TRACE_CALL(__func__);
621  GtkTreeIter iter;
622  GtkTreePath *path;
623  gchar *item_filename;
624  gboolean cmp;
625 
626  if (!gtk_tree_model_get_iter_first(remminamain->priv->file_model_sort, &iter))
627  return;
628 
629  while (TRUE) {
630  gtk_tree_model_get(remminamain->priv->file_model_sort, &iter, FILENAME_COLUMN, &item_filename, -1);
631  cmp = g_strcmp0(item_filename, filename);
632  g_free(item_filename);
633  if (cmp == 0) {
634  gtk_tree_selection_select_iter(gtk_tree_view_get_selection(remminamain->tree_files_list),
635  &iter);
636  path = gtk_tree_model_get_path(remminamain->priv->file_model_sort, &iter);
637  gtk_tree_view_scroll_to_cell(remminamain->tree_files_list, path, NULL, TRUE, 0.5, 0.0);
638  gtk_tree_path_free(path);
639  return;
640  }
641  if (!gtk_tree_model_iter_next(remminamain->priv->file_model_sort, &iter))
642  return;
643  }
644 }
645 
647 {
648  TRACE_CALL(__func__);
649  gint items_count;
650  gchar buf[200];
651  guint context_id;
652  gint view_file_mode;
653  gboolean always_show_notes;
654  char *save_selected_filename;
655  GtkTreeModel *newmodel;
656  const gchar *neticon;
657  const gchar *connection_tooltip;
658 
659  save_selected_filename = g_strdup(remminamain->priv->selected_filename);
661 
662  view_file_mode = remmina_pref.view_file_mode;
663  if (remminamain->priv->override_view_file_mode_to_list)
664  view_file_mode = REMMINA_VIEW_FILE_LIST;
665 
666  switch (remmina_pref.view_file_mode) {
668  gtk_toggle_button_set_active(remminamain->view_toggle_button, FALSE);
669  break;
671  default:
672  gtk_toggle_button_set_active(remminamain->view_toggle_button, TRUE);
673  break;
674  }
675 
676  switch (view_file_mode) {
678  /* Create new GtkTreeStore model */
679  newmodel = GTK_TREE_MODEL(gtk_tree_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
680  /* Hide the Group column in the tree view mode */
681  gtk_tree_view_column_set_visible(remminamain->column_files_list_group, FALSE);
682  /* Load groups first */
683  remmina_main_load_file_tree_group(GTK_TREE_STORE(newmodel));
684  /* Load files list */
685  items_count = remmina_file_manager_iterate((GFunc)remmina_main_load_file_tree_callback, (gpointer)newmodel);
686  break;
687 
689  default:
690  /* Create new GtkListStore model */
691  newmodel = GTK_TREE_MODEL(gtk_list_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
692  /* Show the Group column in the list view mode */
693  gtk_tree_view_column_set_visible(remminamain->column_files_list_group, TRUE);
694  /* Load files list */
695  items_count = remmina_file_manager_iterate((GFunc)remmina_main_load_file_list_callback, (gpointer)newmodel);
696  break;
697  }
698 
699  /* Set note column visibility*/
700  always_show_notes = remmina_pref.always_show_notes;
701  if (!always_show_notes){
702  gtk_tree_view_column_set_visible(remminamain->column_files_list_notes, FALSE);
703  }
704 
705  /* Unset old model */
706  gtk_tree_view_set_model(remminamain->tree_files_list, NULL);
707 
708  /* Destroy the old model and save the new one */
709  remminamain->priv->file_model = newmodel;
710 
711  /* Create a sorted filtered model based on newmodel and apply it to the TreeView */
712  remminamain->priv->file_model_filter = gtk_tree_model_filter_new(remminamain->priv->file_model, NULL);
713  gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(remminamain->priv->file_model_filter),
714  (GtkTreeModelFilterVisibleFunc)remmina_main_filter_visible_func, NULL, NULL);
715  remminamain->priv->file_model_sort = gtk_tree_model_sort_new_with_model(remminamain->priv->file_model_filter);
716  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(remminamain->priv->file_model_sort),
719  gtk_tree_view_set_model(remminamain->tree_files_list, remminamain->priv->file_model_sort);
720  g_signal_connect(G_OBJECT(remminamain->priv->file_model_sort), "sort-column-changed",
721  G_CALLBACK(remmina_main_file_model_on_sort), NULL);
723  /* Select the file previously selected */
724  if (save_selected_filename) {
725  remmina_main_select_file(save_selected_filename);
726  g_free(save_selected_filename);
727  }
728  gtk_tree_view_column_set_widget(remminamain->column_files_list_date, NULL);
729 
730  GtkWidget *label = gtk_tree_view_column_get_button(remminamain->column_files_list_date);
731 
732  gtk_widget_set_tooltip_text(GTK_WIDGET(label),
733  _("The latest successful connection attempt, or a pre-computed date"));
734  /* Show in the status bar the total number of connections found */
735  g_snprintf(buf, sizeof(buf), ngettext("Total %i item.", "Total %i items.", items_count), items_count);
736  context_id = gtk_statusbar_get_context_id(remminamain->statusbar_main, "status");
737  gtk_statusbar_pop(remminamain->statusbar_main, context_id);
738  gtk_statusbar_push(remminamain->statusbar_main, context_id, buf);
739 
741  if (remminamain->monitor->connected){
742  neticon = g_strdup("network-transmit-receive-symbolic");
743  connection_tooltip = g_strdup(_("Network status: fully online"));
744  } else {
745  neticon = g_strdup("network-offline-symbolic");
746  connection_tooltip = g_strdup(_("Network status: offline"));
747  }
748 
749  if (GTK_IS_WIDGET(remminamain->network_icon))
750  gtk_widget_destroy(remminamain->network_icon);
751  GIcon *icon = g_themed_icon_new (neticon);
752  remminamain->network_icon = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
753  gtk_widget_set_tooltip_text (remminamain->network_icon, connection_tooltip);
754 
755  g_object_unref (icon);
756 
757  gtk_box_pack_start (GTK_BOX(remminamain->statusbar_main), remminamain->network_icon, FALSE, FALSE, 0);
758  gtk_widget_show (remminamain->network_icon);
759 
760 }
761 
762 void remmina_main_load_files_cb(GtkEntry *entry, char *string, gpointer user_data)
763 {
764  TRACE_CALL(__func__);
766 }
767 
768 void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data)
769 {
770  TRACE_CALL(__func__);
771 
772  RemminaFile *remminafile;
773 
774  if (!remminamain->priv->selected_filename)
775  return;
776 
777  remminafile = remmina_file_load(remminamain->priv->selected_filename);
778 
779  if (remminafile == NULL)
780  return;
781 
782  if (remmina_pref_get_boolean("use_primary_password")
783  && remmina_pref_get_boolean("lock_connect")
784  && remmina_unlock_new(remminamain->window) == 0)
785  return;
786  if (remmina_file_get_int (remminafile, "profile-lock", FALSE) == 1
787  && remmina_unlock_new(remminamain->window) == 0)
788  return;
789 
790  remmina_file_touch(remminafile);
792 
793  remmina_file_free(remminafile);
794 }
795 
796 void remmina_main_on_action_connection_external_tools(GSimpleAction *action, GVariant *param, gpointer data)
797 {
798  TRACE_CALL(__func__);
799  if (!remminamain->priv->selected_filename)
800  return;
801 
802  remmina_external_tools_from_filename(remminamain, remminamain->priv->selected_filename);
803 }
804 
805 static void remmina_main_file_editor_destroy(GtkWidget *widget, gpointer user_data)
806 {
807  TRACE_CALL(__func__);
808 
809  if (!remminamain)
810  return;
812 }
813 
814 void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data)
815 {
816  TRACE_CALL(__func__);
817  RemminaFile *remminafile;
818 
819  const gchar *username;
820  const gchar *domain;
821  const gchar *group;
822  const gchar *gatewayusername;
823  const gchar *gatewaydomain;
824 
825  username = domain = group = gatewayusername = gatewaydomain = "";
826 
827  remminafile = NULL;
828 
829  if (remmina_pref_get_boolean("use_primary_password")
830  && remmina_pref_get_boolean("lock_edit")
831  && remmina_unlock_new(remminamain->window) == 0)
832  return;
833 
834  if (remminamain->priv->selected_filename) {
835  remminafile = remmina_file_load(remminamain->priv->selected_filename);
836  if (remminafile != NULL) {
837  username = remmina_file_get_string(remminafile, "username");
838  domain = remmina_file_get_string(remminafile, "domain");
839  group = remmina_file_get_string(remminafile, "group");
840  gatewayusername = remmina_file_get_string(remminafile, "gateway_username");
841  gatewaydomain = remmina_file_get_string(remminafile, "gateway_domain");
842  }
843  }
844 
845  remmina_mpchange_schedule(TRUE, group, domain, username, "", gatewayusername, gatewaydomain, "");
846 
847  if (remminafile != NULL)
848  remmina_file_free(remminafile);
849 }
850 
851 void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data)
852 {
853  TRACE_CALL(__func__);
854  if (kioskmode && kioskmode == TRUE)
855  return;
856  GtkWidget *widget;
857 
858  if (remmina_pref_get_boolean("use_primary_password")
859  && remmina_pref_get_boolean("lock_edit")
860  && remmina_unlock_new(remminamain->window) == 0)
861  return;
862 
863  widget = remmina_file_editor_new();
864  g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(remmina_main_file_editor_destroy), remminamain);
865  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
866  gtk_widget_show(widget);
868 }
869 
870 static gboolean remmina_main_search_key_event(GtkWidget *search_entry, GdkEventKey *event, gpointer user_data)
871 {
872  TRACE_CALL(__func__);
873  if (event->keyval == GDK_KEY_Escape) {
874  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
875  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle")), FALSE);
876  return TRUE;
877  }
878  return FALSE;
879 }
880 
881 static gboolean remmina_main_tree_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
882 {
883  TRACE_CALL(__func__);
884  if (gtk_tree_view_row_expanded(tree, path))
885  gtk_tree_view_collapse_row(tree, path);
886  else
887  gtk_tree_view_expand_row(tree, path, FALSE);
888  return TRUE;
889 }
890 
892 {
893  if (gtk_toggle_button_get_active(remminamain->view_toggle_button)) {
896  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
899  }
900  } else {
903  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
906  }
907  }
908 }
909 
910 void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data)
911 {
912  TRACE_CALL(__func__);
913  GtkWidget *widget;
914 
915  if (remmina_pref_get_boolean("use_primary_password")
916  && remmina_unlock_new(remminamain->window) == 0)
917  return;
918 
919  if (!remminamain->priv->selected_filename)
920  return;
921 
922  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
923 
924  if (((remmina_pref_get_boolean("lock_edit")
925  && remmina_pref_get_boolean("use_primary_password"))
926  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
927  && remmina_unlock_new(remminamain->window) == 0)
928  return;
929 
930  if (remminafile) {
931  remmina_file_free(remminafile);
932  remminafile = NULL;
933  }
934 
935  widget = remmina_file_editor_new_copy(remminamain->priv->selected_filename);
936  if (widget) {
937  g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(remmina_main_file_editor_destroy), remminamain);
938  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
939  gtk_widget_show(widget);
940  }
941  /* Select the file previously selected */
942  if (remminamain->priv->selected_filename)
944 }
945 
946 void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data)
947 {
948  TRACE_CALL(__func__);
949  GtkWidget *widget;
950 
951  if (!remminamain->priv->selected_filename)
952  return;
953 
954  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
955 
956  if (remmina_pref_get_boolean("use_primary_password")
957  && (remmina_pref_get_boolean("lock_edit")
958  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
959  && remmina_unlock_new(remminamain->window) == 0)
960  return;
961 
962  if (remminafile) {
963  remmina_file_free(remminafile);
964  remminafile = NULL;
965  }
966 
968  if (widget) {
969  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
970  gtk_widget_show(widget);
971  }
972 /* Select the file previously selected */
973  if (remminamain->priv->selected_filename)
975 }
976 
977 void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data)
978 {
979  TRACE_CALL(__func__);
980  GtkWidget *dialog;
981 
982  if (!remminamain->priv->selected_filename)
983  return;
984 
985  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
986 
987  if (((remmina_pref_get_boolean("lock_edit")
988  && remmina_pref_get_boolean("use_primary_password"))
989  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
990  && remmina_unlock_new(remminamain->window) == 0)
991  return;
992 
993  if (remminafile) {
994  remmina_file_free(remminafile);
995  remminafile = NULL;
996  }
997 
998  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
999  _("Are you sure you want to delete “%s”?"), remminamain->priv->selected_name);
1000  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1001  gchar *delfilename = g_strdup(remminamain->priv->selected_filename);
1002  remmina_file_delete(delfilename);
1003  g_free(delfilename), delfilename = NULL;
1006  }
1007  gtk_widget_destroy(dialog);
1009 }
1010 
1011 void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data)
1012 {
1013  TRACE_CALL(__func__);
1014  GtkWidget *dialog;
1015  GtkTreeSelection *sel = gtk_tree_view_get_selection(remminamain->tree_files_list);
1016  GtkTreeModel *model = gtk_tree_view_get_model(remminamain->tree_files_list);
1017  GList *list = gtk_tree_selection_get_selected_rows(sel, &model);
1018  gchar *file_to_delete;
1019 
1020  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1021  _("Are you sure you want to delete the selected files?"));
1022 
1023  // Delete files if Yes is clicked
1024  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1025  while (list) {
1026  GtkTreePath *path = list->data;
1027  GtkTreeIter iter;
1028 
1029  if (!gtk_tree_model_get_iter(model, &iter, path)) {
1030  GtkWidget *dialog_warning;
1031  dialog_warning = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1032  _("Failed to delete files!"));
1033  gtk_dialog_run(GTK_DIALOG(dialog_warning));
1034  gtk_widget_destroy(dialog_warning);
1035  gtk_widget_destroy(dialog);
1037  return;
1038  }
1039 
1040  gtk_tree_model_get(model, &iter,
1041  FILENAME_COLUMN, &file_to_delete, -1);
1042 
1043  RemminaFile *remminafile = remmina_file_load(file_to_delete);
1044 
1045  if (((remmina_pref_get_boolean("lock_edit")
1046  && remmina_pref_get_boolean("use_primary_password"))
1047  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
1048  && remmina_unlock_new(remminamain->window) == 0)
1049  return;
1050 
1051  if (remminafile) {
1052  remmina_file_free(remminafile);
1053  remminafile = NULL;
1054  }
1055 
1056  gchar *delfilename = g_strdup(file_to_delete);
1057  remmina_file_delete(delfilename);
1058  g_free(delfilename), delfilename = NULL;
1061  list = g_list_next(list);
1062  }
1063  }
1064 
1065  gtk_widget_destroy(dialog);
1067 }
1068 
1069 void remmina_main_on_accel_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
1070 {
1071  TRACE_CALL(__func__);
1072  GVariant *v = g_variant_new("i", 0);
1073 
1075 }
1076 
1078 {
1079  GtkSettings *settings;
1080  settings = gtk_settings_get_default();
1081  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1082  remmina_main_on_action_search_toggle(NULL,NULL,NULL);
1083  gtk_tree_view_column_set_visible(remminamain->column_files_list_notes, remmina_pref.always_show_notes);
1084 }
1085 
1086 void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
1087 {
1088  TRACE_CALL(__func__);
1089 
1090  REMMINA_DEBUG("Opening the preferences");
1091  gint32 tab_num;
1092 
1093  if (param) {
1094  REMMINA_DEBUG("Parameter passed to preferences of type %s", g_variant_get_type_string(param));
1095  tab_num = g_variant_get_int32(param);
1096  REMMINA_DEBUG("We got a parameter for the preferences: %d", tab_num);
1097  } else {
1098  tab_num = 0;
1099  }
1100 
1101  if (remmina_pref_get_boolean("use_primary_password")
1102  && remmina_unlock_new(remminamain->window) == 0)
1103  return;
1104 
1105  GtkWidget *widget = remmina_pref_dialog_new(tab_num, remminamain->window);
1106 
1107  gtk_widget_show_all(widget);
1108  /* Reload to use new preferences */
1110 }
1111 
1112 void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
1113 {
1114  TRACE_CALL(__func__);
1115 #ifndef __APPLE__
1116  g_autoptr(GError) error = NULL;
1117  GDesktopAppInfo *desktop_info;
1118  GAppInfo *info = NULL;
1119  g_autofree gchar *id = g_strconcat(REMMINA_APP_ID, ".desktop", NULL);
1120  int i;
1121 
1122  desktop_info = g_desktop_app_info_new(id);
1123  if (!desktop_info)
1124  return;
1125 
1126  info = G_APP_INFO(desktop_info);
1127 
1128  for (i = 0; supported_mime_types[i]; i++) {
1129  if (!g_app_info_set_as_default_for_type(info, supported_mime_types[i], &error))
1130  g_warning("Failed to set '%s' as the default application for secondary content type '%s': %s",
1131  g_app_info_get_name(info), supported_mime_types[i], error->message);
1132  else
1133  g_debug("Set '%s' as the default application for '%s'",
1134  g_app_info_get_name(info),
1136  }
1137 #endif
1138 }
1139 
1140 void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
1141 {
1142  // Called by quit signal in remmina_main.glade
1143  TRACE_CALL(__func__);
1144  g_debug("Quit intercept");
1146 }
1147 
1149 {
1152  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
1155  }
1156 }
1157 
1158 static void remmina_main_import_file_list(GSList *files)
1159 {
1160  TRACE_CALL(__func__);
1161  GtkWidget *dlg;
1162  GSList *element;
1163  gchar *path;
1164  RemminaFilePlugin *plugin;
1165  GString *err;
1166  RemminaFile *remminafile = NULL;
1167  gboolean imported;
1168 
1169  err = g_string_new(NULL);
1170  imported = FALSE;
1171  for (element = files; element; element = element->next) {
1172  path = (gchar *)element->data;
1174  if (plugin && (remminafile = plugin->import_func(plugin, path)) != NULL && remmina_file_get_string(remminafile, "name")) {
1175  remmina_file_generate_filename(remminafile);
1176  remmina_file_save(remminafile);
1177  imported = TRUE;
1178  } else {
1179  g_string_append(err, path);
1180  g_string_append_c(err, '\n');
1181  }
1182  if (remminafile) {
1183  remmina_file_free(remminafile);
1184  remminafile = NULL;
1185  }
1186  g_free(path);
1187  }
1188  g_slist_free(files);
1189  if (err->len > 0) {
1190  // TRANSLATORS: The placeholder %s is an error message
1191  dlg = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1192  _("Unable to import:\n%s"), err->str);
1193  g_signal_connect(G_OBJECT(dlg), "response", G_CALLBACK(gtk_widget_destroy), NULL);
1194  gtk_widget_show(dlg);
1195  }
1196  g_string_free(err, TRUE);
1197  if (imported)
1199 }
1200 
1201 static void remmina_main_action_tools_import_on_response(GtkDialog *dialog, gint response_id, gpointer user_data)
1202 {
1203  TRACE_CALL(__func__);
1204  GSList *files;
1205 
1206  if (response_id == GTK_RESPONSE_ACCEPT) {
1207  files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
1209  }
1210  gtk_widget_destroy(GTK_WIDGET(dialog));
1211 }
1212 
1213 void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
1214 {
1215  TRACE_CALL(__func__);
1216  GtkWidget *dialog;
1217 
1218  dialog = gtk_file_chooser_dialog_new(_("Import"), remminamain->window, GTK_FILE_CHOOSER_ACTION_OPEN, "Import",
1219  GTK_RESPONSE_ACCEPT, NULL);
1220  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1221  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(remmina_main_action_tools_import_on_response), NULL);
1222  gtk_widget_show(dialog);
1223 }
1224 
1225 void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
1226 {
1227  TRACE_CALL(__func__);
1228  RemminaFilePlugin *plugin;
1229  RemminaFile *remminafile;
1230  GtkWidget *dialog;
1231 
1232  if (!remminamain->priv->selected_filename)
1233  return;
1234 
1235  remminafile = remmina_file_load(remminamain->priv->selected_filename);
1236  if (remminafile == NULL)
1237  return;
1238  plugin = remmina_plugin_manager_get_export_file_handler(remminafile);
1239  if (plugin) {
1240  dialog = gtk_file_chooser_dialog_new(plugin->export_hints, remminamain->window,
1241  GTK_FILE_CHOOSER_ACTION_SAVE, _("_Save"), GTK_RESPONSE_ACCEPT, NULL);
1242  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1243  plugin->export_func(plugin, remminafile, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
1244  gtk_widget_destroy(dialog);
1245  } else {
1246  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1247  _("This protocol does not support exporting."));
1248  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
1249  gtk_widget_show(dialog);
1250  }
1251  remmina_file_free(remminafile);
1252 }
1253 
1254 void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
1255 {
1256  TRACE_CALL(__func__);
1257  remmina_plugin_manager_show(remminamain->window);
1258 }
1259 
1260 void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
1261 {
1262  TRACE_CALL(__func__);
1263  GtkSettings *settings;
1264 
1265  settings = gtk_settings_get_default();
1266 
1267  if (gtk_switch_get_active(remminamain->switch_dark_mode))
1269  else
1272 
1273  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1274 }
1275 
1276 void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
1277 {
1278  TRACE_CALL(__func__);
1279  g_app_info_launch_default_for_uri("https://www.remmina.org", NULL, NULL);
1280 }
1281 
1282 void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
1283 {
1284  TRACE_CALL(__func__);
1285  g_app_info_launch_default_for_uri("https://gitlab.com/Remmina/Remmina/wikis/home", NULL, NULL);
1286 }
1287 
1288 void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
1289 {
1290  TRACE_CALL(__func__);
1291  g_app_info_launch_default_for_uri("https://remmina.org/community", NULL, NULL);
1292 }
1293 
1294 void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
1295 {
1296  TRACE_CALL(__func__);
1297  g_app_info_launch_default_for_uri("https://www.remmina.org/donations", NULL, NULL);
1298 }
1299 
1300 void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
1301 {
1302  TRACE_CALL(__func__);
1304 }
1305 
1306 void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
1307 {
1308  TRACE_CALL(__func__);
1309  remmina_about_open(remminamain->window);
1310 };
1311 
1312 static gboolean is_empty(const gchar *s)
1313 {
1314  if (s == NULL)
1315  return TRUE;
1316  while (*s != 0) {
1317  if (!isspace((unsigned char)*s))
1318  return FALSE;
1319  s++;
1320  }
1321  return TRUE;
1322 }
1323 
1324 static gboolean remmina_main_quickconnect(void)
1325 {
1326  TRACE_CALL(__func__);
1327  RemminaFile *remminafile;
1328  gchar *server;
1329  gchar *server_trimmed;
1330  gchar *qcp;
1331 
1332 
1333  /* Save quick connect protocol if different from the previous one */
1334  qcp = gtk_combo_box_text_get_active_text(remminamain->combo_quick_connect_protocol);
1335  if (qcp && strcmp(qcp, remmina_pref.last_quickconnect_protocol) != 0) {
1337  remmina_pref.last_quickconnect_protocol = g_strdup(qcp);
1339  }
1340 
1341  remminafile = remmina_file_new();
1342  server = g_strdup(gtk_entry_get_text(remminamain->entry_quick_connect_server));
1343  if (g_hostname_to_ascii(server) == NULL)
1344  return FALSE;
1345  /* If server contain /, e.g. vnc://, it won't connect
1346  * We could search for an array of invalid characters, but
1347  * it's better to find a way to correctly parse and validate addresses
1348  */
1349  if (g_strrstr(server, "/") != NULL)
1350  return FALSE;
1351  //if (g_str_has_suffix (server, "/"))
1352  //return FALSE;
1353  if (is_empty(server))
1354  return FALSE;
1355 
1356  /* check if server is an IP address and trim whitespace if so */
1357  server_trimmed = g_strdup(server);
1358  g_strstrip(server_trimmed);
1359  gchar **strings = g_strsplit(server_trimmed, ":", 2);
1360 
1361  if (strings[0] != NULL)
1362  if (g_hostname_is_ip_address(strings[0]))
1363  g_stpcpy(server, server_trimmed);
1364 
1365  remmina_file_set_string(remminafile, "sound", "off");
1366  remmina_file_set_string(remminafile, "server", server);
1367  remmina_file_set_string(remminafile, "name", server);
1368  remmina_file_set_string(remminafile, "protocol", qcp);
1369  g_free(server);
1370  g_free(server_trimmed);
1371  g_free(qcp);
1372 
1373  rcw_open_from_file(remminafile);
1374 
1375  return FALSE;
1376 }
1377 
1378 gboolean remmina_main_quickconnect_on_click(GtkWidget *widget, gpointer user_data)
1379 {
1380  TRACE_CALL(__func__);
1381  if (!kioskmode && kioskmode == FALSE)
1382  return remmina_main_quickconnect();
1383  return FALSE;
1384 }
1385 
1386 /* Select all the text inside the quick search box if there is anything */
1387 void remmina_main_quick_search_enter(GtkWidget *widget, gpointer user_data)
1388 {
1389  if (gtk_entry_get_text(remminamain->entry_quick_connect_server))
1390  gtk_editable_select_region(GTK_EDITABLE(remminamain->entry_quick_connect_server), 0, -1);
1391 }
1392 
1393 void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
1394 {
1395  TRACE_CALL(__func__);
1396  gtk_tree_view_collapse_all(remminamain->tree_files_list);
1397 }
1398 
1399 void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
1400 {
1401  TRACE_CALL(__func__);
1402  REMMINA_DEBUG("Search toggle triggered");
1403  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remminamain->search_toggle), !remmina_pref.hide_searchbar);
1404 
1405  gboolean toggle_status = gtk_toggle_button_get_active(remminamain->search_toggle);
1406 
1407  gtk_search_bar_set_search_mode(remminamain->search_bar, toggle_status);
1408  if (toggle_status) {
1409  REMMINA_DEBUG("Search toggle is active");
1410  gtk_widget_grab_focus(GTK_WIDGET(remminamain->entry_quick_connect_server));
1411  } else {
1412  REMMINA_DEBUG("Search toggle is not active, focus is tree_files_list");
1413  gtk_widget_grab_focus(GTK_WIDGET(remminamain->tree_files_list));
1414  }
1415 }
1416 
1418 {
1419  TRACE_CALL(__func__);
1420  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remminamain->search_toggle), TRUE);
1421 }
1422 
1423 void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
1424 {
1425  TRACE_CALL(__func__);
1426  gtk_tree_view_expand_all(remminamain->tree_files_list);
1427 }
1428 
1429 /* Handle double click on a row in the connections list */
1430 void remmina_main_file_list_on_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
1431 {
1432  TRACE_CALL(__func__);
1433 /* If a connection was selected then execute the default action */
1434  if (remminamain->priv->selected_filename) {
1435  switch (remmina_pref.default_action) {
1436  case REMMINA_ACTION_EDIT:
1437  remmina_main_on_action_connection_edit(NULL, NULL, NULL);
1438  break;
1440  default:
1442  break;
1443  }
1444  }
1445 }
1446 
1447 /* Show the popup menu by the right button mouse click */
1448 gboolean remmina_main_file_list_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1449 {
1450  TRACE_CALL(__func__);
1451  if (event->button == MOUSE_BUTTON_RIGHT) {
1452  if (!kioskmode && kioskmode == FALSE) {
1453 #if GTK_CHECK_VERSION(3, 22, 0)
1454  // For now, if more than one selected row, display only a delete menu option
1455  if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(remminamain->tree_files_list)) > 1) {
1456  gtk_menu_popup_at_pointer(GTK_MENU(remminamain->menu_popup_delete_rc), (GdkEvent *)event);
1457  return GDK_EVENT_STOP;
1458  }
1459  else {
1460  gtk_menu_popup_at_pointer(GTK_MENU(remminamain->menu_popup), (GdkEvent *)event);
1461  }
1462 #else
1463  gtk_menu_popup(remminamain->menu_popup, NULL, NULL, NULL, NULL, event->button, event->time);
1464 #endif
1465  }
1466  }
1467  return FALSE;
1468 }
1469 
1470 /* Show the popup menu by the menu key */
1471 gboolean remmina_main_file_list_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1472 {
1473  TRACE_CALL(__func__);
1474  if (event->keyval == GDK_KEY_Menu) {
1475 #if GTK_CHECK_VERSION(3, 22, 0)
1476  gtk_menu_popup_at_widget(GTK_MENU(remminamain->menu_popup), widget,
1477  GDK_GRAVITY_CENTER, GDK_GRAVITY_CENTER,
1478  (GdkEvent *)event);
1479 #else
1480  gtk_menu_popup(remminamain->menu_popup, NULL, NULL, NULL, NULL, 0, event->time);
1481 #endif
1482  }
1483  return FALSE;
1484 }
1485 
1486 void remmina_main_quick_search_on_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
1487 {
1488  TRACE_CALL(__func__);
1489  if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
1490  gtk_entry_set_text(entry, "");
1491 }
1492 
1493 void remmina_main_quick_search_on_changed(GtkEditable *editable, gpointer user_data)
1494 {
1495  TRACE_CALL(__func__);
1496  /* If a search text was input then temporary set the file mode to list */
1497  if (gtk_entry_get_text_length(remminamain->entry_quick_connect_server)) {
1498  if (GTK_IS_TREE_STORE(remminamain->priv->file_model)) {
1499  /* File view mode changed, put it to override and reload list */
1500  remminamain->priv->override_view_file_mode_to_list = TRUE;
1502  }
1503  } else {
1504  if (remminamain->priv->override_view_file_mode_to_list) {
1505  /* File view mode changed, put it to default (disable override) and reload list */
1506  remminamain->priv->override_view_file_mode_to_list = FALSE;
1508  }
1509  }
1510  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(remminamain->priv->file_model_filter));
1511 }
1512 
1513 void remmina_main_on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y,
1514  GtkSelectionData *data, guint info, guint time, gpointer user_data)
1515 {
1516  TRACE_CALL(__func__);
1517  gchar **uris;
1518  GSList *files = NULL;
1519  gint i;
1520 
1521  uris = g_uri_list_extract_uris((const gchar *)gtk_selection_data_get_data(data));
1522  for (i = 0; uris[i]; i++) {
1523  if (strncmp(uris[i], "file://", 7) != 0)
1524  continue;
1525  files = g_slist_append(files, g_strdup(uris[i] + 7));
1526  }
1527  g_strfreev(uris);
1529 }
1530 
1531 /* Add a new menuitem to the Tools menu */
1532 static gboolean remmina_main_add_tool_plugin(gchar *name, RemminaPlugin *plugin, gpointer user_data)
1533 {
1534  TRACE_CALL(__func__);
1535  RemminaToolPlugin *tool_plugin = (RemminaToolPlugin *)plugin;
1536  GtkWidget *menuitem = gtk_menu_item_new_with_label(plugin->description);
1537 
1538  gtk_widget_show(menuitem);
1539  gtk_menu_shell_append(GTK_MENU_SHELL(remminamain->menu_popup_full), menuitem);
1540  g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(tool_plugin->exec_func), tool_plugin);
1541  return FALSE;
1542 }
1543 
1544 gboolean remmina_main_on_window_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
1545 {
1546  TRACE_CALL(__func__);
1547  return FALSE;
1548 }
1549 
1550 /* Remmina main window initialization */
1551 static void remmina_main_init(void)
1552 {
1553  TRACE_CALL(__func__);
1554  int i, qcp_idx, qcp_actidx;
1555  char *name;
1556  GtkSettings *settings;
1557 
1558  REMMINA_DEBUG("Initializing the Remmina main window");
1559  /* Switch to a dark theme if the user enabled it */
1560  settings = gtk_settings_get_default();
1561  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1562 
1563  REMMINA_DEBUG ("Initializing monitor");
1564  remminamain->monitor = remmina_network_monitor_new();
1565 
1567  if (!kioskmode && kioskmode == FALSE)
1568  gtk_window_set_title(remminamain->window, _("Remmina Remote Desktop Client"));
1569  else
1570  gtk_window_set_title(remminamain->window, _("Remmina Kiosk"));
1571  if (!kioskmode && kioskmode == FALSE) {
1572  gtk_window_set_default_size(remminamain->window, remmina_pref.main_width, remmina_pref.main_height);
1574  gtk_window_maximize(remminamain->window);
1575  }
1576  /* Honor global preferences Search Bar visibility */
1578  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle")), FALSE);
1579 
1580  /* Add a GtkMenuItem to the Tools menu for each plugin of type REMMINA_PLUGIN_TYPE_TOOL */
1582 
1583  /* Add available quick connect protocols to remminamain->combo_quick_connect_protocol */
1584  qcp_idx = qcp_actidx = 0;
1585  for (i = 0; i < sizeof(quick_connect_plugin_list) / sizeof(quick_connect_plugin_list[0]); i++) {
1586  name = quick_connect_plugin_list[i];
1588  gtk_combo_box_text_append(remminamain->combo_quick_connect_protocol, name, name);
1590  qcp_actidx = qcp_idx;
1591  qcp_idx++;
1592  }
1593  }
1594  gtk_combo_box_set_active(GTK_COMBO_BOX(remminamain->combo_quick_connect_protocol), qcp_actidx);
1595 
1596  /* Connect the group accelerators to the GtkWindow */
1597  //gtk_window_add_accel_group(remminamain->window, remminamain->accelgroup_shortcuts);
1598  /* Set the Quick Connection */
1599  gtk_entry_set_activates_default(remminamain->entry_quick_connect_server, TRUE);
1600  /* Set the TreeView for the files list */
1601  gtk_tree_selection_set_select_function(
1602  gtk_tree_view_get_selection(remminamain->tree_files_list),
1603  remmina_main_selection_func, NULL, NULL);
1605  gtk_tree_view_set_search_entry(remminamain->tree_files_list, GTK_ENTRY(remminamain->entry_quick_connect_server));
1607  gtk_widget_grab_focus(GTK_WIDGET(remminamain->tree_files_list));
1608  /* Load the files list */
1610 
1611  /* Drag-n-drop support */
1612  gtk_drag_dest_set(GTK_WIDGET(remminamain->window), GTK_DEST_DEFAULT_ALL, remmina_drop_types, 1, GDK_ACTION_COPY);
1613 
1614  /* Finish initialization */
1615  remminamain->priv->initialized = TRUE;
1616 
1617  /* Register the window in remmina_widget_pool with GType=GTK_WINDOW and TAG=remmina-main-window */
1618  g_object_set_data(G_OBJECT(remminamain->window), "tag", "remmina-main-window");
1619  remmina_widget_pool_register(GTK_WIDGET(remminamain->window));
1620 }
1621 
1622 /* Signal handler for "show" on remminamain->window */
1623 void remmina_main_on_show(GtkWidget *w, gpointer user_data)
1624 {
1625  TRACE_CALL(__func__);
1626 #ifdef SNAP_BUILD
1628 #endif
1629 }
1630 
1631 /* RemminaMain instance */
1632 GtkWidget *remmina_main_new(void)
1633 {
1634  TRACE_CALL(__func__);
1635  GSimpleActionGroup *actions;
1636  GtkAccelGroup *accel_group = NULL;
1637 
1638  remminamain = g_new0(RemminaMain, 1);
1639  remminamain->priv = g_new0(RemminaMainPriv, 1);
1640  /* Assign UI widgets to the private members */
1641  remminamain->builder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_main.glade");
1642  remminamain->window = GTK_WINDOW(RM_GET_OBJECT("RemminaMain"));
1643  if (kioskmode && kioskmode == TRUE) {
1644  gtk_window_set_position(remminamain->window, GTK_WIN_POS_CENTER_ALWAYS);
1645  gtk_window_set_default_size(remminamain->window, 800, 400);
1646  gtk_window_set_resizable(remminamain->window, FALSE);
1647  }
1648  /* New Button */
1649  remminamain->button_new = GTK_BUTTON(RM_GET_OBJECT("button_new"));
1650  if (kioskmode && kioskmode == TRUE)
1651  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->button_new), FALSE);
1652  /* Search bar */
1653  remminamain->search_toggle = GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle"));
1654  remminamain->search_bar = GTK_SEARCH_BAR(RM_GET_OBJECT("search_bar"));
1655  /* view mode list/tree */
1656  remminamain->view_toggle_button = GTK_TOGGLE_BUTTON(RM_GET_OBJECT("view_toggle_button"));
1657  if (kioskmode && kioskmode == TRUE)
1658  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->view_toggle_button), FALSE);
1659 
1660  /* Menu widgets */
1661  remminamain->menu_popup = GTK_MENU(RM_GET_OBJECT("menu_popup"));
1662  remminamain->menu_header_button = GTK_MENU_BUTTON(RM_GET_OBJECT("menu_header_button"));
1663  remminamain->menu_popup_full = GTK_MENU(RM_GET_OBJECT("menu_popup_full"));
1664  remminamain->menu_popup_delete_rc = GTK_MENU(RM_GET_OBJECT("menu_popup_delete_rc"));
1665  if (kioskmode && kioskmode == TRUE) {
1666  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->menu_popup_full), FALSE);
1667  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->menu_header_button), FALSE);
1668  }
1669  /* View mode radios */
1670  remminamain->menuitem_view_mode_list = GTK_RADIO_MENU_ITEM(RM_GET_OBJECT("menuitem_view_mode_list"));
1671  remminamain->menuitem_view_mode_tree = GTK_RADIO_MENU_ITEM(RM_GET_OBJECT("menuitem_view_mode_tree"));
1672  /* Quick connect objects */
1673  remminamain->box_quick_connect = GTK_BOX(RM_GET_OBJECT("box_quick_connect"));
1674  remminamain->combo_quick_connect_protocol = GTK_COMBO_BOX_TEXT(RM_GET_OBJECT("combo_quick_connect_protocol"));
1675  if (kioskmode && kioskmode == TRUE)
1676  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->combo_quick_connect_protocol), FALSE);
1677  remminamain->entry_quick_connect_server = GTK_ENTRY(RM_GET_OBJECT("entry_quick_connect_server"));
1678  /* Other widgets */
1679  remminamain->tree_files_list = GTK_TREE_VIEW(RM_GET_OBJECT("tree_files_list"));
1680  remminamain->column_files_list_name = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_name"));
1681  remminamain->column_files_list_group = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_group"));
1682  remminamain->column_files_list_server = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_server"));
1683  remminamain->column_files_list_plugin = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_plugin"));
1684  remminamain->column_files_list_date = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_date"));
1685  remminamain->column_files_list_notes = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_notes"));
1686  gtk_tree_view_column_set_fixed_width(remminamain->column_files_list_notes, 100);
1687  remminamain->statusbar_main = GTK_STATUSBAR(RM_GET_OBJECT("statusbar_main"));
1688  /* signals */
1689  g_signal_connect(remminamain->entry_quick_connect_server, "key-release-event", G_CALLBACK(remmina_main_search_key_event), NULL);
1690  g_signal_connect(remminamain->tree_files_list, "row-activated", G_CALLBACK(remmina_main_tree_row_activated), NULL);
1691  /* Non widget objects */
1692  actions = g_simple_action_group_new();
1693  g_action_map_add_action_entries(G_ACTION_MAP(actions), app_actions, G_N_ELEMENTS(app_actions), remminamain->window);
1694  gtk_widget_insert_action_group(GTK_WIDGET(remminamain->window), "app", G_ACTION_GROUP(actions));
1695  g_action_map_add_action_entries(G_ACTION_MAP(actions), main_actions, G_N_ELEMENTS(main_actions), remminamain->window);
1696  gtk_widget_insert_action_group(GTK_WIDGET(remminamain->window), "main", G_ACTION_GROUP(actions));
1697  g_object_unref(actions);
1698  /* Accelerators */
1699  accel_group = gtk_accel_group_new();
1700  gtk_window_add_accel_group(remminamain->window, accel_group);
1701  gtk_accel_group_connect(accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0,
1702  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_action_application_quit), NULL, NULL));
1703  // TODO: This crash remmina because the function doesn't receive the parameter we expect
1704  gtk_accel_group_connect(accel_group, GDK_KEY_P, GDK_CONTROL_MASK, 0,
1705  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_accel_application_preferences), NULL, NULL));
1706  gtk_accel_group_connect(accel_group, GDK_KEY_F, GDK_CONTROL_MASK, 0,
1707  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_accel_search_toggle), remminamain, NULL));
1708 
1709  /* Connect signals */
1710  gtk_builder_connect_signals(remminamain->builder, NULL);
1711  /* Initialize the window and load the preferences */
1713  return GTK_WIDGET(remminamain->window);
1714 }
1715 
1717 {
1718  if (!remminamain)
1719  return NULL;
1720  if (!remminamain->priv)
1721  return NULL;
1722  if (!remminamain->priv->initialized)
1723  return NULL;
1724  remminamain->window = GTK_WINDOW(RM_GET_OBJECT("RemminaMain"));
1725  return remminamain->window;
1726 }
1727 
1729 {
1730  if (!remminamain)
1731  return;
1733 }
1734 
1735 void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar* message) {
1736  GtkWidget *dialog;
1737 
1738  if (remminamain->window) {
1739  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, msg, buttons, "%s", message);
1740  gtk_dialog_run(GTK_DIALOG(dialog));
1741  gtk_widget_destroy(dialog);
1742  }
1743 }
1744 
1745 void remmina_main_show_warning_dialog(const gchar *message) {
1746  GtkWidget *dialog;
1747 
1748  if (remminamain->window) {
1749  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
1750  message, g_get_application_name());
1751  gtk_dialog_run(GTK_DIALOG(dialog));
1752  gtk_widget_destroy(dialog);
1753  }
1754 }
G_BEGIN_DECLS struct _RemminaGroupData RemminaGroupData
+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-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #include "config.h"
39 #include <ctype.h>
40 #include <gio/gio.h>
41 #ifndef __APPLE__
42 #include <gio/gdesktopappinfo.h>
43 #endif
44 #include <gdk/gdkkeysyms.h>
45 #include <glib/gi18n.h>
46 #include <gtk/gtk.h>
47 
48 #include "remmina.h"
49 #include "remmina_string_array.h"
50 #include "remmina_public.h"
51 #include "remmina_file.h"
52 #include "remmina_file_manager.h"
53 #include "remmina_file_editor.h"
54 #include "rcw.h"
55 #include "remmina_about.h"
56 #include "remmina_pref.h"
57 #include "remmina_pref_dialog.h"
58 #include "remmina_widget_pool.h"
59 #include "remmina_plugin_manager.h"
60 #include "remmina_log.h"
61 #include "remmina_icon.h"
62 #include "remmina_main.h"
63 #include "remmina_exec.h"
64 #include "remmina_mpchange.h"
65 #include "remmina_external_tools.h"
66 #include "remmina_unlock.h"
68 
70 
71 #define RM_GET_OBJECT(object_name) gtk_builder_get_object(remminamain->builder, object_name)
72 
73 enum {
84 };
85 
86 static
87 const gchar *supported_mime_types[] = {
88  "x-scheme-handler/rdp",
89  "x-scheme-handler/spice",
90  "x-scheme-handler/vnc",
91  "x-scheme-handler/remmina",
92  "application/x-remmina",
93  NULL
94 };
95 
96 static GActionEntry app_actions[] = {
97  { "about", remmina_main_on_action_application_about, NULL, NULL, NULL },
98  { "default", remmina_main_on_action_application_default, NULL, NULL, NULL },
99  { "mpchange", remmina_main_on_action_application_mpchange, NULL, NULL, NULL },
100  { "plugins", remmina_main_on_action_application_plugins, NULL, NULL, NULL },
101  { "preferences", remmina_main_on_action_application_preferences, "i", NULL, NULL },
102  { "dark", remmina_main_on_action_application_dark_theme, NULL, NULL, NULL },
103  { "debug", remmina_main_on_action_help_debug, NULL, NULL, NULL },
104  { "community", remmina_main_on_action_help_community, NULL, NULL, NULL },
105  { "donations", remmina_main_on_action_help_donations, NULL, NULL, NULL },
106  { "homepage", remmina_main_on_action_help_homepage, NULL, NULL, NULL },
107  { "wiki", remmina_main_on_action_help_wiki, NULL, NULL, NULL },
108  { "quit", remmina_main_on_action_application_quit, NULL, NULL, NULL },
109 };
110 
111 static GActionEntry main_actions[] = {
112  { "connect", remmina_main_on_action_connection_connect, NULL, NULL, NULL },
113  { "copy", remmina_main_on_action_connection_copy, NULL, NULL, NULL },
114  { "delete", remmina_main_on_action_connection_delete, NULL, NULL, NULL },
115  { "delete_multiple", remmina_main_on_action_connection_delete_multiple, NULL, NULL, NULL },
116  { "edit", remmina_main_on_action_connection_edit, NULL, NULL, NULL },
117  { "exttools", remmina_main_on_action_connection_external_tools, NULL, NULL, NULL },
118  { "new", remmina_main_on_action_connection_new, NULL, NULL, NULL },
119  { "export", remmina_main_on_action_tools_export, NULL, NULL, NULL },
120  { "import", remmina_main_on_action_tools_import, NULL, NULL, NULL },
121  { "expand", remmina_main_on_action_expand, NULL, NULL, NULL },
122  { "collapse", remmina_main_on_action_collapse, NULL, NULL, NULL },
123  { "search", remmina_main_on_action_search_toggle, NULL, NULL, NULL },
124 };
125 
126 static GtkTargetEntry remmina_drop_types[] =
127 {
128  { "text/uri-list", 0, 1 }
129 };
130 
132 {
133  "RDP", "VNC", "SSH", "NX", "SPICE", "X2GO"
134 };
135 
139 static void remmina_main_save_size(void)
140 {
141  TRACE_CALL(__func__);
142  if ((gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(remminamain->window))) & GDK_WINDOW_STATE_MAXIMIZED) == 0) {
143  gtk_window_get_size(remminamain->window, &remmina_pref.main_width, &remmina_pref.main_height);
144  remmina_pref.main_maximize = FALSE;
145  } else {
147  }
148 }
149 
150 static void remmina_main_save_expanded_group_func(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data)
151 {
152  TRACE_CALL(__func__);
153  GtkTreeIter iter;
154  gchar *group;
155 
156  gtk_tree_model_get_iter(remminamain->priv->file_model_sort, &iter, path);
157  gtk_tree_model_get(remminamain->priv->file_model_sort, &iter, GROUP_COLUMN, &group, -1);
158  if (group) {
159  remmina_string_array_add(remminamain->priv->expanded_group, group);
160  g_free(group);
161  }
162 }
163 
165 {
166  TRACE_CALL(__func__);
167  if (GTK_IS_TREE_STORE(remminamain->priv->file_model)) {
168  if (remminamain->priv->expanded_group)
170  remminamain->priv->expanded_group = remmina_string_array_new();
171  gtk_tree_view_map_expanded_rows(remminamain->tree_files_list,
172  (GtkTreeViewMappingFunc)remmina_main_save_expanded_group_func, NULL);
173  }
174 }
175 
181 {
182  TRACE_CALL(__func__);
183  if (!remminamain || !remminamain->window)
184  return;
185 
191 }
192 
194 {
195  TRACE_CALL(__func__);
196 
197  if (remminamain) {
198  if (remminamain->window)
199  gtk_widget_destroy(GTK_WIDGET(remminamain->window));
200 
201  g_object_unref(remminamain->builder);
203  remminamain->priv->expanded_group = NULL;
204  if (remminamain->priv->file_model)
205  g_object_unref(G_OBJECT(remminamain->priv->file_model));
206  g_object_unref(G_OBJECT(remminamain->priv->file_model_filter));
207  g_free(remminamain->priv->selected_filename);
208  g_free(remminamain->priv->selected_name);
209  g_free(remminamain->priv);
210  g_free(remminamain);
211  remminamain = NULL;
212  }
213 }
214 
218 static gboolean remmina_main_dexit(gpointer data)
219 {
220  TRACE_CALL(__func__);
222  return FALSE;
223 }
224 
225 gboolean remmina_main_on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
226 {
227  TRACE_CALL(__func__);
229 
230  g_idle_add(remmina_main_dexit, NULL);
231 
232  return FALSE;
233 }
234 
235 gboolean remmina_main_idle_destroy(gpointer data)
236 {
237  TRACE_CALL(__func__);
238 
239  if (remminamain)
241 
242  return G_SOURCE_REMOVE;
243 }
244 
249 {
250  TRACE_CALL(__func__);
251 
252  if (remminamain) {
253  /* Invalidate remminamain->window to avoid multiple destructions */
254  remminamain->window = NULL;
255  /* Destroy remminamain struct, later. We can't destroy
256  * important objects like the builder now */
257  g_idle_add(remmina_main_idle_destroy, NULL);
258  }
259 }
260 
262 {
263  TRACE_CALL(__func__);
264  g_free(remminamain->priv->selected_filename);
265  g_free(remminamain->priv->selected_name);
266  remminamain->priv->selected_filename = NULL;
267  remminamain->priv->selected_name = NULL;
268 }
269 
270 #ifdef SNAP_BUILD
271 
273 {
274  GtkBuilder *dlgbuilder = NULL;
275  GtkWidget *dlg;
276  GtkWindow *parent;
277  int result;
278  static gboolean shown_once = FALSE;
279  gboolean need_snap_interface_connections = FALSE;
280  GtkWidget *dsa;
282 
283  if (shown_once)
284  return;
285  else
286  shown_once = TRUE;
287 
288  g_print("Remmina is compiled as a SNAP package.\n");
289  remmina_secret_plugin = remmina_plugin_manager_get_secret_plugin();
290  if (remmina_secret_plugin == NULL) {
291  g_print(" but we can’t find the secret plugin inside the SNAP.\n");
292  need_snap_interface_connections = TRUE;
293  } else {
294  if (!remmina_secret_plugin->is_service_available(remmina_secret_plugin)) {
295  g_print(" but we can’t access a secret service. Secret service or SNAP interface connection is missing.\n");
296  need_snap_interface_connections = TRUE;
297  }
298  }
299 
300  if (need_snap_interface_connections && !remmina_pref.prevent_snap_welcome_message) {
301  dlgbuilder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_snap_info_dialog.glade");
302  dsa = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "dontshowagain"));
303  if (dlgbuilder) {
304  parent = remmina_main_get_window();
305  dlg = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "SnapInfoDlg"));
306  if (parent)
307  gtk_window_set_transient_for(GTK_WINDOW(dlg), parent);
308  gtk_builder_connect_signals(dlgbuilder, NULL);
309  result = gtk_dialog_run(GTK_DIALOG(dlg));
310  if (result == 1) {
311  remmina_pref.prevent_snap_welcome_message = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dsa));
313  }
314  gtk_widget_destroy(dlg);
315  g_object_unref(dlgbuilder);
316  }
317  }
318 }
319 #endif
320 
321 
322 static gboolean remmina_main_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path,
323  gboolean path_currently_selected, gpointer user_data)
324 {
325  TRACE_CALL(__func__);
326  guint context_id;
327  GtkTreeIter iter;
328  gchar buf[1000];
329 
330  if (path_currently_selected)
331  return TRUE;
332 
333  if (!gtk_tree_model_get_iter(model, &iter, path))
334  return TRUE;
335 
337 
338  gtk_tree_model_get(model, &iter,
339  NAME_COLUMN, &remminamain->priv->selected_name,
340  FILENAME_COLUMN, &remminamain->priv->selected_filename,
341  -1);
342 
343  context_id = gtk_statusbar_get_context_id(remminamain->statusbar_main, "status");
344  gtk_statusbar_pop(remminamain->statusbar_main, context_id);
345  if (remminamain->priv->selected_filename) {
346  g_snprintf(buf, sizeof(buf), "%s (%s)", remminamain->priv->selected_name, remminamain->priv->selected_filename);
347  gtk_statusbar_push(remminamain->statusbar_main, context_id, buf);
348  } else {
349  gtk_statusbar_push(remminamain->statusbar_main, context_id, remminamain->priv->selected_name);
350  }
351 
352  return TRUE;
353 }
354 
355 static void remmina_main_load_file_list_callback(RemminaFile *remminafile, gpointer user_data)
356 {
357  TRACE_CALL(__func__);
358  GtkTreeIter iter;
359  GtkListStore *store;
360 
361  store = GTK_LIST_STORE(user_data);
362  gchar *datetime;
363 
364  datetime = remmina_file_get_datetime(remminafile);
365  gtk_list_store_append(store, &iter);
366  gtk_list_store_set(store, &iter,
368  NAME_COLUMN, remmina_file_get_string(remminafile, "name"),
369  NOTES_COLUMN, g_uri_unescape_string(remmina_file_get_string(remminafile, "notes_text"), NULL),
370  GROUP_COLUMN, remmina_file_get_string(remminafile, "group"),
371  SERVER_COLUMN, remmina_file_get_string(remminafile, "server"),
372  PLUGIN_COLUMN, remmina_file_get_string(remminafile, "protocol"),
373  DATE_COLUMN, datetime,
375  LABELS_COLUMN, remmina_file_get_string(remminafile, "labels"),
376  -1);
377  g_free(datetime);
378 }
379 
380 static gboolean remmina_main_load_file_tree_traverse(GNode *node, GtkTreeStore *store, GtkTreeIter *parent)
381 {
382  TRACE_CALL(__func__);
383  GtkTreeIter *iter;
384  RemminaGroupData *data;
385  GNode *child;
386 
387  iter = NULL;
388  if (node->data) {
389  data = (RemminaGroupData *)node->data;
390  iter = g_new0(GtkTreeIter, 1);
391  gtk_tree_store_append(store, iter, parent);
392  gtk_tree_store_set(store, iter,
393  PROTOCOL_COLUMN, "folder-symbolic",
394  NAME_COLUMN, data->name,
395  GROUP_COLUMN, data->group,
396  DATE_COLUMN, data->datetime,
397  FILENAME_COLUMN, NULL,
398  LABELS_COLUMN, data->labels,
399  -1);
400  }
401  for (child = g_node_first_child(node); child; child = g_node_next_sibling(child))
402  remmina_main_load_file_tree_traverse(child, store, iter);
403  g_free(iter);
404  return FALSE;
405 }
406 
407 static void remmina_main_load_file_tree_group(GtkTreeStore *store)
408 {
409  TRACE_CALL(__func__);
410  GNode *root;
411 
413  remmina_main_load_file_tree_traverse(root, store, NULL);
415 }
416 
417 static void remmina_main_expand_group_traverse(GtkTreeIter *iter)
418 {
419  TRACE_CALL(__func__);
420  GtkTreeModel *tree;
421  gboolean ret;
422  gchar *group, *filename;
423  GtkTreeIter child;
424  GtkTreePath *path;
425 
426  tree = remminamain->priv->file_model_sort;
427  ret = TRUE;
428  while (ret) {
429  gtk_tree_model_get(tree, iter, GROUP_COLUMN, &group, FILENAME_COLUMN, &filename, -1);
430  if (filename == NULL) {
431  if (remmina_string_array_find(remminamain->priv->expanded_group, group) >= 0) {
432  path = gtk_tree_model_get_path(tree, iter);
433  gtk_tree_view_expand_row(remminamain->tree_files_list, path, FALSE);
434  gtk_tree_path_free(path);
435  }
436  if (gtk_tree_model_iter_children(tree, &child, iter))
438  }
439  g_free(group);
440  g_free(filename);
441 
442  ret = gtk_tree_model_iter_next(tree, iter);
443  }
444 }
445 
446 static void remmina_main_expand_group(void)
447 {
448  TRACE_CALL(__func__);
449  GtkTreeIter iter;
450 
451  if (gtk_tree_model_get_iter_first(remminamain->priv->file_model_sort, &iter))
453 }
454 
455 static gboolean remmina_main_load_file_tree_find(GtkTreeModel *tree, GtkTreeIter *iter, const gchar *match_group)
456 {
457  TRACE_CALL(__func__);
458  gboolean ret, match;
459  gchar *group, *filename;
460  GtkTreeIter child;
461 
462  match = FALSE;
463  ret = TRUE;
464  while (ret) {
465  gtk_tree_model_get(tree, iter, GROUP_COLUMN, &group, FILENAME_COLUMN, &filename, -1);
466  match = (filename == NULL && g_strcmp0(group, match_group) == 0);
467  g_free(group);
468  g_free(filename);
469  if (match)
470  break;
471  if (gtk_tree_model_iter_children(tree, &child, iter)) {
472  match = remmina_main_load_file_tree_find(tree, &child, match_group);
473  if (match) {
474  memcpy(iter, &child, sizeof(GtkTreeIter));
475  break;
476  }
477  }
478  ret = gtk_tree_model_iter_next(tree, iter);
479  }
480  return match;
481 }
482 
483 static void remmina_main_load_file_tree_callback(RemminaFile *remminafile, gpointer user_data)
484 {
485  TRACE_CALL(__func__);
486  GtkTreeIter iter, child;
487  GtkTreeStore *store;
488  gboolean found;
489  gchar *datetime = NULL;
490 
491  store = GTK_TREE_STORE(user_data);
492 
493  found = FALSE;
494  if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
495  found = remmina_main_load_file_tree_find(GTK_TREE_MODEL(store), &iter,
496  remmina_file_get_string(remminafile, "group"));
497 
498  datetime = remmina_file_get_datetime(remminafile);
499  //REMMINA_DEBUG("The date is %s", datetime);
500  gtk_tree_store_append(store, &child, (found ? &iter : NULL));
501  gtk_tree_store_set(store, &child,
503  NAME_COLUMN, remmina_file_get_string(remminafile, "name"),
504  NOTES_COLUMN, g_uri_unescape_string(remmina_file_get_string(remminafile, "notes_text"), NULL),
505  GROUP_COLUMN, remmina_file_get_string(remminafile, "group"),
506  SERVER_COLUMN, remmina_file_get_string(remminafile, "server"),
507  PLUGIN_COLUMN, remmina_file_get_string(remminafile, "protocol"),
508  DATE_COLUMN, datetime,
510  LABELS_COLUMN, remmina_file_get_string(remminafile, "labels"),
511  -1);
512  g_free(datetime);
513 }
514 
515 static void remmina_main_file_model_on_sort(GtkTreeSortable *sortable, gpointer user_data)
516 {
517  TRACE_CALL(__func__);
518  gint columnid;
519  GtkSortType order;
520 
521  gtk_tree_sortable_get_sort_column_id(sortable, &columnid, &order);
525 }
526 
527 static gboolean remmina_main_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
528 {
529  TRACE_CALL(__func__);
530  gchar *text;
531  gchar *protocol, *name, *labels, *group, *server, *plugin, *date, *s;
532  gboolean result = TRUE;
533 
534  text = g_ascii_strdown(gtk_entry_get_text(remminamain->entry_quick_connect_server), -1);
535  if (text && text[0]) {
536  gtk_tree_model_get(model, iter,
537  PROTOCOL_COLUMN, &protocol,
538  NAME_COLUMN, &name,
539  GROUP_COLUMN, &group,
540  SERVER_COLUMN, &server,
541  PLUGIN_COLUMN, &plugin,
542  DATE_COLUMN, &date,
543  LABELS_COLUMN, &labels,
544  -1);
545  if (g_strcmp0(protocol, "folder-symbolic") != 0) {
546  s = g_ascii_strdown(name ? name : "", -1);
547  g_free(name);
548  name = s;
549  s = g_ascii_strdown(group ? group : "", -1);
550  g_free(group);
551  group = s;
552  s = g_ascii_strdown(server ? server : "", -1);
553  g_free(server);
554  server = s;
555  s = g_ascii_strdown(plugin ? plugin : "", -1);
556  g_free(plugin);
557  plugin = s;
558  s = g_ascii_strdown(date ? date : "", -1);
559  g_free(date);
560  date = s;
561  result = (strstr(name, text) || strstr(group, text) || strstr(server, text) || strstr(plugin, text) || strstr(date, text));
562 
563  // Filter by labels
564 
565  s = g_ascii_strdown(labels ? labels : "", -1);
566  g_free(labels);
567  labels = s;
568 
569  if (strlen(labels) > 0) {
570  gboolean labels_result = TRUE;
571  gchar **labels_array = g_strsplit(labels, ",", -1);
572  gchar **text_array = g_strsplit(text, ",", -1);
573 
574  for (int t = 0; (NULL != text_array[t]); t++) {
575  if (0 == strlen(text_array[t])) {
576  continue;
577  }
578 
579  gboolean text_result = FALSE;
580 
581  for (int l = 0; (NULL != labels_array[l]); l++) {
582  if (0 == strlen(labels_array[l])) {
583  continue;
584  }
585 
586  text_result = (text_result || strstr(labels_array[l], text_array[t]));
587 
588  if (text_result) {
589  break;
590  }
591  }
592 
593  labels_result = (labels_result && text_result);
594 
595  if (!labels_result) {
596  break;
597  }
598  }
599 
600  result = (result || labels_result);
601 
602  g_strfreev(labels_array);
603  g_strfreev(text_array);
604  }
605  }
606  g_free(protocol);
607  g_free(name);
608  g_free(labels);
609  g_free(group);
610  g_free(server);
611  g_free(plugin);
612  g_free(date);
613  }
614  g_free(text);
615  return result;
616 }
617 
618 static void remmina_main_select_file(const gchar *filename)
619 {
620  TRACE_CALL(__func__);
621  GtkTreeIter iter;
622  GtkTreePath *path;
623  gchar *item_filename;
624  gboolean cmp;
625 
626  if (!gtk_tree_model_get_iter_first(remminamain->priv->file_model_sort, &iter))
627  return;
628 
629  while (TRUE) {
630  gtk_tree_model_get(remminamain->priv->file_model_sort, &iter, FILENAME_COLUMN, &item_filename, -1);
631  cmp = g_strcmp0(item_filename, filename);
632  g_free(item_filename);
633  if (cmp == 0) {
634  gtk_tree_selection_select_iter(gtk_tree_view_get_selection(remminamain->tree_files_list),
635  &iter);
636  path = gtk_tree_model_get_path(remminamain->priv->file_model_sort, &iter);
637  gtk_tree_view_scroll_to_cell(remminamain->tree_files_list, path, NULL, TRUE, 0.5, 0.0);
638  gtk_tree_path_free(path);
639  return;
640  }
641  if (!gtk_tree_model_iter_next(remminamain->priv->file_model_sort, &iter))
642  return;
643  }
644 }
645 
647 {
648  TRACE_CALL(__func__);
649  gint items_count;
650  gchar buf[200];
651  guint context_id;
652  gint view_file_mode;
653  gboolean always_show_notes;
654  char *save_selected_filename;
655  GtkTreeModel *newmodel;
656  const gchar *neticon;
657  const gchar *connection_tooltip;
658 
659  save_selected_filename = g_strdup(remminamain->priv->selected_filename);
661 
662  view_file_mode = remmina_pref.view_file_mode;
663  if (remminamain->priv->override_view_file_mode_to_list)
664  view_file_mode = REMMINA_VIEW_FILE_LIST;
665 
666  switch (remmina_pref.view_file_mode) {
668  gtk_toggle_button_set_active(remminamain->view_toggle_button, FALSE);
669  break;
671  default:
672  gtk_toggle_button_set_active(remminamain->view_toggle_button, TRUE);
673  break;
674  }
675 
676  switch (view_file_mode) {
678  /* Create new GtkTreeStore model */
679  newmodel = GTK_TREE_MODEL(gtk_tree_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
680  /* Hide the Group column in the tree view mode */
681  gtk_tree_view_column_set_visible(remminamain->column_files_list_group, FALSE);
682  /* Load groups first */
683  remmina_main_load_file_tree_group(GTK_TREE_STORE(newmodel));
684  /* Load files list */
685  items_count = remmina_file_manager_iterate((GFunc)remmina_main_load_file_tree_callback, (gpointer)newmodel);
686  break;
687 
689  default:
690  /* Create new GtkListStore model */
691  newmodel = GTK_TREE_MODEL(gtk_list_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
692  /* Show the Group column in the list view mode */
693  gtk_tree_view_column_set_visible(remminamain->column_files_list_group, TRUE);
694  /* Load files list */
695  items_count = remmina_file_manager_iterate((GFunc)remmina_main_load_file_list_callback, (gpointer)newmodel);
696  break;
697  }
698 
699  /* Set note column visibility*/
700  always_show_notes = remmina_pref.always_show_notes;
701  if (!always_show_notes){
702  gtk_tree_view_column_set_visible(remminamain->column_files_list_notes, FALSE);
703  }
704 
705  /* Unset old model */
706  gtk_tree_view_set_model(remminamain->tree_files_list, NULL);
707 
708  /* Destroy the old model and save the new one */
709  remminamain->priv->file_model = newmodel;
710 
711  /* Create a sorted filtered model based on newmodel and apply it to the TreeView */
712  remminamain->priv->file_model_filter = gtk_tree_model_filter_new(remminamain->priv->file_model, NULL);
713  gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(remminamain->priv->file_model_filter),
714  (GtkTreeModelFilterVisibleFunc)remmina_main_filter_visible_func, NULL, NULL);
715  remminamain->priv->file_model_sort = gtk_tree_model_sort_new_with_model(remminamain->priv->file_model_filter);
716  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(remminamain->priv->file_model_sort),
719  gtk_tree_view_set_model(remminamain->tree_files_list, remminamain->priv->file_model_sort);
720  g_signal_connect(G_OBJECT(remminamain->priv->file_model_sort), "sort-column-changed",
721  G_CALLBACK(remmina_main_file_model_on_sort), NULL);
723  /* Select the file previously selected */
724  if (save_selected_filename) {
725  remmina_main_select_file(save_selected_filename);
726  g_free(save_selected_filename);
727  }
728  gtk_tree_view_column_set_widget(remminamain->column_files_list_date, NULL);
729 
730  GtkWidget *label = gtk_tree_view_column_get_button(remminamain->column_files_list_date);
731 
732  gtk_widget_set_tooltip_text(GTK_WIDGET(label),
733  _("The latest successful connection attempt, or a pre-computed date"));
734  /* Show in the status bar the total number of connections found */
735  g_snprintf(buf, sizeof(buf), ngettext("Total %i item.", "Total %i items.", items_count), items_count);
736  context_id = gtk_statusbar_get_context_id(remminamain->statusbar_main, "status");
737  gtk_statusbar_pop(remminamain->statusbar_main, context_id);
738  gtk_statusbar_push(remminamain->statusbar_main, context_id, buf);
739 
741  if (remminamain->monitor->connected){
742  neticon = g_strdup("network-transmit-receive-symbolic");
743  connection_tooltip = g_strdup(_("Network status: fully online"));
744  } else {
745  neticon = g_strdup("network-offline-symbolic");
746  connection_tooltip = g_strdup(_("Network status: offline"));
747  }
748 
749  if (GTK_IS_WIDGET(remminamain->network_icon))
750  gtk_widget_destroy(remminamain->network_icon);
751  GIcon *icon = g_themed_icon_new (neticon);
752  remminamain->network_icon = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
753  gtk_widget_set_tooltip_text (remminamain->network_icon, connection_tooltip);
754 
755  g_object_unref (icon);
756 
757  gtk_box_pack_start (GTK_BOX(remminamain->statusbar_main), remminamain->network_icon, FALSE, FALSE, 0);
758  gtk_widget_show (remminamain->network_icon);
759 
760 }
761 
762 void remmina_main_load_files_cb(GtkEntry *entry, char *string, gpointer user_data)
763 {
764  TRACE_CALL(__func__);
766 }
767 
768 void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data)
769 {
770  TRACE_CALL(__func__);
771 
772  RemminaFile *remminafile;
773 
774  if (!remminamain->priv->selected_filename)
775  return;
776 
777  remminafile = remmina_file_load(remminamain->priv->selected_filename);
778 
779  if (remminafile == NULL)
780  return;
781 
782  if (remmina_pref_get_boolean("use_primary_password")
783  && remmina_pref_get_boolean("lock_connect")
784  && remmina_unlock_new(remminamain->window) == 0)
785  return;
786  if (remmina_file_get_int (remminafile, "profile-lock", FALSE) == 1
787  && remmina_unlock_new(remminamain->window) == 0)
788  return;
789 
790  remmina_file_touch(remminafile);
792 
793  remmina_file_free(remminafile);
794 }
795 
796 void remmina_main_on_action_connection_external_tools(GSimpleAction *action, GVariant *param, gpointer data)
797 {
798  TRACE_CALL(__func__);
799  if (!remminamain->priv->selected_filename)
800  return;
801 
802  remmina_external_tools_from_filename(remminamain, remminamain->priv->selected_filename);
803 }
804 
805 static void remmina_main_file_editor_destroy(GtkWidget *widget, gpointer user_data)
806 {
807  TRACE_CALL(__func__);
808 
809  if (!remminamain)
810  return;
812 }
813 
814 void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data)
815 {
816  TRACE_CALL(__func__);
817  RemminaFile *remminafile;
818 
819  const gchar *username;
820  const gchar *domain;
821  const gchar *group;
822  const gchar *gatewayusername;
823  const gchar *gatewaydomain;
824 
825  username = domain = group = gatewayusername = gatewaydomain = "";
826 
827  remminafile = NULL;
828 
829  if (remmina_pref_get_boolean("use_primary_password")
830  && remmina_pref_get_boolean("lock_edit")
831  && remmina_unlock_new(remminamain->window) == 0)
832  return;
833 
834  if (remminamain->priv->selected_filename) {
835  remminafile = remmina_file_load(remminamain->priv->selected_filename);
836  if (remminafile != NULL) {
837  username = remmina_file_get_string(remminafile, "username");
838  domain = remmina_file_get_string(remminafile, "domain");
839  group = remmina_file_get_string(remminafile, "group");
840  gatewayusername = remmina_file_get_string(remminafile, "gateway_username");
841  gatewaydomain = remmina_file_get_string(remminafile, "gateway_domain");
842  }
843  }
844 
845  remmina_mpchange_schedule(TRUE, group, domain, username, "", gatewayusername, gatewaydomain, "");
846 
847  if (remminafile != NULL)
848  remmina_file_free(remminafile);
849 }
850 
851 void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data)
852 {
853  TRACE_CALL(__func__);
854  if (kioskmode && kioskmode == TRUE)
855  return;
856  GtkWidget *widget;
857 
858  if (remmina_pref_get_boolean("use_primary_password")
859  && remmina_pref_get_boolean("lock_edit")
860  && remmina_unlock_new(remminamain->window) == 0)
861  return;
862 
863  widget = remmina_file_editor_new();
864  g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(remmina_main_file_editor_destroy), remminamain);
865  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
866  gtk_widget_show(widget);
868 }
869 
870 static gboolean remmina_main_search_key_event(GtkWidget *search_entry, GdkEventKey *event, gpointer user_data)
871 {
872  TRACE_CALL(__func__);
873  if (event->keyval == GDK_KEY_Escape) {
874  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
875  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle")), FALSE);
876  return TRUE;
877  }
878  return FALSE;
879 }
880 
881 static gboolean remmina_main_tree_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
882 {
883  TRACE_CALL(__func__);
884  if (gtk_tree_view_row_expanded(tree, path))
885  gtk_tree_view_collapse_row(tree, path);
886  else
887  gtk_tree_view_expand_row(tree, path, FALSE);
888  return TRUE;
889 }
890 
892 {
893  if (gtk_toggle_button_get_active(remminamain->view_toggle_button)) {
896  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
899  }
900  } else {
903  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
906  }
907  }
908 }
909 
910 void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data)
911 {
912  TRACE_CALL(__func__);
913  GtkWidget *widget;
914 
915  if (remmina_pref_get_boolean("use_primary_password")
916  && remmina_unlock_new(remminamain->window) == 0)
917  return;
918 
919  if (!remminamain->priv->selected_filename)
920  return;
921 
922  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
923 
924  if (((remmina_pref_get_boolean("lock_edit")
925  && remmina_pref_get_boolean("use_primary_password"))
926  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
927  && remmina_unlock_new(remminamain->window) == 0)
928  return;
929 
930  if (remminafile) {
931  remmina_file_free(remminafile);
932  remminafile = NULL;
933  }
934 
935  widget = remmina_file_editor_new_copy(remminamain->priv->selected_filename);
936  if (widget) {
937  g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(remmina_main_file_editor_destroy), remminamain);
938  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
939  gtk_widget_show(widget);
940  }
941  /* Select the file previously selected */
942  if (remminamain->priv->selected_filename)
944 }
945 
946 void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data)
947 {
948  TRACE_CALL(__func__);
949  GtkWidget *widget;
950 
951  if (!remminamain->priv->selected_filename)
952  return;
953 
954  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
955 
956  if (remmina_pref_get_boolean("use_primary_password")
957  && (remmina_pref_get_boolean("lock_edit")
958  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
959  && remmina_unlock_new(remminamain->window) == 0)
960  return;
961 
962  if (remminafile) {
963  remmina_file_free(remminafile);
964  remminafile = NULL;
965  }
966 
968  if (widget) {
969  gtk_window_set_transient_for(GTK_WINDOW(widget), remminamain->window);
970  gtk_widget_show(widget);
971  }
972 /* Select the file previously selected */
973  if (remminamain->priv->selected_filename)
975 }
976 
977 void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data)
978 {
979  TRACE_CALL(__func__);
980  GtkWidget *dialog;
981 
982  if (!remminamain->priv->selected_filename)
983  return;
984 
985  RemminaFile *remminafile = remmina_file_load(remminamain->priv->selected_filename);
986 
987  if (((remmina_pref_get_boolean("lock_edit")
988  && remmina_pref_get_boolean("use_primary_password"))
989  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
990  && remmina_unlock_new(remminamain->window) == 0)
991  return;
992 
993  if (remminafile) {
994  remmina_file_free(remminafile);
995  remminafile = NULL;
996  }
997 
998  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
999  _("Are you sure you want to delete “%s”?"), remminamain->priv->selected_name);
1000  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1001  gchar *delfilename = g_strdup(remminamain->priv->selected_filename);
1002  remmina_file_delete(delfilename);
1003  g_free(delfilename), delfilename = NULL;
1006  }
1007  gtk_widget_destroy(dialog);
1009 }
1010 
1011 void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data)
1012 {
1013  TRACE_CALL(__func__);
1014  GtkWidget *dialog;
1015  GtkTreeSelection *sel = gtk_tree_view_get_selection(remminamain->tree_files_list);
1016  GtkTreeModel *model = gtk_tree_view_get_model(remminamain->tree_files_list);
1017  GList *list = gtk_tree_selection_get_selected_rows(sel, &model);
1018  gchar *file_to_delete;
1019 
1020  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1021  _("Are you sure you want to delete the selected files?"));
1022 
1023  // Delete files if Yes is clicked
1024  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1025  while (list) {
1026  GtkTreePath *path = list->data;
1027  GtkTreeIter iter;
1028 
1029  if (!gtk_tree_model_get_iter(model, &iter, path)) {
1030  GtkWidget *dialog_warning;
1031  dialog_warning = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1032  _("Failed to delete files!"));
1033  gtk_dialog_run(GTK_DIALOG(dialog_warning));
1034  gtk_widget_destroy(dialog_warning);
1035  gtk_widget_destroy(dialog);
1037  return;
1038  }
1039 
1040  gtk_tree_model_get(model, &iter,
1041  FILENAME_COLUMN, &file_to_delete, -1);
1042 
1043  RemminaFile *remminafile = remmina_file_load(file_to_delete);
1044 
1045  if (((remmina_pref_get_boolean("lock_edit")
1046  && remmina_pref_get_boolean("use_primary_password"))
1047  || remmina_file_get_int (remminafile, "profile-lock", FALSE))
1048  && remmina_unlock_new(remminamain->window) == 0)
1049  return;
1050 
1051  if (remminafile) {
1052  remmina_file_free(remminafile);
1053  remminafile = NULL;
1054  }
1055 
1056  gchar *delfilename = g_strdup(file_to_delete);
1057  remmina_file_delete(delfilename);
1058  g_free(delfilename), delfilename = NULL;
1061  list = g_list_next(list);
1062  }
1063  }
1064 
1065  gtk_widget_destroy(dialog);
1067 }
1068 
1069 void remmina_main_on_accel_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
1070 {
1071  TRACE_CALL(__func__);
1072  GVariant *v = g_variant_new("i", 0);
1073 
1075 }
1076 
1078 {
1079  GtkSettings *settings;
1080  settings = gtk_settings_get_default();
1081  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1083  gtk_toggle_button_set_active(remminamain->search_toggle, FALSE);
1084  }
1085  else{
1086  gtk_toggle_button_set_active(remminamain->search_toggle, TRUE);
1087  }
1088  gtk_tree_view_column_set_visible(remminamain->column_files_list_notes, remmina_pref.always_show_notes);
1089 }
1090 
1091 void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
1092 {
1093  TRACE_CALL(__func__);
1094 
1095  REMMINA_DEBUG("Opening the preferences");
1096  gint32 tab_num;
1097 
1098  if (param) {
1099  REMMINA_DEBUG("Parameter passed to preferences of type %s", g_variant_get_type_string(param));
1100  tab_num = g_variant_get_int32(param);
1101  REMMINA_DEBUG("We got a parameter for the preferences: %d", tab_num);
1102  } else {
1103  tab_num = 0;
1104  }
1105 
1106  if (remmina_pref_get_boolean("use_primary_password")
1107  && remmina_unlock_new(remminamain->window) == 0)
1108  return;
1109 
1110  GtkWidget *widget = remmina_pref_dialog_new(tab_num, remminamain->window);
1111 
1112  gtk_widget_show_all(widget);
1113 }
1114 
1115 void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
1116 {
1117  TRACE_CALL(__func__);
1118 #ifndef __APPLE__
1119  g_autoptr(GError) error = NULL;
1120  GDesktopAppInfo *desktop_info;
1121  GAppInfo *info = NULL;
1122  g_autofree gchar *id = g_strconcat(REMMINA_APP_ID, ".desktop", NULL);
1123  int i;
1124 
1125  desktop_info = g_desktop_app_info_new(id);
1126  if (!desktop_info)
1127  return;
1128 
1129  info = G_APP_INFO(desktop_info);
1130 
1131  for (i = 0; supported_mime_types[i]; i++) {
1132  if (!g_app_info_set_as_default_for_type(info, supported_mime_types[i], &error))
1133  g_warning("Failed to set '%s' as the default application for secondary content type '%s': %s",
1134  g_app_info_get_name(info), supported_mime_types[i], error->message);
1135  else
1136  g_debug("Set '%s' as the default application for '%s'",
1137  g_app_info_get_name(info),
1139  }
1140 #endif
1141 }
1142 
1143 void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
1144 {
1145  // Called by quit signal in remmina_main.glade
1146  TRACE_CALL(__func__);
1147  g_debug("Quit intercept");
1149 }
1150 
1152 {
1155  gtk_entry_set_text(remminamain->entry_quick_connect_server, "");
1158  }
1159 }
1160 
1161 static void remmina_main_import_file_list(GSList *files)
1162 {
1163  TRACE_CALL(__func__);
1164  GtkWidget *dlg;
1165  GSList *element;
1166  gchar *path;
1167  RemminaFilePlugin *plugin;
1168  GString *err;
1169  RemminaFile *remminafile = NULL;
1170  gboolean imported;
1171 
1172  err = g_string_new(NULL);
1173  imported = FALSE;
1174  for (element = files; element; element = element->next) {
1175  path = (gchar *)element->data;
1177  if (plugin && (remminafile = plugin->import_func(plugin, path)) != NULL && remmina_file_get_string(remminafile, "name")) {
1178  remmina_file_generate_filename(remminafile);
1179  remmina_file_save(remminafile);
1180  imported = TRUE;
1181  } else {
1182  g_string_append(err, path);
1183  g_string_append_c(err, '\n');
1184  }
1185  if (remminafile) {
1186  remmina_file_free(remminafile);
1187  remminafile = NULL;
1188  }
1189  g_free(path);
1190  }
1191  g_slist_free(files);
1192  if (err->len > 0) {
1193  // TRANSLATORS: The placeholder %s is an error message
1194  dlg = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1195  _("Unable to import:\n%s"), err->str);
1196  g_signal_connect(G_OBJECT(dlg), "response", G_CALLBACK(gtk_widget_destroy), NULL);
1197  gtk_widget_show(dlg);
1198  }
1199  g_string_free(err, TRUE);
1200  if (imported)
1202 }
1203 
1204 static void remmina_main_action_tools_import_on_response(GtkDialog *dialog, gint response_id, gpointer user_data)
1205 {
1206  TRACE_CALL(__func__);
1207  GSList *files;
1208 
1209  if (response_id == GTK_RESPONSE_ACCEPT) {
1210  files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
1212  }
1213  gtk_widget_destroy(GTK_WIDGET(dialog));
1214 }
1215 
1216 void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
1217 {
1218  TRACE_CALL(__func__);
1219  GtkWidget *dialog;
1220 
1221  dialog = gtk_file_chooser_dialog_new(_("Import"), remminamain->window, GTK_FILE_CHOOSER_ACTION_OPEN, "Import",
1222  GTK_RESPONSE_ACCEPT, NULL);
1223  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1224  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(remmina_main_action_tools_import_on_response), NULL);
1225  gtk_widget_show(dialog);
1226 }
1227 
1228 void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
1229 {
1230  TRACE_CALL(__func__);
1231  RemminaFilePlugin *plugin;
1232  RemminaFile *remminafile;
1233  GtkWidget *dialog;
1234 
1235  if (!remminamain->priv->selected_filename)
1236  return;
1237 
1238  remminafile = remmina_file_load(remminamain->priv->selected_filename);
1239  if (remminafile == NULL)
1240  return;
1241  plugin = remmina_plugin_manager_get_export_file_handler(remminafile);
1242  if (plugin) {
1243  dialog = gtk_file_chooser_dialog_new(plugin->export_hints, remminamain->window,
1244  GTK_FILE_CHOOSER_ACTION_SAVE, _("_Save"), GTK_RESPONSE_ACCEPT, NULL);
1245  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1246  plugin->export_func(plugin, remminafile, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
1247  gtk_widget_destroy(dialog);
1248  } else {
1249  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1250  _("This protocol does not support exporting."));
1251  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
1252  gtk_widget_show(dialog);
1253  }
1254  remmina_file_free(remminafile);
1255 }
1256 
1257 void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
1258 {
1259  TRACE_CALL(__func__);
1260  remmina_plugin_manager_show(remminamain->window);
1261 }
1262 
1263 void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
1264 {
1265  TRACE_CALL(__func__);
1266  GtkSettings *settings;
1267 
1268  settings = gtk_settings_get_default();
1269 
1270  if (gtk_switch_get_active(remminamain->switch_dark_mode))
1272  else
1275 
1276  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1277 }
1278 
1279 void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
1280 {
1281  TRACE_CALL(__func__);
1282  g_app_info_launch_default_for_uri("https://www.remmina.org", NULL, NULL);
1283 }
1284 
1285 void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
1286 {
1287  TRACE_CALL(__func__);
1288  g_app_info_launch_default_for_uri("https://gitlab.com/Remmina/Remmina/wikis/home", NULL, NULL);
1289 }
1290 
1291 void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
1292 {
1293  TRACE_CALL(__func__);
1294  g_app_info_launch_default_for_uri("https://remmina.org/community", NULL, NULL);
1295 }
1296 
1297 void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
1298 {
1299  TRACE_CALL(__func__);
1300  g_app_info_launch_default_for_uri("https://www.remmina.org/donations", NULL, NULL);
1301 }
1302 
1303 void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
1304 {
1305  TRACE_CALL(__func__);
1307 }
1308 
1309 void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
1310 {
1311  TRACE_CALL(__func__);
1312  remmina_about_open(remminamain->window);
1313 };
1314 
1315 static gboolean is_empty(const gchar *s)
1316 {
1317  if (s == NULL)
1318  return TRUE;
1319  while (*s != 0) {
1320  if (!isspace((unsigned char)*s))
1321  return FALSE;
1322  s++;
1323  }
1324  return TRUE;
1325 }
1326 
1327 static gboolean remmina_main_quickconnect(void)
1328 {
1329  TRACE_CALL(__func__);
1330  RemminaFile *remminafile;
1331  gchar *server;
1332  gchar *server_trimmed;
1333  gchar *qcp;
1334 
1335 
1336  /* Save quick connect protocol if different from the previous one */
1337  qcp = gtk_combo_box_text_get_active_text(remminamain->combo_quick_connect_protocol);
1338  if (qcp && strcmp(qcp, remmina_pref.last_quickconnect_protocol) != 0) {
1340  remmina_pref.last_quickconnect_protocol = g_strdup(qcp);
1342  }
1343 
1344  remminafile = remmina_file_new();
1345  server = g_strdup(gtk_entry_get_text(remminamain->entry_quick_connect_server));
1346  if (g_hostname_to_ascii(server) == NULL)
1347  return FALSE;
1348  /* If server contain /, e.g. vnc://, it won't connect
1349  * We could search for an array of invalid characters, but
1350  * it's better to find a way to correctly parse and validate addresses
1351  */
1352  if (g_strrstr(server, "/") != NULL)
1353  return FALSE;
1354  //if (g_str_has_suffix (server, "/"))
1355  //return FALSE;
1356  if (is_empty(server))
1357  return FALSE;
1358 
1359  /* check if server is an IP address and trim whitespace if so */
1360  server_trimmed = g_strdup(server);
1361  g_strstrip(server_trimmed);
1362  gchar **strings = g_strsplit(server_trimmed, ":", 2);
1363 
1364  if (strings[0] != NULL)
1365  if (g_hostname_is_ip_address(strings[0]))
1366  g_stpcpy(server, server_trimmed);
1367 
1368  remmina_file_set_string(remminafile, "sound", "off");
1369  remmina_file_set_string(remminafile, "server", server);
1370  remmina_file_set_string(remminafile, "name", server);
1371  remmina_file_set_string(remminafile, "protocol", qcp);
1372  g_free(server);
1373  g_free(server_trimmed);
1374  g_free(qcp);
1375 
1376  rcw_open_from_file(remminafile);
1377 
1378  return FALSE;
1379 }
1380 
1381 gboolean remmina_main_quickconnect_on_click(GtkWidget *widget, gpointer user_data)
1382 {
1383  TRACE_CALL(__func__);
1384  if (!kioskmode && kioskmode == FALSE)
1385  return remmina_main_quickconnect();
1386  return FALSE;
1387 }
1388 
1389 /* Select all the text inside the quick search box if there is anything */
1390 void remmina_main_quick_search_enter(GtkWidget *widget, gpointer user_data)
1391 {
1392  if (gtk_entry_get_text(remminamain->entry_quick_connect_server))
1393  gtk_editable_select_region(GTK_EDITABLE(remminamain->entry_quick_connect_server), 0, -1);
1394 }
1395 
1396 void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
1397 {
1398  TRACE_CALL(__func__);
1399  gtk_tree_view_collapse_all(remminamain->tree_files_list);
1400 }
1401 
1402 void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
1403 {
1404  TRACE_CALL(__func__);
1405  REMMINA_DEBUG("Search toggle triggered");
1406 
1407  gboolean toggle_status = gtk_toggle_button_get_active(remminamain->search_toggle);
1408 
1409  gtk_search_bar_set_search_mode(remminamain->search_bar, toggle_status);
1410  if (toggle_status) {
1411  REMMINA_DEBUG("Search toggle is active");
1412  gtk_widget_grab_focus(GTK_WIDGET(remminamain->entry_quick_connect_server));
1413  } else {
1414  REMMINA_DEBUG("Search toggle is not active, focus is tree_files_list");
1415  gtk_widget_grab_focus(GTK_WIDGET(remminamain->tree_files_list));
1416  }
1417 }
1418 
1420 {
1421  TRACE_CALL(__func__);
1422  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remminamain->search_toggle), TRUE);
1423 }
1424 
1425 void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
1426 {
1427  TRACE_CALL(__func__);
1428  gtk_tree_view_expand_all(remminamain->tree_files_list);
1429 }
1430 
1431 /* Handle double click on a row in the connections list */
1432 void remmina_main_file_list_on_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
1433 {
1434  TRACE_CALL(__func__);
1435 /* If a connection was selected then execute the default action */
1436  if (remminamain->priv->selected_filename) {
1437  switch (remmina_pref.default_action) {
1438  case REMMINA_ACTION_EDIT:
1439  remmina_main_on_action_connection_edit(NULL, NULL, NULL);
1440  break;
1442  default:
1444  break;
1445  }
1446  }
1447 }
1448 
1449 /* Show the popup menu by the right button mouse click */
1450 gboolean remmina_main_file_list_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1451 {
1452  TRACE_CALL(__func__);
1453  if (event->button == MOUSE_BUTTON_RIGHT) {
1454  if (!kioskmode && kioskmode == FALSE) {
1455 #if GTK_CHECK_VERSION(3, 22, 0)
1456  // For now, if more than one selected row, display only a delete menu option
1457  if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(remminamain->tree_files_list)) > 1) {
1458  gtk_menu_popup_at_pointer(GTK_MENU(remminamain->menu_popup_delete_rc), (GdkEvent *)event);
1459  return GDK_EVENT_STOP;
1460  }
1461  else {
1462  gtk_menu_popup_at_pointer(GTK_MENU(remminamain->menu_popup), (GdkEvent *)event);
1463  }
1464 #else
1465  gtk_menu_popup(remminamain->menu_popup, NULL, NULL, NULL, NULL, event->button, event->time);
1466 #endif
1467  }
1468  }
1469  return FALSE;
1470 }
1471 
1472 /* Show the popup menu by the menu key */
1473 gboolean remmina_main_file_list_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1474 {
1475  TRACE_CALL(__func__);
1476  if (event->keyval == GDK_KEY_Menu) {
1477 #if GTK_CHECK_VERSION(3, 22, 0)
1478  gtk_menu_popup_at_widget(GTK_MENU(remminamain->menu_popup), widget,
1479  GDK_GRAVITY_CENTER, GDK_GRAVITY_CENTER,
1480  (GdkEvent *)event);
1481 #else
1482  gtk_menu_popup(remminamain->menu_popup, NULL, NULL, NULL, NULL, 0, event->time);
1483 #endif
1484  }
1485  return FALSE;
1486 }
1487 
1488 void remmina_main_quick_search_on_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
1489 {
1490  TRACE_CALL(__func__);
1491  if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
1492  gtk_entry_set_text(entry, "");
1493 }
1494 
1495 void remmina_main_quick_search_on_changed(GtkEditable *editable, gpointer user_data)
1496 {
1497  TRACE_CALL(__func__);
1498  /* If a search text was input then temporary set the file mode to list */
1499  if (gtk_entry_get_text_length(remminamain->entry_quick_connect_server)) {
1500  if (GTK_IS_TREE_STORE(remminamain->priv->file_model)) {
1501  /* File view mode changed, put it to override and reload list */
1502  remminamain->priv->override_view_file_mode_to_list = TRUE;
1504  }
1505  } else {
1506  if (remminamain->priv->override_view_file_mode_to_list) {
1507  /* File view mode changed, put it to default (disable override) and reload list */
1508  remminamain->priv->override_view_file_mode_to_list = FALSE;
1510  }
1511  }
1512  gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(remminamain->priv->file_model_filter));
1513 }
1514 
1515 void remmina_main_on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y,
1516  GtkSelectionData *data, guint info, guint time, gpointer user_data)
1517 {
1518  TRACE_CALL(__func__);
1519  gchar **uris;
1520  GSList *files = NULL;
1521  gint i;
1522 
1523  uris = g_uri_list_extract_uris((const gchar *)gtk_selection_data_get_data(data));
1524  for (i = 0; uris[i]; i++) {
1525  if (strncmp(uris[i], "file://", 7) != 0)
1526  continue;
1527  files = g_slist_append(files, g_strdup(uris[i] + 7));
1528  }
1529  g_strfreev(uris);
1531 }
1532 
1533 /* Add a new menuitem to the Tools menu */
1534 static gboolean remmina_main_add_tool_plugin(gchar *name, RemminaPlugin *plugin, gpointer user_data)
1535 {
1536  TRACE_CALL(__func__);
1537  RemminaToolPlugin *tool_plugin = (RemminaToolPlugin *)plugin;
1538  GtkWidget *menuitem = gtk_menu_item_new_with_label(plugin->description);
1539 
1540  gtk_widget_show(menuitem);
1541  gtk_menu_shell_append(GTK_MENU_SHELL(remminamain->menu_popup_full), menuitem);
1542  g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(tool_plugin->exec_func), tool_plugin);
1543  return FALSE;
1544 }
1545 
1546 gboolean remmina_main_on_window_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
1547 {
1548  TRACE_CALL(__func__);
1549  return FALSE;
1550 }
1551 
1552 /* Remmina main window initialization */
1553 static void remmina_main_init(void)
1554 {
1555  TRACE_CALL(__func__);
1556  int i, qcp_idx, qcp_actidx;
1557  char *name;
1558  GtkSettings *settings;
1559 
1560  REMMINA_DEBUG("Initializing the Remmina main window");
1561  /* Switch to a dark theme if the user enabled it */
1562  settings = gtk_settings_get_default();
1563  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
1564 
1565  REMMINA_DEBUG ("Initializing monitor");
1566  remminamain->monitor = remmina_network_monitor_new();
1567 
1569  if (!kioskmode && kioskmode == FALSE)
1570  gtk_window_set_title(remminamain->window, _("Remmina Remote Desktop Client"));
1571  else
1572  gtk_window_set_title(remminamain->window, _("Remmina Kiosk"));
1573  if (!kioskmode && kioskmode == FALSE) {
1574  gtk_window_set_default_size(remminamain->window, remmina_pref.main_width, remmina_pref.main_height);
1576  gtk_window_maximize(remminamain->window);
1577  }
1578  /* Honor global preferences Search Bar visibility */
1580  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle")), FALSE);
1581 
1582  /* Add a GtkMenuItem to the Tools menu for each plugin of type REMMINA_PLUGIN_TYPE_TOOL */
1584 
1585  /* Add available quick connect protocols to remminamain->combo_quick_connect_protocol */
1586  qcp_idx = qcp_actidx = 0;
1587  for (i = 0; i < sizeof(quick_connect_plugin_list) / sizeof(quick_connect_plugin_list[0]); i++) {
1588  name = quick_connect_plugin_list[i];
1590  gtk_combo_box_text_append(remminamain->combo_quick_connect_protocol, name, name);
1592  qcp_actidx = qcp_idx;
1593  qcp_idx++;
1594  }
1595  }
1596  gtk_combo_box_set_active(GTK_COMBO_BOX(remminamain->combo_quick_connect_protocol), qcp_actidx);
1597 
1598  /* Connect the group accelerators to the GtkWindow */
1599  //gtk_window_add_accel_group(remminamain->window, remminamain->accelgroup_shortcuts);
1600  /* Set the Quick Connection */
1601  gtk_entry_set_activates_default(remminamain->entry_quick_connect_server, TRUE);
1602  /* Set the TreeView for the files list */
1603  gtk_tree_selection_set_select_function(
1604  gtk_tree_view_get_selection(remminamain->tree_files_list),
1605  remmina_main_selection_func, NULL, NULL);
1607  gtk_tree_view_set_search_entry(remminamain->tree_files_list, GTK_ENTRY(remminamain->entry_quick_connect_server));
1609  gtk_widget_grab_focus(GTK_WIDGET(remminamain->tree_files_list));
1610  /* Load the files list */
1612 
1613  /* Drag-n-drop support */
1614  gtk_drag_dest_set(GTK_WIDGET(remminamain->window), GTK_DEST_DEFAULT_ALL, remmina_drop_types, 1, GDK_ACTION_COPY);
1615 
1616  /* Finish initialization */
1617  remminamain->priv->initialized = TRUE;
1618 
1619  /* Register the window in remmina_widget_pool with GType=GTK_WINDOW and TAG=remmina-main-window */
1620  g_object_set_data(G_OBJECT(remminamain->window), "tag", "remmina-main-window");
1621  remmina_widget_pool_register(GTK_WIDGET(remminamain->window));
1622 }
1623 
1624 /* Signal handler for "show" on remminamain->window */
1625 void remmina_main_on_show(GtkWidget *w, gpointer user_data)
1626 {
1627  TRACE_CALL(__func__);
1628 #ifdef SNAP_BUILD
1630 #endif
1631 }
1632 
1633 /* RemminaMain instance */
1634 GtkWidget *remmina_main_new(void)
1635 {
1636  TRACE_CALL(__func__);
1637  GSimpleActionGroup *actions;
1638  GtkAccelGroup *accel_group = NULL;
1639 
1640  remminamain = g_new0(RemminaMain, 1);
1641  remminamain->priv = g_new0(RemminaMainPriv, 1);
1642  /* Assign UI widgets to the private members */
1643  remminamain->builder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_main.glade");
1644  remminamain->window = GTK_WINDOW(RM_GET_OBJECT("RemminaMain"));
1645  if (kioskmode && kioskmode == TRUE) {
1646  gtk_window_set_position(remminamain->window, GTK_WIN_POS_CENTER_ALWAYS);
1647  gtk_window_set_default_size(remminamain->window, 800, 400);
1648  gtk_window_set_resizable(remminamain->window, FALSE);
1649  }
1650  /* New Button */
1651  remminamain->button_new = GTK_BUTTON(RM_GET_OBJECT("button_new"));
1652  if (kioskmode && kioskmode == TRUE)
1653  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->button_new), FALSE);
1654  /* Search bar */
1655  remminamain->search_toggle = GTK_TOGGLE_BUTTON(RM_GET_OBJECT("search_toggle"));
1656  remminamain->search_bar = GTK_SEARCH_BAR(RM_GET_OBJECT("search_bar"));
1657  /* view mode list/tree */
1658  remminamain->view_toggle_button = GTK_TOGGLE_BUTTON(RM_GET_OBJECT("view_toggle_button"));
1659  if (kioskmode && kioskmode == TRUE)
1660  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->view_toggle_button), FALSE);
1661 
1662  /* Menu widgets */
1663  remminamain->menu_popup = GTK_MENU(RM_GET_OBJECT("menu_popup"));
1664  remminamain->menu_header_button = GTK_MENU_BUTTON(RM_GET_OBJECT("menu_header_button"));
1665  remminamain->menu_popup_full = GTK_MENU(RM_GET_OBJECT("menu_popup_full"));
1666  remminamain->menu_popup_delete_rc = GTK_MENU(RM_GET_OBJECT("menu_popup_delete_rc"));
1667  if (kioskmode && kioskmode == TRUE) {
1668  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->menu_popup_full), FALSE);
1669  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->menu_header_button), FALSE);
1670  }
1671  /* View mode radios */
1672  remminamain->menuitem_view_mode_list = GTK_RADIO_MENU_ITEM(RM_GET_OBJECT("menuitem_view_mode_list"));
1673  remminamain->menuitem_view_mode_tree = GTK_RADIO_MENU_ITEM(RM_GET_OBJECT("menuitem_view_mode_tree"));
1674  /* Quick connect objects */
1675  remminamain->box_quick_connect = GTK_BOX(RM_GET_OBJECT("box_quick_connect"));
1676  remminamain->combo_quick_connect_protocol = GTK_COMBO_BOX_TEXT(RM_GET_OBJECT("combo_quick_connect_protocol"));
1677  if (kioskmode && kioskmode == TRUE)
1678  gtk_widget_set_sensitive(GTK_WIDGET(remminamain->combo_quick_connect_protocol), FALSE);
1679  remminamain->entry_quick_connect_server = GTK_ENTRY(RM_GET_OBJECT("entry_quick_connect_server"));
1680  /* Other widgets */
1681  remminamain->tree_files_list = GTK_TREE_VIEW(RM_GET_OBJECT("tree_files_list"));
1682  remminamain->column_files_list_name = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_name"));
1683  remminamain->column_files_list_group = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_group"));
1684  remminamain->column_files_list_server = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_server"));
1685  remminamain->column_files_list_plugin = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_plugin"));
1686  remminamain->column_files_list_date = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_date"));
1687  remminamain->column_files_list_notes = GTK_TREE_VIEW_COLUMN(RM_GET_OBJECT("column_files_list_notes"));
1688  gtk_tree_view_column_set_fixed_width(remminamain->column_files_list_notes, 100);
1689  remminamain->statusbar_main = GTK_STATUSBAR(RM_GET_OBJECT("statusbar_main"));
1690  /* signals */
1691  g_signal_connect(remminamain->entry_quick_connect_server, "key-release-event", G_CALLBACK(remmina_main_search_key_event), NULL);
1692  g_signal_connect(remminamain->tree_files_list, "row-activated", G_CALLBACK(remmina_main_tree_row_activated), NULL);
1693  /* Non widget objects */
1694  actions = g_simple_action_group_new();
1695  g_action_map_add_action_entries(G_ACTION_MAP(actions), app_actions, G_N_ELEMENTS(app_actions), remminamain->window);
1696  gtk_widget_insert_action_group(GTK_WIDGET(remminamain->window), "app", G_ACTION_GROUP(actions));
1697  g_action_map_add_action_entries(G_ACTION_MAP(actions), main_actions, G_N_ELEMENTS(main_actions), remminamain->window);
1698  gtk_widget_insert_action_group(GTK_WIDGET(remminamain->window), "main", G_ACTION_GROUP(actions));
1699  g_object_unref(actions);
1700  /* Accelerators */
1701  accel_group = gtk_accel_group_new();
1702  gtk_window_add_accel_group(remminamain->window, accel_group);
1703  gtk_accel_group_connect(accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0,
1704  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_action_application_quit), NULL, NULL));
1705  // TODO: This crash remmina because the function doesn't receive the parameter we expect
1706  gtk_accel_group_connect(accel_group, GDK_KEY_P, GDK_CONTROL_MASK, 0,
1707  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_accel_application_preferences), NULL, NULL));
1708  gtk_accel_group_connect(accel_group, GDK_KEY_F, GDK_CONTROL_MASK, 0,
1709  g_cclosure_new_swap(G_CALLBACK(remmina_main_on_accel_search_toggle), remminamain, NULL));
1710 
1711  /* Connect signals */
1712  gtk_builder_connect_signals(remminamain->builder, NULL);
1713  /* Initialize the window and load the preferences */
1715  return GTK_WIDGET(remminamain->window);
1716 }
1717 
1719 {
1720  if (!remminamain)
1721  return NULL;
1722  if (!remminamain->priv)
1723  return NULL;
1724  if (!remminamain->priv->initialized)
1725  return NULL;
1726  remminamain->window = GTK_WINDOW(RM_GET_OBJECT("RemminaMain"));
1727  return remminamain->window;
1728 }
1729 
1731 {
1732  if (!remminamain)
1733  return;
1735 }
1736 
1737 void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar* message) {
1738  GtkWidget *dialog;
1739 
1740  if (remminamain->window) {
1741  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, msg, buttons, "%s", message);
1742  gtk_dialog_run(GTK_DIALOG(dialog));
1743  gtk_widget_destroy(dialog);
1744  }
1745 }
1746 
1747 void remmina_main_show_warning_dialog(const gchar *message) {
1748  GtkWidget *dialog;
1749 
1750  if (remminamain->window) {
1751  dialog = gtk_message_dialog_new(remminamain->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
1752  message, g_get_application_name());
1753  gtk_dialog_run(GTK_DIALOG(dialog));
1754  gtk_widget_destroy(dialog);
1755  }
1756 }
G_BEGIN_DECLS struct _RemminaGroupData RemminaGroupData
RemminaFile * remmina_file_load(const gchar *filename)
Definition: remmina_file.c:350
static RemminaSecretPlugin * remmina_secret_plugin
void remmina_log_start(void)
Definition: remmina_log.c:116
@@ -100,11 +100,11 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
GtkRadioMenuItem * menuitem_view_mode_list
Definition: remmina_main.h:56
static void remmina_main_load_file_tree_callback(RemminaFile *remminafile, gpointer user_data)
Definition: remmina_main.c:483
-
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
GtkWidget * network_icon
Definition: remmina_main.h:82
gint default_action
Definition: remmina_pref.h:141
static void remmina_main_show_snap_welcome()
Definition: remmina_main.c:272
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
gchar * selected_filename
Definition: remmina_main.h:96
GtkTreeModel * file_model
Definition: remmina_main.h:90
static void remmina_main_save_expanded_group(void)
Definition: remmina_main.c:164
@@ -126,7 +126,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
void remmina_widget_pool_register(GtkWidget *widget)
gchar * last_quickconnect_protocol
Definition: remmina_pref.h:227
-
gboolean remmina_main_file_list_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+
gboolean remmina_main_file_list_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
RemminaFile *(* import_func)(struct _RemminaFilePlugin *instance, const gchar *from_file)
Definition: plugin.h:108
static gboolean remmina_main_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
Definition: remmina_main.c:527
@@ -138,7 +138,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
RemminaFilePlugin * remmina_plugin_manager_get_import_file_handler(const gchar *file)
static gboolean remmina_main_search_key_event(GtkWidget *search_entry, GdkEventKey *event, gpointer user_data)
Definition: remmina_main.c:870
-
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
RemminaMonitor * remmina_network_monitor_new()
RemminaSecretPlugin * remmina_plugin_manager_get_secret_plugin(void)
@@ -158,8 +158,8 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gchar * remmina_file_get_datetime(RemminaFile *remminafile)
Return the string date of the last time a Remmina state file has been modified.
static void remmina_main_file_model_on_sort(GtkTreeSortable *sortable, gpointer user_data)
Definition: remmina_main.c:515
-
GtkWidget * remmina_main_new(void)
-
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
+
GtkWidget * remmina_main_new(void)
+
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
gint remmina_string_array_find(RemminaStringArray *array, const gchar *str)
gchar * remmina_string_array_to_string(RemminaStringArray *array)
GtkSwitch * switch_dark_mode
Definition: remmina_main.h:64
@@ -175,30 +175,30 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
static gboolean remmina_main_load_file_tree_find(GtkTreeModel *tree, GtkTreeIter *iter, const gchar *match_group)
Definition: remmina_main.c:455
gchar * selected_name
Definition: remmina_main.h:97
-
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
RemminaMonitor * monitor
Definition: remmina_main.h:86
gint main_sort_order
Definition: remmina_pref.h:221
-
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_load_files_cb(GtkEntry *entry, char *string, gpointer user_data)
Definition: remmina_main.c:762
-
gboolean remmina_main_on_window_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
+
gboolean remmina_main_on_window_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
-
void remmina_main_update_file_datetime(RemminaFile *file)
+
void remmina_main_update_file_datetime(RemminaFile *file)
GtkMenuButton * menu_header_button
Definition: remmina_main.h:53
static void remmina_main_load_file_tree_group(GtkTreeStore *store)
Definition: remmina_main.c:407
void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:910
void remmina_plugin_manager_show(GtkWindow *parent)
-
static void remmina_main_import_file_list(GSList *files)
+
static void remmina_main_import_file_list(GSList *files)
-
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
GtkMenu * menu_popup
Definition: remmina_main.h:52
gboolean remmina_main_idle_destroy(gpointer data)
Definition: remmina_main.c:235
static gboolean remmina_main_tree_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
Definition: remmina_main.c:881
-
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
+
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
gboolean initialized
Definition: remmina_main.h:94
@@ -207,11 +207,11 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gboolean prevent_snap_welcome_message
Definition: remmina_pref.h:226
gchar * expanded_group
Definition: remmina_pref.h:222
GtkBox * box_quick_connect
Definition: remmina_main.h:69
-
void remmina_main_on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer user_data)
+
void remmina_main_on_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer user_data)
GtkTreeViewColumn * column_files_list_server
Definition: remmina_main.h:77
-
void remmina_main_show_warning_dialog(const gchar *message)
+
void remmina_main_show_warning_dialog(const gchar *message)
void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:851
-
void remmina_main_quick_search_enter(GtkWidget *widget, gpointer user_data)
+
void remmina_main_quick_search_enter(GtkWidget *widget, gpointer user_data)
void remmina_file_delete(const gchar *filename)
Definition: remmina_file.c:909
GtkButton * button_new
Definition: remmina_main.h:60
GtkMenu * menu_popup_full
Definition: remmina_main.h:54
@@ -221,14 +221,14 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gboolean main_maximize
Definition: remmina_pref.h:219
GtkStatusbar * statusbar_main
Definition: remmina_main.h:81
GtkTreeViewColumn * column_files_list_plugin
Definition: remmina_main.h:78
-
void remmina_main_quick_search_on_changed(GtkEditable *editable, gpointer user_data)
-
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_quick_search_on_changed(GtkEditable *editable, gpointer user_data)
+
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
GtkBuilder * builder
Definition: remmina_main.h:49
GtkBuilder * remmina_public_gtk_builder_new_from_resource(gchar *resource)
void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:977
-
static gboolean is_empty(const gchar *s)
+
static gboolean is_empty(const gchar *s)
RemminaStringArray * remmina_string_array_new_from_string(const gchar *strs)
gboolean remmina_pref_get_boolean(const gchar *key)
gint view_file_mode
Definition: remmina_pref.h:213
@@ -237,17 +237,17 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
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)
-
static void remmina_main_init(void)
+
void remmina_main_on_show(GtkWidget *w, gpointer user_data)
+
static void remmina_main_init(void)
GtkTreeView * tree_files_list
Definition: remmina_main.h:74
static void remmina_main_select_file(const gchar *filename)
Definition: remmina_main.c:618
gboolean remmina_main_on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
Definition: remmina_main.c:225
-
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
GtkToggleButton * view_toggle_button
Definition: remmina_main.h:65
void remmina_main_destroy()
Definition: remmina_main.c:193
RemminaFile * remmina_file_new(void)
Definition: remmina_file.c:93
GtkTreeViewColumn * column_files_list_group
Definition: remmina_main.h:76
-
void remmina_main_file_list_on_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
+
void remmina_main_file_list_on_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
static void remmina_main_expand_group_traverse(GtkTreeIter *iter)
Definition: remmina_main.c:417
RemminaStringArray * expanded_group
Definition: remmina_main.h:99
static gboolean remmina_main_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer user_data)
Definition: remmina_main.c:322
@@ -255,17 +255,17 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
static void remmina_main_clear_selection_data(void)
Definition: remmina_main.c:261
void rcw_open_from_file(RemminaFile *remminafile)
Definition: rcw.c:4446
-
void remmina_main_on_date_column_sort_clicked()
+
void remmina_main_on_date_column_sort_clicked()
RemminaPref remmina_pref
Definition: rcw.c:79
-
gboolean remmina_main_file_list_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+
gboolean remmina_main_file_list_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
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_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)
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
-
static gboolean remmina_main_add_tool_plugin(gchar *name, RemminaPlugin *plugin, gpointer user_data)
+
static gboolean remmina_main_add_tool_plugin(gchar *name, RemminaPlugin *plugin, gpointer user_data)
@@ -276,7 +276,7 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
gboolean rcw_open_from_filename(const gchar *filename)
Definition: rcw.c:4398
static const gchar * supported_mime_types[]
Definition: remmina_main.c:87
-
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
gboolean(* export_func)(struct _RemminaFilePlugin *instance, RemminaFile *file, const gchar *to_file)
Definition: plugin.h:110
gboolean kioskmode
Definition: remmina.c:87
GtkWindow * window
Definition: remmina_main.h:50
@@ -285,14 +285,14 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
static char * quick_connect_plugin_list[]
Definition: remmina_main.c:131
void remmina_file_save(RemminaFile *remminafile)
Definition: remmina_file.c:728
GtkTreeViewColumn * column_files_list_notes
Definition: remmina_main.h:80
-
static gboolean remmina_main_quickconnect(void)
+
static gboolean remmina_main_quickconnect(void)
gboolean always_show_notes
Definition: remmina_pref.h:153
void remmina_string_array_add(RemminaStringArray *array, const gchar *str)
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)
-
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
+
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)
const gchar * remmina_file_get_icon_name(RemminaFile *remminafile)
Definition: remmina_file.c:883
@@ -303,24 +303,24 @@ $(document).ready(function(){initNavTree('remmina__main_8c_source.html','');});
GtkWidget * remmina_pref_dialog_new(gint default_tab, GtkWindow *parent)
GNode * remmina_file_manager_get_group_tree(void)
-
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
gboolean override_view_file_mode_to_list
Definition: remmina_main.h:98
-
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
static void remmina_main_file_editor_destroy(GtkWidget *widget, gpointer user_data)
Definition: remmina_main.c:805
gint remmina_file_manager_iterate(GFunc func, gpointer user_data)
gboolean dark_theme
Definition: remmina_pref.h:149
static void remmina_main_expand_group(void)
Definition: remmina_main.c:446
-
void remmina_main_quick_search_on_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
-
void remmina_main_on_accel_search_toggle(RemminaMain *remminamain)
+
void remmina_main_quick_search_on_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
+
void remmina_main_on_accel_search_toggle(RemminaMain *remminamain)
static void remmina_main_load_files()
Definition: remmina_main.c:646
GtkTreeViewColumn * column_files_list_date
Definition: remmina_main.h:79
-
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
-
static void remmina_main_action_tools_import_on_response(GtkDialog *dialog, gint response_id, gpointer user_data)
-
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
+
static void remmina_main_action_tools_import_on_response(GtkDialog *dialog, gint response_id, gpointer user_data)
+
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
static gboolean remmina_main_dexit(gpointer data)
Try to exit remmina after a delete window event.
Definition: remmina_main.c:218
-
gboolean remmina_main_quickconnect_on_click(GtkWidget *widget, gpointer user_data)
+
gboolean remmina_main_quickconnect_on_click(GtkWidget *widget, gpointer user_data)
diff --git a/public/remmina__main_8h.html b/public/remmina__main_8h.html index 4077a2e95..ef0ac5a7c 100644 --- a/public/remmina__main_8h.html +++ b/public/remmina__main_8h.html @@ -246,7 +246,7 @@ Functions
-

Definition at line 1716 of file remmina_main.c.

+

Definition at line 1718 of file remmina_main.c.

@@ -266,7 +266,7 @@ Functions
-

Definition at line 1632 of file remmina_main.c.

+

Definition at line 1634 of file remmina_main.c.

@@ -302,7 +302,7 @@ Functions
-

Definition at line 1306 of file remmina_main.c.

+

Definition at line 1309 of file remmina_main.c.

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

Definition at line 1260 of file remmina_main.c.

+

Definition at line 1263 of file remmina_main.c.

@@ -374,7 +374,7 @@ Functions
-

Definition at line 1112 of file remmina_main.c.

+

Definition at line 1115 of file remmina_main.c.

@@ -446,7 +446,7 @@ Functions
-

Definition at line 1254 of file remmina_main.c.

+

Definition at line 1257 of file remmina_main.c.

@@ -482,7 +482,7 @@ Functions
-

Definition at line 1086 of file remmina_main.c.

+

Definition at line 1091 of file remmina_main.c.

@@ -518,7 +518,7 @@ Functions
-

Definition at line 1140 of file remmina_main.c.

+

Definition at line 1143 of file remmina_main.c.

@@ -554,7 +554,7 @@ Functions
-

Definition at line 1393 of file remmina_main.c.

+

Definition at line 1396 of file remmina_main.c.

@@ -842,7 +842,7 @@ Functions
-

Definition at line 1423 of file remmina_main.c.

+

Definition at line 1425 of file remmina_main.c.

@@ -878,7 +878,7 @@ Functions
-

Definition at line 1288 of file remmina_main.c.

+

Definition at line 1291 of file remmina_main.c.

@@ -914,7 +914,7 @@ Functions
-

Definition at line 1300 of file remmina_main.c.

+

Definition at line 1303 of file remmina_main.c.

@@ -950,7 +950,7 @@ Functions
-

Definition at line 1294 of file remmina_main.c.

+

Definition at line 1297 of file remmina_main.c.

@@ -986,7 +986,7 @@ Functions
-

Definition at line 1276 of file remmina_main.c.

+

Definition at line 1279 of file remmina_main.c.

@@ -1022,7 +1022,7 @@ Functions
-

Definition at line 1282 of file remmina_main.c.

+

Definition at line 1285 of file remmina_main.c.

@@ -1058,7 +1058,7 @@ Functions
-

Definition at line 1399 of file remmina_main.c.

+

Definition at line 1402 of file remmina_main.c.

@@ -1094,7 +1094,7 @@ Functions
-

Definition at line 1225 of file remmina_main.c.

+

Definition at line 1228 of file remmina_main.c.

@@ -1130,7 +1130,7 @@ Functions
-

Definition at line 1213 of file remmina_main.c.

+

Definition at line 1216 of file remmina_main.c.

@@ -1230,7 +1230,7 @@ Functions
-

Definition at line 1735 of file remmina_main.c.

+

Definition at line 1737 of file remmina_main.c.

@@ -1250,7 +1250,7 @@ Functions
-

Definition at line 1745 of file remmina_main.c.

+

Definition at line 1747 of file remmina_main.c.

@@ -1270,7 +1270,7 @@ Functions
-

Definition at line 1728 of file remmina_main.c.

+

Definition at line 1730 of file remmina_main.c.

diff --git a/public/remmina__main_8h_source.html b/public/remmina__main_8h_source.html index e0f243b93..9bd1d24fa 100644 --- a/public/remmina__main_8h_source.html +++ b/public/remmina__main_8h_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('remmina__main_8h_source.html','');});
remmina_main.h
-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-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #pragma once
39 
40 #include "remmina_file.h"
41 #include "remmina_monitor.h"
42 #include <gtk/gtk.h>
43 
44 #include "remmina_string_array.h"
45 
47 
48 typedef struct _RemminaMain {
49  GtkBuilder * builder;
50  GtkWindow * window;
51  /* Menu widgets */
52  GtkMenu * menu_popup;
53  GtkMenuButton * menu_header_button;
54  GtkMenu * menu_popup_full;
56  GtkRadioMenuItem * menuitem_view_mode_list;
57  GtkRadioMenuItem * menuitem_view_mode_tree;
58  GtkMenuItem * menuitem_connection_quit;
59  /* Button new */
60  GtkButton * button_new;
61  GtkButton * button_make_default;
62  /* Search bar objects */
63  GtkToggleButton * search_toggle;
64  GtkSwitch * switch_dark_mode;
65  GtkToggleButton * view_toggle_button;
66  GtkToggleButton * ustats_toggle;
67  GtkSearchBar * search_bar;
68  /* Quick connect objects */
70  GtkComboBoxText * combo_quick_connect_protocol;
72  GtkButton * button_quick_connect;
73  /* Other widgets */
74  GtkTreeView * tree_files_list;
75  GtkTreeViewColumn * column_files_list_name;
76  GtkTreeViewColumn * column_files_list_group;
77  GtkTreeViewColumn * column_files_list_server;
78  GtkTreeViewColumn * column_files_list_plugin;
79  GtkTreeViewColumn * column_files_list_date;
80  GtkTreeViewColumn * column_files_list_notes;
81  GtkStatusbar * statusbar_main;
82  GtkWidget * network_icon;
83  /* Non widget objects */
84  GtkAccelGroup * accelgroup_shortcuts;
87 } RemminaMain;
88 
90  GtkTreeModel * file_model;
91  GtkTreeModel * file_model_filter;
92  GtkTreeModel * file_model_sort;
93 
94  gboolean initialized;
95 
97  gchar * selected_name;
100 };
101 
102 G_BEGIN_DECLS
103 
104 /* Create the remminamain struct and the remmina main Remmina window */
105 GtkWidget *remmina_main_new(void);
106 /* Get the current main GTK window or NULL if not initialized */
107 GtkWindow *remmina_main_get_window(void);
108 
110 
111 void remmina_main_destroy(void);
114 
115 void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar* message);
116 void remmina_main_show_warning_dialog(const gchar *message);
117 void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data);
118 void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data);
119 void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data);
120 void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data);
121 void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data);
122 void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data);
123 void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data);
124 void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data);
125 void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data);
126 void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data);
127 void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data);
128 void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data);
129 void remmina_main_on_action_connection_external_tools(GSimpleAction *action, GVariant *param, gpointer data);
130 void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data);
131 void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data);
132 void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data);
133 void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data);
134 void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data);
135 void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data);
136 void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data);
137 void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data);
138 void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data);
139 void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data);
140 void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data);
142 
143 G_END_DECLS
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
+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-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 #pragma once
39 
40 #include "remmina_file.h"
41 #include "remmina_monitor.h"
42 #include <gtk/gtk.h>
43 
44 #include "remmina_string_array.h"
45 
47 
48 typedef struct _RemminaMain {
49  GtkBuilder * builder;
50  GtkWindow * window;
51  /* Menu widgets */
52  GtkMenu * menu_popup;
53  GtkMenuButton * menu_header_button;
54  GtkMenu * menu_popup_full;
56  GtkRadioMenuItem * menuitem_view_mode_list;
57  GtkRadioMenuItem * menuitem_view_mode_tree;
58  GtkMenuItem * menuitem_connection_quit;
59  /* Button new */
60  GtkButton * button_new;
61  GtkButton * button_make_default;
62  /* Search bar objects */
63  GtkToggleButton * search_toggle;
64  GtkSwitch * switch_dark_mode;
65  GtkToggleButton * view_toggle_button;
66  GtkToggleButton * ustats_toggle;
67  GtkSearchBar * search_bar;
68  /* Quick connect objects */
70  GtkComboBoxText * combo_quick_connect_protocol;
72  GtkButton * button_quick_connect;
73  /* Other widgets */
74  GtkTreeView * tree_files_list;
75  GtkTreeViewColumn * column_files_list_name;
76  GtkTreeViewColumn * column_files_list_group;
77  GtkTreeViewColumn * column_files_list_server;
78  GtkTreeViewColumn * column_files_list_plugin;
79  GtkTreeViewColumn * column_files_list_date;
80  GtkTreeViewColumn * column_files_list_notes;
81  GtkStatusbar * statusbar_main;
82  GtkWidget * network_icon;
83  /* Non widget objects */
84  GtkAccelGroup * accelgroup_shortcuts;
87 } RemminaMain;
88 
90  GtkTreeModel * file_model;
91  GtkTreeModel * file_model_filter;
92  GtkTreeModel * file_model_sort;
93 
94  gboolean initialized;
95 
97  gchar * selected_name;
100 };
101 
102 G_BEGIN_DECLS
103 
104 /* Create the remminamain struct and the remmina main Remmina window */
105 GtkWidget *remmina_main_new(void);
106 /* Get the current main GTK window or NULL if not initialized */
107 GtkWindow *remmina_main_get_window(void);
108 
110 
111 void remmina_main_destroy(void);
114 
115 void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar* message);
116 void remmina_main_show_warning_dialog(const gchar *message);
117 void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data);
118 void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data);
119 void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data);
120 void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data);
121 void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data);
122 void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data);
123 void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data);
124 void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data);
125 void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data);
126 void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data);
127 void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data);
128 void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data);
129 void remmina_main_on_action_connection_external_tools(GSimpleAction *action, GVariant *param, gpointer data);
130 void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data);
131 void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data);
132 void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data);
133 void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data);
134 void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data);
135 void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data);
136 void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data);
137 void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data);
138 void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data);
139 void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data);
140 void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data);
142 
143 G_END_DECLS
void remmina_main_on_action_application_plugins(GSimpleAction *action, GVariant *param, gpointer data)
GtkToggleButton * search_toggle
Definition: remmina_main.h:63
GtkRadioMenuItem * menuitem_view_mode_list
Definition: remmina_main.h:56
GtkWidget * network_icon
Definition: remmina_main.h:82
@@ -97,7 +97,7 @@ $(document).ready(function(){initNavTree('remmina__main_8h_source.html','');});
GtkTreeModel * file_model
Definition: remmina_main.h:90
void remmina_main_destroy(void)
Definition: remmina_main.c:193
RemminaMainPriv * priv
Definition: remmina_main.h:85
-
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_homepage(GSimpleAction *action, GVariant *param, gpointer data)
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
GtkMenuItem * menuitem_connection_quit
Definition: remmina_main.h:58
GtkRadioMenuItem * menuitem_view_mode_tree
Definition: remmina_main.h:57
@@ -105,23 +105,23 @@ $(document).ready(function(){initNavTree('remmina__main_8h_source.html','');});
GtkMenu * menu_popup_delete_rc
Definition: remmina_main.h:55
-
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_expand(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_debug(GSimpleAction *action, GVariant *param, gpointer data)
void remmina_main_on_action_connection_copy(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:910
-
G_BEGIN_DECLS GtkWidget * remmina_main_new(void)
-
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
+
G_BEGIN_DECLS GtkWidget * remmina_main_new(void)
+
void remmina_main_on_action_tools_import(GSimpleAction *action, GVariant *param, gpointer data)
GtkSwitch * switch_dark_mode
Definition: remmina_main.h:64
GtkAccelGroup * accelgroup_shortcuts
Definition: remmina_main.h:84
-
void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_dark_theme(GSimpleAction *action, GVariant *param, gpointer data)
GtkTreeModel * file_model_filter
Definition: remmina_main.h:91
gchar * selected_name
Definition: remmina_main.h:97
RemminaMonitor * monitor
Definition: remmina_main.h:86
void remmina_main_on_action_connection_delete(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:977
-
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_about(GSimpleAction *action, GVariant *param, gpointer data)
GtkMenuButton * menu_header_button
Definition: remmina_main.h:53
-
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
-
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
-
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
+
void remmina_main_on_action_search_toggle(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_preferences(GSimpleAction *action, GVariant *param, gpointer data)
GtkMenu * menu_popup
Definition: remmina_main.h:52
void remmina_main_reload_preferences()
@@ -130,7 +130,7 @@ $(document).ready(function(){initNavTree('remmina__main_8h_source.html','');});
void remmina_main_on_action_connection_delete_multiple(GSimpleAction *action, GVariant *param, gpointer data)
GtkBox * box_quick_connect
Definition: remmina_main.h:69
GtkTreeViewColumn * column_files_list_server
Definition: remmina_main.h:77
-
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_community(GSimpleAction *action, GVariant *param, gpointer data)
GtkButton * button_new
Definition: remmina_main.h:60
GtkMenu * menu_popup_full
Definition: remmina_main.h:54
GtkStatusbar * statusbar_main
Definition: remmina_main.h:81
@@ -140,30 +140,30 @@ $(document).ready(function(){initNavTree('remmina__main_8h_source.html','');});
GtkBuilder * builder
Definition: remmina_main.h:49
GtkButton * button_quick_connect
Definition: remmina_main.h:72
-
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
-
GtkWindow * remmina_main_get_window(void)
+
void remmina_main_on_action_tools_export(GSimpleAction *action, GVariant *param, gpointer data)
+
GtkWindow * remmina_main_get_window(void)
void remmina_main_on_action_application_mpchange(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:814
GtkTreeView * tree_files_list
Definition: remmina_main.h:74
GtkToggleButton * view_toggle_button
Definition: remmina_main.h:65
GtkTreeViewColumn * column_files_list_group
Definition: remmina_main.h:76
RemminaStringArray * expanded_group
Definition: remmina_main.h:99
void remmina_main_on_action_connection_edit(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:946
-
void remmina_main_show_warning_dialog(const gchar *message)
-
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_show_warning_dialog(const gchar *message)
+
void remmina_main_on_action_application_default(GSimpleAction *action, GVariant *param, gpointer data)
GtkTreeModel * file_model_sort
Definition: remmina_main.h:92
-
void remmina_main_update_file_datetime(RemminaFile *file)
+
void remmina_main_update_file_datetime(RemminaFile *file)
void remmina_main_on_action_connection_connect(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:768
GtkWindow * window
Definition: remmina_main.h:50
-
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_application_quit(GSimpleAction *action, GVariant *param, gpointer data)
GtkToggleButton * ustats_toggle
Definition: remmina_main.h:66
void remmina_main_on_action_connection_new(GSimpleAction *action, GVariant *param, gpointer data)
Definition: remmina_main.c:851
-
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_collapse(GSimpleAction *action, GVariant *param, gpointer data)
GtkButton * button_make_default
Definition: remmina_main.h:61
-
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_donations(GSimpleAction *action, GVariant *param, gpointer data)
GtkTreeViewColumn * column_files_list_notes
Definition: remmina_main.h:80
GtkSearchBar * search_bar
Definition: remmina_main.h:67
GtkEntry * entry_quick_connect_server
Definition: remmina_main.h:71
-
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
+
void remmina_main_on_action_help_wiki(GSimpleAction *action, GVariant *param, gpointer data)
gboolean override_view_file_mode_to_list
Definition: remmina_main.h:98
struct _RemminaMain RemminaMain
diff --git a/public/remmina__mpchange_8c_source.html b/public/remmina__mpchange_8c_source.html index 23fd27647..9f34cd8a4 100644 --- a/public/remmina__mpchange_8c_source.html +++ b/public/remmina__mpchange_8c_source.html @@ -93,7 +93,7 @@ $(document).ready(function(){initNavTree('remmina__mpchange_8c_source.html','');
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:516
guint searchentrychange_timeout_source_id
static void remmina_mpchange_stopsearch(GtkSearchEntry *entry, gpointer user_data)
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
GtkEntry * eGatewayPassword2
diff --git a/public/remmina__plugin__manager_8c_source.html b/public/remmina__plugin__manager_8c_source.html index 8fbaadad6..d08b9a7f0 100644 --- a/public/remmina__plugin__manager_8c_source.html +++ b/public/remmina__plugin__manager_8c_source.html @@ -101,7 +101,7 @@ $(document).ready(function(){initNavTree('remmina__plugin__manager_8c_source.htm
static void htdestroy(gpointer ht)
gchar * remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
Start an SSH tunnel if possible and return the host:port string.
-
GtkWindow * remmina_main_get_window()
+
GtkWindow * remmina_main_get_window()
void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
gboolean remmina_plugin_native_load(RemminaPluginService *service, const char *name)
@@ -173,7 +173,7 @@ $(document).ready(function(){initNavTree('remmina__plugin__manager_8c_source.htm
void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
RemminaPluginService remmina_plugin_manager_service
static const gchar * remmina_plugin_type_name[]
-
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
+
void remmina_main_show_dialog(GtkMessageType msg, GtkButtonsType buttons, const gchar *message)
void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
RemminaProtocolFeatureType type
Definition: types.h:73
-- cgit v1.2.3