From 96e67f6598fef8b9c8a879585f09ebc73076e3db Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Tue, 15 Aug 2023 13:52:05 +0000 Subject: Automatic doc build by remmina-ci --- public/functions_u.html | 3 + public/functions_vars_u.html | 3 + public/globals_c.html | 7 +- public/globals_func_c.html | 3 + public/globals_r.html | 16 +- public/navtreedata.js | 20 +- public/navtreeindex0.js | 2 +- public/navtreeindex10.js | 4 +- public/navtreeindex11.js | 6 +- public/navtreeindex12.js | 4 +- public/navtreeindex13.js | 4 +- public/navtreeindex14.js | 10 +- public/navtreeindex15.js | 6 +- public/navtreeindex16.js | 6 +- public/navtreeindex17.js | 6 +- public/navtreeindex18.js | 2 + public/navtreeindex8.js | 208 +++++++------- public/navtreeindex9.js | 4 +- public/plugin_8h_source.html | 2 +- public/rcw_8c_source.html | 62 ++-- public/remmina__masterthread__exec_8c_source.html | 14 +- public/remmina__plugin__manager_8c_source.html | 98 +++---- public/remmina__protocol__widget_8c.html | 260 +++++++++-------- public/remmina__protocol__widget_8c.js | 1 + public/remmina__protocol__widget_8c_source.html | 313 +++++++++++---------- public/remmina__protocol__widget_8h.html | 150 +++++----- public/remmina__protocol__widget_8h_source.html | 158 +++++------ public/remmina__ssh_8c_source.html | 12 +- public/remmina__ssh__plugin_8c_source.html | 2 +- public/search/all_12.js | 6 +- public/search/all_15.js | 1 + public/search/all_3.js | 1 + public/search/functions_3.js | 1 + public/search/variables_14.js | 1 + public/struct___remmina_protocol_widget_priv.html | 58 ++-- public/struct___remmina_protocol_widget_priv.js | 1 + ...ruct___remmina_protocol_widget_signal_data.html | 6 +- public/struct_mp_run_info.html | 10 +- ...ina__protocol__widget__dialog__mt__data__t.html | 26 +- 39 files changed, 789 insertions(+), 708 deletions(-) diff --git a/public/functions_u.html b/public/functions_u.html index fc3646469..a03150f0f 100644 --- a/public/functions_u.html +++ b/public/functions_u.html @@ -161,6 +161,9 @@ $(document).ready(function(){initNavTree('functions_u.html','');});
  • user_data : _RemminaSSHShell
  • +
  • user_disconnect +: _RemminaProtocolWidgetPriv +
  • username : _ConnectionData , _RemminaProtocolWidgetPriv diff --git a/public/functions_vars_u.html b/public/functions_vars_u.html index 3cdb689b9..2e27b88bb 100644 --- a/public/functions_vars_u.html +++ b/public/functions_vars_u.html @@ -161,6 +161,9 @@ $(document).ready(function(){initNavTree('functions_vars_u.html','');});
  • user_data : _RemminaSSHShell
  • +
  • user_disconnect +: _RemminaProtocolWidgetPriv +
  • username : _ConnectionData , _RemminaProtocolWidgetPriv diff --git a/public/globals_c.html b/public/globals_c.html index 5400be516..338fe28ad 100644 --- a/public/globals_c.html +++ b/public/globals_c.html @@ -161,9 +161,9 @@ $(document).ready(function(){initNavTree('globals_c.html','');}); : remmina_ssh_plugin.c
  • colordepth_list -: vnc_plugin.c +: rdp_plugin.c , gvnc_plugin.c -, rdp_plugin.c +, vnc_plugin.c
  • common_identities : remmina_ssh.c @@ -183,6 +183,9 @@ $(document).ready(function(){initNavTree('globals_c.html','');});
  • conn_closed() : remmina_protocol_widget.c
  • +
  • conn_closed_real() +: remmina_protocol_widget.c +
  • conn_opened() : remmina_protocol_widget.c
  • diff --git a/public/globals_func_c.html b/public/globals_func_c.html index 13a67f832..7830cb616 100644 --- a/public/globals_func_c.html +++ b/public/globals_func_c.html @@ -139,6 +139,9 @@ $(document).ready(function(){initNavTree('globals_func_c.html','');});
  • conn_closed() : remmina_protocol_widget.c
  • +
  • conn_closed_real() +: remmina_protocol_widget.c +
  • conn_opened() : remmina_protocol_widget.c
  • diff --git a/public/globals_r.html b/public/globals_r.html index 44f46c019..17b219125 100644 --- a/public/globals_r.html +++ b/public/globals_r.html @@ -4329,18 +4329,18 @@ $(document).ready(function(){initNavTree('globals_r.html','');});
  • remmina_ssh_tunnel_new_from_file() : remmina_ssh.h
  • -
  • REMMINA_SSH_TUNNEL_OPEN -: remmina_ssh.h -
  • remmina_ssh_tunnel_open() : remmina_ssh.h
  • -
  • remmina_ssh_tunnel_reverse() -: remmina_ssh.h +
  • REMMINA_SSH_TUNNEL_OPEN +: remmina_ssh.h
  • REMMINA_SSH_TUNNEL_REVERSE : remmina_ssh.h
  • +
  • remmina_ssh_tunnel_reverse() +: remmina_ssh.h +
  • remmina_ssh_tunnel_terminated() : remmina_ssh.h
  • @@ -4859,12 +4859,12 @@ $(document).ready(function(){initNavTree('globals_r.html','');});
  • RemminaLogWindowClass : remmina_log.c
  • -
  • remminamain -: remmina_main.c -
  • RemminaMain : remmina_main.h
  • +
  • remminamain +: remmina_main.c +
  • RemminaMainPriv : remmina_main.h
  • diff --git a/public/navtreedata.js b/public/navtreedata.js index 6d81be21b..36eafb83a 100644 --- a/public/navtreedata.js +++ b/public/navtreedata.js @@ -96,16 +96,16 @@ var NAVTREEINDEX = "remmina__ftp__client_8c.html#a3872b49a2c0bea73d51d0500c5cee488", "remmina__main_8c.html#aace9ecdd0b74d392ad6ed541bd605c1c", "remmina__pref_8c.html", -"remmina__protocol__widget_8h.html#a172fa9cf2ce196c9846a3e47ea9036b4", -"remmina__ssh_8c.html#abc556f0a4335083436f6e19c204fa553", -"remmina__utils_8c_source.html", -"struct___remmina_color_pref.html#a5ae99dc78a80baa14e0407983077c500", -"struct___remmina_plugin_service.html#a434bf35a11eea8a5b653ffd8c7823d84", -"struct___remmina_pref.html#a901034949132f369eb34c4f1ded3a0a6", -"struct___remmina_s_f_t_p_client.html#a95d95acad60636dd6c45ca93620d1f5b", -"structlsb__distro__info.html", -"structrf__context.html#aa79909e0ac140a3404151a40bed6a6ec", -"www__plugin_8c.html#a98eddc35144b89bce2e247d5ea49177b" +"remmina__protocol__widget_8h.html#a1585ea6908dd5c0a9b0f47d409916435", +"remmina__ssh_8c.html#ab8f07d5ab2ee8aa8423a11808b6cb100", +"remmina__utils_8c.html#aff7d3597f23cae366973218cc01a2ae8", +"struct___remmina_color_pref.html#a4ad947d133d2aa2c94756aacb5031e79", +"struct___remmina_plugin_service.html#a42ca6bc7a62f91efdba93cde19b347ce", +"struct___remmina_pref.html#a8edfd2a9a9a06b1fd876fbe8742b9ff6", +"struct___remmina_s_f_t_p_client.html#a42cfd0524388c2c05ea4b926dbe966e1", +"structitem.html#a975a1b37d9e003e1abb2a505474894b5", +"structrf__context.html#aa13bb4f72f3024d81e9051de4bd65ec0", +"www__plugin_8c.html#a9323d1142816fbac8f87545a398a0f71" ]; var SYNCONMSG = 'click to disable panel synchronisation'; diff --git a/public/navtreeindex0.js b/public/navtreeindex0.js index 9e5ccdcfe..ca4c0c095 100644 --- a/public/navtreeindex0.js +++ b/public/navtreeindex0.js @@ -161,8 +161,8 @@ var NAVTREEINDEX0 = "globals_type.html":[61,1,3], "globals_u.html":[61,1,0,21], "globals_v.html":[61,1,0,22], -"globals_vars.html":[61,1,2,0], "globals_vars.html":[61,1,2], +"globals_vars.html":[61,1,2,0], "globals_vars_a.html":[61,1,2,1], "globals_vars_b.html":[61,1,2,2], "globals_vars_c.html":[61,1,2,3], diff --git a/public/navtreeindex10.js b/public/navtreeindex10.js index 981cc8036..cce8cd9cd 100644 --- a/public/navtreeindex10.js +++ b/public/navtreeindex10.js @@ -1,5 +1,6 @@ var NAVTREEINDEX10 = { +"remmina__ssh_8c.html#ab8f07d5ab2ee8aa8423a11808b6cb100":[61,0,133,26], "remmina__ssh_8c.html#abc556f0a4335083436f6e19c204fa553":[61,0,133,21], "remmina__ssh_8c.html#ad6f3f5c196175412049af0c440414e65":[61,0,133,7], "remmina__ssh_8c.html#adfe0e9338fec4a1c03677595c15514d1":[61,0,133,18], @@ -248,6 +249,5 @@ var NAVTREEINDEX10 = "remmina__utils_8c.html#ac804e6111e538ee2fa425b8b6fd1fb66":[61,0,149,18], "remmina__utils_8c.html#ae4318060ee81f8fbd907904892dd71d3":[61,0,149,20], "remmina__utils_8c.html#af1acfeca84e3efd47ab1ef8365f94f99":[61,0,149,14], -"remmina__utils_8c.html#afe83bd0997a1054045e17d3f66c8bb0d":[61,0,149,19], -"remmina__utils_8c.html#aff7d3597f23cae366973218cc01a2ae8":[61,0,149,4] +"remmina__utils_8c.html#afe83bd0997a1054045e17d3f66c8bb0d":[61,0,149,19] }; diff --git a/public/navtreeindex11.js b/public/navtreeindex11.js index a534a92c9..65d135ea0 100644 --- a/public/navtreeindex11.js +++ b/public/navtreeindex11.js @@ -1,5 +1,6 @@ var NAVTREEINDEX11 = { +"remmina__utils_8c.html#aff7d3597f23cae366973218cc01a2ae8":[61,0,149,4], "remmina__utils_8c_source.html":[61,0,149], "remmina__utils_8h.html":[61,0,150], "remmina__utils_8h.html#a0f10e190a6dd212fcb0cf36ce81c8324":[61,0,150,5], @@ -97,8 +98,8 @@ var NAVTREEINDEX11 = "src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159":[61,0,16,12], "src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159a6ca21e5d81f80ca35b556f92f5ca35cc":[61,0,16,12,0], "src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159a6ca21e5d81f80ca35b556f92f5ca35cc":[61,0,17,12,0], -"src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159a9ed2edb74e687da7e752fd9968eece34":[61,0,16,12,1], "src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159a9ed2edb74e687da7e752fd9968eece34":[61,0,17,12,1], +"src_2pygobject_8h.html#a18eca93aad557c40e8a75b655961b159a9ed2edb74e687da7e752fd9968eece34":[61,0,16,12,1], "src_2pygobject_8h.html#a2fa9a05e0ca89774ce56238aa81a6cac":[61,0,16,14], "src_2pygobject_8h.html#a31a009f7ec59c55c3ad1fe73343e543f":[61,0,16,15], "src_2pygobject_8h.html#a4710f3c87d09751239a9ea9cd8fd4e15":[61,0,16,13], @@ -248,6 +249,5 @@ var NAVTREEINDEX11 = "struct___remmina_color_pref.html#a2a14fc38e73351f9009fe155dd859808":[60,0,15,1], "struct___remmina_color_pref.html#a2d0facd5a0480a450d525ce9ef4fed60":[60,0,15,12], "struct___remmina_color_pref.html#a3a897d3fdc112fd9f96d2363f4094fc4":[60,0,15,9], -"struct___remmina_color_pref.html#a3f12bdb761d7c3ee02c0871aa423bcd1":[60,0,15,17], -"struct___remmina_color_pref.html#a4ad947d133d2aa2c94756aacb5031e79":[60,0,15,7] +"struct___remmina_color_pref.html#a3f12bdb761d7c3ee02c0871aa423bcd1":[60,0,15,17] }; diff --git a/public/navtreeindex12.js b/public/navtreeindex12.js index 827cad889..27194f681 100644 --- a/public/navtreeindex12.js +++ b/public/navtreeindex12.js @@ -1,5 +1,6 @@ var NAVTREEINDEX12 = { +"struct___remmina_color_pref.html#a4ad947d133d2aa2c94756aacb5031e79":[60,0,15,7], "struct___remmina_color_pref.html#a5ae99dc78a80baa14e0407983077c500":[60,0,15,18], "struct___remmina_color_pref.html#a5d92875f0034e5fc3d360d97d5992bd4":[60,0,15,15], "struct___remmina_color_pref.html#a675a8004488715429fa540dffb330d49":[60,0,15,0], @@ -248,6 +249,5 @@ var NAVTREEINDEX12 = "struct___remmina_plugin_service.html#a387f974b25c4164811f661128e200c8c":[60,0,43,34], "struct___remmina_plugin_service.html#a3e05115143ed8a545605a25a497a2db5":[60,0,43,93], "struct___remmina_plugin_service.html#a402cb9bb28e67cec7f643968767453cb":[60,0,43,117], -"struct___remmina_plugin_service.html#a40855f4643654a7f2a88f72008ea0b5e":[60,0,43,91], -"struct___remmina_plugin_service.html#a42ca6bc7a62f91efdba93cde19b347ce":[60,0,43,122] +"struct___remmina_plugin_service.html#a40855f4643654a7f2a88f72008ea0b5e":[60,0,43,91] }; diff --git a/public/navtreeindex13.js b/public/navtreeindex13.js index 58e5d7a27..a1a673649 100644 --- a/public/navtreeindex13.js +++ b/public/navtreeindex13.js @@ -1,5 +1,6 @@ var NAVTREEINDEX13 = { +"struct___remmina_plugin_service.html#a42ca6bc7a62f91efdba93cde19b347ce":[60,0,43,122], "struct___remmina_plugin_service.html#a434bf35a11eea8a5b653ffd8c7823d84":[60,0,43,98], "struct___remmina_plugin_service.html#a45416583767fafcac3fe3a9ac50d400f":[60,0,43,105], "struct___remmina_plugin_service.html#a4558dbff70064da3de58a6d684611fad":[60,0,43,68], @@ -248,6 +249,5 @@ var NAVTREEINDEX13 = "struct___remmina_pref.html#a7c139ee405d50330b1d9bfb646c0258c":[60,0,54,9], "struct___remmina_pref.html#a85e3d3ef34fb8969211860df159a04d8":[60,0,54,7], "struct___remmina_pref.html#a887cbbd379d159cd0ac1acea7173d07b":[60,0,54,52], -"struct___remmina_pref.html#a8cbf300dc913d51365c93f928e0d02fd":[60,0,54,24], -"struct___remmina_pref.html#a8edfd2a9a9a06b1fd876fbe8742b9ff6":[60,0,54,34] +"struct___remmina_pref.html#a8cbf300dc913d51365c93f928e0d02fd":[60,0,54,24] }; diff --git a/public/navtreeindex14.js b/public/navtreeindex14.js index e98a3db2c..3a3f82ae0 100644 --- a/public/navtreeindex14.js +++ b/public/navtreeindex14.js @@ -1,5 +1,6 @@ var NAVTREEINDEX14 = { +"struct___remmina_pref.html#a8edfd2a9a9a06b1fd876fbe8742b9ff6":[60,0,54,34], "struct___remmina_pref.html#a901034949132f369eb34c4f1ded3a0a6":[60,0,54,84], "struct___remmina_pref.html#a90e0cfac442b9e50e0f4857b3ff74255":[60,0,54,83], "struct___remmina_pref.html#a920221c2f304bfa278d0944bbbb6e011":[60,0,54,10], @@ -220,13 +221,14 @@ var NAVTREEINDEX14 = "struct___remmina_protocol_widget_priv.html#a2c5f3bd1f990157bef034920db49dc6e":[60,0,64,1], "struct___remmina_protocol_widget_priv.html#a37bd29fa334e378eff4367d61ee59e05":[60,0,64,4], "struct___remmina_protocol_widget_priv.html#a41a28954660d2d3816630e2ef9bb4211":[60,0,64,14], -"struct___remmina_protocol_widget_priv.html#a5cbea00dcc608759fcf66186e6afde93":[60,0,64,28], +"struct___remmina_protocol_widget_priv.html#a5cbea00dcc608759fcf66186e6afde93":[60,0,64,29], "struct___remmina_protocol_widget_priv.html#a6a24677077c069fbbb1f17e747530e1b":[60,0,64,0], "struct___remmina_protocol_widget_priv.html#a708ea5b5a9d1f5dcc5ab5bfb3d1a8483":[60,0,64,7], "struct___remmina_protocol_widget_priv.html#a70cdb4f879e8bb26b23d05cbbe685640":[60,0,64,15], "struct___remmina_protocol_widget_priv.html#a75d5f7d146f04132de722d0b7d09bb7d":[60,0,64,11], "struct___remmina_protocol_widget_priv.html#a7c8675e38544a9c393b560b31d165791":[60,0,64,23], "struct___remmina_protocol_widget_priv.html#a8700f21cfca6167fc9c4abe37c2d99b6":[60,0,64,6], +"struct___remmina_protocol_widget_priv.html#a8fc83f0db5c5d5d8fad8467d96e35642":[60,0,64,27], "struct___remmina_protocol_widget_priv.html#a93da102535413a0b3b1b740b582444ca":[60,0,64,19], "struct___remmina_protocol_widget_priv.html#a94ef3b8e64d6ced7cd639b7917026f4c":[60,0,64,25], "struct___remmina_protocol_widget_priv.html#aa37ce53d4329aaaa7c4059c60882a533":[60,0,64,24], @@ -236,7 +238,7 @@ var NAVTREEINDEX14 = "struct___remmina_protocol_widget_priv.html#ac613cf4b362b9dfc25e66f9d265e9326":[60,0,64,13], "struct___remmina_protocol_widget_priv.html#aca49dce014d8471be0d3cfe29cc7a35d":[60,0,64,10], "struct___remmina_protocol_widget_priv.html#acad26c8fddd63360e26ecc99b0d57be4":[60,0,64,22], -"struct___remmina_protocol_widget_priv.html#ae3feb5e5dad00109813fac890d913885":[60,0,64,27], +"struct___remmina_protocol_widget_priv.html#ae3feb5e5dad00109813fac890d913885":[60,0,64,28], "struct___remmina_protocol_widget_priv.html#ae76f074f8613e3f3b01c26eb3ce194f0":[60,0,64,5], "struct___remmina_protocol_widget_priv.html#af72272c7e2f45d61130ab4e57eb86380":[60,0,64,12], "struct___remmina_protocol_widget_priv.html#af9db6b4306852214f3dc2cdc06a635b4":[60,0,64,2], @@ -247,7 +249,5 @@ var NAVTREEINDEX14 = "struct___remmina_s_f_t_p.html#a7dab48a7603f1dd6671a8dd1efe1958e":[60,0,69,1], "struct___remmina_s_f_t_p.html#adef92bcfa7b9a86debf0531d0239a5df":[60,0,69,0], "struct___remmina_s_f_t_p_client.html":[60,0,70], -"struct___remmina_s_f_t_p_client.html#a1f66c9db34816532a1c12de30c57f210":[60,0,70,1], -"struct___remmina_s_f_t_p_client.html#a42cfd0524388c2c05ea4b926dbe966e1":[60,0,70,0], -"struct___remmina_s_f_t_p_client.html#a6c056e13ab45261dc4f07720910f3270":[60,0,70,3] +"struct___remmina_s_f_t_p_client.html#a1f66c9db34816532a1c12de30c57f210":[60,0,70,1] }; diff --git a/public/navtreeindex15.js b/public/navtreeindex15.js index 155e77df9..80da818c9 100644 --- a/public/navtreeindex15.js +++ b/public/navtreeindex15.js @@ -1,5 +1,7 @@ var NAVTREEINDEX15 = { +"struct___remmina_s_f_t_p_client.html#a42cfd0524388c2c05ea4b926dbe966e1":[60,0,70,0], +"struct___remmina_s_f_t_p_client.html#a6c056e13ab45261dc4f07720910f3270":[60,0,70,3], "struct___remmina_s_f_t_p_client.html#a95d95acad60636dd6c45ca93620d1f5b":[60,0,70,4], "struct___remmina_s_f_t_p_client.html#ab74654f5e47c939e1098c183a582023c":[60,0,70,2], "struct___remmina_s_f_t_p_client.html#ad6c612bb5172905eb63bfd5b672e1875":[60,0,70,5], @@ -247,7 +249,5 @@ var NAVTREEINDEX15 = "structitem.html#a1bfbfa35087440a4b217fd9fa4466bdb":[60,0,85,5], "structitem.html#a38ed39bc82590b07b2746c48a2eef262":[60,0,85,4], "structitem.html#a456c6639914adbd3be8b4da351775d04":[60,0,85,0], -"structitem.html#a86aaa250b539e47685bae65032af9ce7":[60,0,85,2], -"structitem.html#a975a1b37d9e003e1abb2a505474894b5":[60,0,85,3], -"structitem.html#adb779965c903bb950d429e90ebce3162":[60,0,85,1] +"structitem.html#a86aaa250b539e47685bae65032af9ce7":[60,0,85,2] }; diff --git a/public/navtreeindex16.js b/public/navtreeindex16.js index 206f65b33..40104faac 100644 --- a/public/navtreeindex16.js +++ b/public/navtreeindex16.js @@ -1,5 +1,7 @@ var NAVTREEINDEX16 = { +"structitem.html#a975a1b37d9e003e1abb2a505474894b5":[60,0,85,3], +"structitem.html#adb779965c903bb950d429e90ebce3162":[60,0,85,1], "structlsb__distro__info.html":[60,0,86], "structlsb__distro__info.html#a251763a49054183774e2082595537e47":[60,0,86,0], "structlsb__distro__info.html#a7aba92d963bcaed1a5dda7b7be4fa6d7":[60,0,86,1], @@ -247,7 +249,5 @@ var NAVTREEINDEX16 = "structrf__context.html#aa0aafcfa61ad736204a06281153f0a5da0b7e911f34ade078b572b43780fc6982":[60,0,113,2], "structrf__context.html#aa0aafcfa61ad736204a06281153f0a5da2266700ffb95b7f2c38eea7294f6fba6":[60,0,113,1], "structrf__context.html#aa0aafcfa61ad736204a06281153f0a5da6fd8f1c40304866e0168e9d496c26a68":[60,0,113,0], -"structrf__context.html#aa0b949ab1e2f06b7d5efeccc924efaee":[60,0,113,32], -"structrf__context.html#aa13bb4f72f3024d81e9051de4bd65ec0":[60,0,113,6], -"structrf__context.html#aa574515edb4966117f539d26e26f0a62":[60,0,113,46] +"structrf__context.html#aa0b949ab1e2f06b7d5efeccc924efaee":[60,0,113,32] }; diff --git a/public/navtreeindex17.js b/public/navtreeindex17.js index a064484fd..e9ba19f2f 100644 --- a/public/navtreeindex17.js +++ b/public/navtreeindex17.js @@ -1,5 +1,7 @@ var NAVTREEINDEX17 = { +"structrf__context.html#aa13bb4f72f3024d81e9051de4bd65ec0":[60,0,113,6], +"structrf__context.html#aa574515edb4966117f539d26e26f0a62":[60,0,113,46], "structrf__context.html#aa79909e0ac140a3404151a40bed6a6ec":[60,0,113,34], "structrf__context.html#aafce196b029d2578151275acd07ccb82":[60,0,113,24], "structrf__context.html#ab5ffc4d8ba9d3d8a298414dc8e4efd2a":[60,0,113,30], @@ -247,7 +249,5 @@ var NAVTREEINDEX17 = "www__plugin_8c.html#a3874a40164919bc5389d166df691bfdb":[61,0,169,24], "www__plugin_8c.html#a3b53d8bbfcf5bdf5564c8804d211cf99":[61,0,169,21], "www__plugin_8c.html#a56e5020de11446dbc23f3480e313f208":[61,0,169,2], -"www__plugin_8c.html#a73ffad7289c2476a04d7270fa340bee9":[61,0,169,1], -"www__plugin_8c.html#a9323d1142816fbac8f87545a398a0f71":[61,0,169,10], -"www__plugin_8c.html#a9493664f6bdafe3f5b593c3e5e1eacc7":[61,0,169,22] +"www__plugin_8c.html#a73ffad7289c2476a04d7270fa340bee9":[61,0,169,1] }; diff --git a/public/navtreeindex18.js b/public/navtreeindex18.js index 2988b2a55..a7972fa1f 100644 --- a/public/navtreeindex18.js +++ b/public/navtreeindex18.js @@ -1,5 +1,7 @@ var NAVTREEINDEX18 = { +"www__plugin_8c.html#a9323d1142816fbac8f87545a398a0f71":[61,0,169,10], +"www__plugin_8c.html#a9493664f6bdafe3f5b593c3e5e1eacc7":[61,0,169,22], "www__plugin_8c.html#a98eddc35144b89bce2e247d5ea49177b":[61,0,169,17], "www__plugin_8c.html#aaa970cf06dde51601b91b8d6f936b7ed":[61,0,169,6], "www__plugin_8c.html#aab3ceb1ae095823fcbee98ce2811b374":[61,0,169,7], diff --git a/public/navtreeindex8.js b/public/navtreeindex8.js index 1ca637875..d3f7ab3a7 100644 --- a/public/navtreeindex8.js +++ b/public/navtreeindex8.js @@ -126,120 +126,121 @@ var NAVTREEINDEX8 = "remmina__pref__dialog_8h.html#aeba55bfe8ab83707f2e68034061a3dd2":[61,0,118,3], "remmina__pref__dialog_8h_source.html":[61,0,118], "remmina__protocol__widget_8c.html":[61,0,119], -"remmina__protocol__widget_8c.html#a04f0a11e50cdbd98ab80984fd5aca16d":[61,0,119,20], -"remmina__protocol__widget_8c.html#a05b5edfc3d3d0dcff1745d1d35aaca5c":[61,0,119,95], +"remmina__protocol__widget_8c.html#a04f0a11e50cdbd98ab80984fd5aca16d":[61,0,119,21], +"remmina__protocol__widget_8c.html#a05b5edfc3d3d0dcff1745d1d35aaca5c":[61,0,119,96], "remmina__protocol__widget_8c.html#a05f9694efc84de6273efa46d232b84f9":[61,0,119,7], -"remmina__protocol__widget_8c.html#a08d312825fc0de9f9286279d99f763a1":[61,0,119,34], +"remmina__protocol__widget_8c.html#a08d312825fc0de9f9286279d99f763a1":[61,0,119,35], "remmina__protocol__widget_8c.html#a0a93da80662ff18b93270ced59243ce3":[61,0,119,10], -"remmina__protocol__widget_8c.html#a0b19dbe685e4465e7f06706270e120fa":[61,0,119,89], -"remmina__protocol__widget_8c.html#a0fcec40aae330e115d1bae66aeefb3df":[61,0,119,54], -"remmina__protocol__widget_8c.html#a11480396cb379860d16d9d41ef91ecb1":[61,0,119,24], -"remmina__protocol__widget_8c.html#a122e28e59acb89200937ff823b82ddaf":[61,0,119,109], -"remmina__protocol__widget_8c.html#a12eddf3428a53201ee0a2ec422d2fa4a":[61,0,119,96], -"remmina__protocol__widget_8c.html#a13e14fa81f7ca52942415a7caf5b932c":[61,0,119,80], -"remmina__protocol__widget_8c.html#a14684e3222e6afb1b43d77634a174767":[61,0,119,104], -"remmina__protocol__widget_8c.html#a15368afcbeb770f8cf25941bd49e7b54":[61,0,119,87], -"remmina__protocol__widget_8c.html#a1585ea6908dd5c0a9b0f47d409916435":[61,0,119,58], -"remmina__protocol__widget_8c.html#a172fa9cf2ce196c9846a3e47ea9036b4":[61,0,119,99], -"remmina__protocol__widget_8c.html#a1caaa7bea6ef53e5c7e8109f3d0814e1":[61,0,119,62], -"remmina__protocol__widget_8c.html#a1cae52cad394f317c712eb4fd709d261":[61,0,119,94], -"remmina__protocol__widget_8c.html#a2067c19b160eb43bddda6c6c6e8d6045":[61,0,119,52], -"remmina__protocol__widget_8c.html#a247c73c70d9c58427022a4dbcd638d32":[61,0,119,15], -"remmina__protocol__widget_8c.html#a2506e80d482c34532d0e534856452069":[61,0,119,40], -"remmina__protocol__widget_8c.html#a2551dd6f53480609596d2695040fba5d":[61,0,119,101], -"remmina__protocol__widget_8c.html#a25797eafabe9d6f5729b56145abe1572":[61,0,119,111], -"remmina__protocol__widget_8c.html#a25bcb2ae99449624fed6f770218e3d25":[61,0,119,38], -"remmina__protocol__widget_8c.html#a262d75d6b535bd8c623e607805db4084":[61,0,119,71], -"remmina__protocol__widget_8c.html#a278e13b53a4fdb65498e00e908edb98d":[61,0,119,74], -"remmina__protocol__widget_8c.html#a2830f756dfc3d735b57b0c5753c429e3":[61,0,119,56], -"remmina__protocol__widget_8c.html#a290eb68f0e86de1b7b82e2d98a1494d1":[61,0,119,51], -"remmina__protocol__widget_8c.html#a2c2a41aeee8f3ef6481378a95c02c130":[61,0,119,114], -"remmina__protocol__widget_8c.html#a2f5270c5e5007a8e95f4d460c11b2a06":[61,0,119,82], -"remmina__protocol__widget_8c.html#a36e01bda95825ee6b5f164f52af7c457":[61,0,119,57], -"remmina__protocol__widget_8c.html#a3fc52d61f77327534286f57e563e0923":[61,0,119,45], -"remmina__protocol__widget_8c.html#a4017a800d7803a40d606ffce2578509a":[61,0,119,78], -"remmina__protocol__widget_8c.html#a41b62f211a8a8e960bc80aa1ba6b0380":[61,0,119,92], -"remmina__protocol__widget_8c.html#a450fbca7e27c952b6aaba6e33192051d":[61,0,119,106], -"remmina__protocol__widget_8c.html#a480f842fac65440c367bf3c3d87d2601":[61,0,119,76], -"remmina__protocol__widget_8c.html#a4a3a9ba7422fc302b0b412ac771c9953":[61,0,119,19], +"remmina__protocol__widget_8c.html#a0b19dbe685e4465e7f06706270e120fa":[61,0,119,90], +"remmina__protocol__widget_8c.html#a0fcec40aae330e115d1bae66aeefb3df":[61,0,119,55], +"remmina__protocol__widget_8c.html#a11480396cb379860d16d9d41ef91ecb1":[61,0,119,25], +"remmina__protocol__widget_8c.html#a122e28e59acb89200937ff823b82ddaf":[61,0,119,110], +"remmina__protocol__widget_8c.html#a12eddf3428a53201ee0a2ec422d2fa4a":[61,0,119,97], +"remmina__protocol__widget_8c.html#a13e14fa81f7ca52942415a7caf5b932c":[61,0,119,81], +"remmina__protocol__widget_8c.html#a14684e3222e6afb1b43d77634a174767":[61,0,119,105], +"remmina__protocol__widget_8c.html#a15368afcbeb770f8cf25941bd49e7b54":[61,0,119,88], +"remmina__protocol__widget_8c.html#a1585ea6908dd5c0a9b0f47d409916435":[61,0,119,59], +"remmina__protocol__widget_8c.html#a172fa9cf2ce196c9846a3e47ea9036b4":[61,0,119,100], +"remmina__protocol__widget_8c.html#a1caaa7bea6ef53e5c7e8109f3d0814e1":[61,0,119,63], +"remmina__protocol__widget_8c.html#a1cae52cad394f317c712eb4fd709d261":[61,0,119,95], +"remmina__protocol__widget_8c.html#a2067c19b160eb43bddda6c6c6e8d6045":[61,0,119,53], +"remmina__protocol__widget_8c.html#a247c73c70d9c58427022a4dbcd638d32":[61,0,119,16], +"remmina__protocol__widget_8c.html#a2506e80d482c34532d0e534856452069":[61,0,119,41], +"remmina__protocol__widget_8c.html#a2551dd6f53480609596d2695040fba5d":[61,0,119,102], +"remmina__protocol__widget_8c.html#a25797eafabe9d6f5729b56145abe1572":[61,0,119,112], +"remmina__protocol__widget_8c.html#a25bcb2ae99449624fed6f770218e3d25":[61,0,119,39], +"remmina__protocol__widget_8c.html#a262d75d6b535bd8c623e607805db4084":[61,0,119,72], +"remmina__protocol__widget_8c.html#a278e13b53a4fdb65498e00e908edb98d":[61,0,119,75], +"remmina__protocol__widget_8c.html#a2830f756dfc3d735b57b0c5753c429e3":[61,0,119,57], +"remmina__protocol__widget_8c.html#a290eb68f0e86de1b7b82e2d98a1494d1":[61,0,119,52], +"remmina__protocol__widget_8c.html#a2c2a41aeee8f3ef6481378a95c02c130":[61,0,119,115], +"remmina__protocol__widget_8c.html#a2f5270c5e5007a8e95f4d460c11b2a06":[61,0,119,83], +"remmina__protocol__widget_8c.html#a36e01bda95825ee6b5f164f52af7c457":[61,0,119,58], +"remmina__protocol__widget_8c.html#a3fc52d61f77327534286f57e563e0923":[61,0,119,46], +"remmina__protocol__widget_8c.html#a4017a800d7803a40d606ffce2578509a":[61,0,119,79], +"remmina__protocol__widget_8c.html#a41b62f211a8a8e960bc80aa1ba6b0380":[61,0,119,93], +"remmina__protocol__widget_8c.html#a450fbca7e27c952b6aaba6e33192051d":[61,0,119,107], +"remmina__protocol__widget_8c.html#a480f842fac65440c367bf3c3d87d2601":[61,0,119,77], +"remmina__protocol__widget_8c.html#a4a3a9ba7422fc302b0b412ac771c9953":[61,0,119,20], "remmina__protocol__widget_8c.html#a4fb4c2252289e8e891376db6279ef8f5":[61,0,119,9], -"remmina__protocol__widget_8c.html#a508044024b303c286a0e643e44d85a29":[61,0,119,37], -"remmina__protocol__widget_8c.html#a5567a5c55d9a880d174faabafcd15fa3":[61,0,119,55], -"remmina__protocol__widget_8c.html#a57ac13fc4a2653c40e0601183628c0ca":[61,0,119,77], -"remmina__protocol__widget_8c.html#a5aaadd752a3275a0a8e0018a3dd669f8":[61,0,119,91], -"remmina__protocol__widget_8c.html#a5c2137462d3168e90c812f1ce75a6e62":[61,0,119,61], -"remmina__protocol__widget_8c.html#a5ec62969da54155e24edcb1d998f93f7":[61,0,119,35], -"remmina__protocol__widget_8c.html#a605b69a9aa4393024369cc5070488692":[61,0,119,17], -"remmina__protocol__widget_8c.html#a6399c3828908e36ed6202b5599bd206b":[61,0,119,64], -"remmina__protocol__widget_8c.html#a66263e6e7da79357ceb80d32b191d9f2":[61,0,119,21], +"remmina__protocol__widget_8c.html#a508044024b303c286a0e643e44d85a29":[61,0,119,38], +"remmina__protocol__widget_8c.html#a5567a5c55d9a880d174faabafcd15fa3":[61,0,119,56], +"remmina__protocol__widget_8c.html#a57ac13fc4a2653c40e0601183628c0ca":[61,0,119,78], +"remmina__protocol__widget_8c.html#a5aaadd752a3275a0a8e0018a3dd669f8":[61,0,119,92], +"remmina__protocol__widget_8c.html#a5c2137462d3168e90c812f1ce75a6e62":[61,0,119,62], +"remmina__protocol__widget_8c.html#a5ec62969da54155e24edcb1d998f93f7":[61,0,119,36], +"remmina__protocol__widget_8c.html#a605b69a9aa4393024369cc5070488692":[61,0,119,18], +"remmina__protocol__widget_8c.html#a6399c3828908e36ed6202b5599bd206b":[61,0,119,65], +"remmina__protocol__widget_8c.html#a66263e6e7da79357ceb80d32b191d9f2":[61,0,119,22], "remmina__protocol__widget_8c.html#a69757e0c39fa9fcf31800f6375772016":[61,0,119,12], -"remmina__protocol__widget_8c.html#a6a630e96e5b914d60d678ae8eaad4cd9":[61,0,119,18], -"remmina__protocol__widget_8c.html#a70aecb9af2ea35527e8d058d1d87a0d3":[61,0,119,32], -"remmina__protocol__widget_8c.html#a76ad91e7f8648699f71c466e203aa6dd":[61,0,119,65], -"remmina__protocol__widget_8c.html#a78b123eca6709bceeacda7d791a94bf1":[61,0,119,60], -"remmina__protocol__widget_8c.html#a7b1e83afd68c2b7301fc4d6da6a8f6d8":[61,0,119,108], -"remmina__protocol__widget_8c.html#a7c15fa81642c52ef382e1dbe34ffb6ac":[61,0,119,36], -"remmina__protocol__widget_8c.html#a7e54d9bb42d2d337527d3af657ef1e1f":[61,0,119,27], -"remmina__protocol__widget_8c.html#a7ed85f4ea19e0660dbf46f4f3dc4b895":[61,0,119,75], -"remmina__protocol__widget_8c.html#a8127b4cc7c278216dff87a7e4a336dfb":[61,0,119,41], -"remmina__protocol__widget_8c.html#a843c2455a10c9382aee454515f9e7f8b":[61,0,119,73], -"remmina__protocol__widget_8c.html#a8565f01f8b5a3f0ee4518bda5f923f9a":[61,0,119,113], -"remmina__protocol__widget_8c.html#a858e4756aa97ce424ccf12475c225c54":[61,0,119,28], -"remmina__protocol__widget_8c.html#a8c125f58aa4fac0e4c88f293e4d4dd74":[61,0,119,23], -"remmina__protocol__widget_8c.html#a8ef0523afadadc9984d53fb02ecc01ad":[61,0,119,70], -"remmina__protocol__widget_8c.html#a9092c29f585fdabaf0ce7e865670053b":[61,0,119,72], +"remmina__protocol__widget_8c.html#a6a630e96e5b914d60d678ae8eaad4cd9":[61,0,119,19], +"remmina__protocol__widget_8c.html#a70aecb9af2ea35527e8d058d1d87a0d3":[61,0,119,33], +"remmina__protocol__widget_8c.html#a76ad91e7f8648699f71c466e203aa6dd":[61,0,119,66], +"remmina__protocol__widget_8c.html#a78b123eca6709bceeacda7d791a94bf1":[61,0,119,61], +"remmina__protocol__widget_8c.html#a7b1e83afd68c2b7301fc4d6da6a8f6d8":[61,0,119,109], +"remmina__protocol__widget_8c.html#a7c15fa81642c52ef382e1dbe34ffb6ac":[61,0,119,37], +"remmina__protocol__widget_8c.html#a7e54d9bb42d2d337527d3af657ef1e1f":[61,0,119,28], +"remmina__protocol__widget_8c.html#a7ed85f4ea19e0660dbf46f4f3dc4b895":[61,0,119,76], +"remmina__protocol__widget_8c.html#a8127b4cc7c278216dff87a7e4a336dfb":[61,0,119,42], +"remmina__protocol__widget_8c.html#a843c2455a10c9382aee454515f9e7f8b":[61,0,119,74], +"remmina__protocol__widget_8c.html#a8565f01f8b5a3f0ee4518bda5f923f9a":[61,0,119,114], +"remmina__protocol__widget_8c.html#a858e4756aa97ce424ccf12475c225c54":[61,0,119,29], +"remmina__protocol__widget_8c.html#a8c125f58aa4fac0e4c88f293e4d4dd74":[61,0,119,24], +"remmina__protocol__widget_8c.html#a8ef0523afadadc9984d53fb02ecc01ad":[61,0,119,71], +"remmina__protocol__widget_8c.html#a9092c29f585fdabaf0ce7e865670053b":[61,0,119,73], "remmina__protocol__widget_8c.html#a91d88c61dd84299369fe3c79e19821b1":[61,0,119,4], "remmina__protocol__widget_8c.html#a9275874ac61d3750aa677a36da714373":[61,0,119,5], "remmina__protocol__widget_8c.html#a9275874ac61d3750aa677a36da714373a622fa08b626cd4dc1faf24c073e15c65":[61,0,119,5,1], "remmina__protocol__widget_8c.html#a9275874ac61d3750aa677a36da714373ab2286d6e72e1c7ddd0e760caa78f47ed":[61,0,119,5,2], "remmina__protocol__widget_8c.html#a9275874ac61d3750aa677a36da714373af288a06859b2eb1df4a011e1c2cba44c":[61,0,119,5,0], -"remmina__protocol__widget_8c.html#a9473da27fd10eb46ef8360f9ad4be86d":[61,0,119,31], -"remmina__protocol__widget_8c.html#a95088334da86faf9520383629fff48af":[61,0,119,88], -"remmina__protocol__widget_8c.html#a96159bd8e9d70c74967e666e2f188df0":[61,0,119,49], -"remmina__protocol__widget_8c.html#a97cba8208a4348446159bf465b3233f5":[61,0,119,59], +"remmina__protocol__widget_8c.html#a9473da27fd10eb46ef8360f9ad4be86d":[61,0,119,32], +"remmina__protocol__widget_8c.html#a95088334da86faf9520383629fff48af":[61,0,119,89], +"remmina__protocol__widget_8c.html#a96159bd8e9d70c74967e666e2f188df0":[61,0,119,50], +"remmina__protocol__widget_8c.html#a97cba8208a4348446159bf465b3233f5":[61,0,119,60], "remmina__protocol__widget_8c.html#a99ba55ddcb17c9e87ca233fa83787227":[61,0,119,8], -"remmina__protocol__widget_8c.html#a9acf045c5a3eec5b7f748678dee0d3ee":[61,0,119,26], -"remmina__protocol__widget_8c.html#a9bcd0d356c7215dc0f791c9744360705":[61,0,119,84], -"remmina__protocol__widget_8c.html#a9d55210413d6a313478f81cf76ecf1b7":[61,0,119,97], -"remmina__protocol__widget_8c.html#a9ed3110b7b030bccd0ff9ed70e86da2d":[61,0,119,48], +"remmina__protocol__widget_8c.html#a9acf045c5a3eec5b7f748678dee0d3ee":[61,0,119,27], +"remmina__protocol__widget_8c.html#a9bcd0d356c7215dc0f791c9744360705":[61,0,119,85], +"remmina__protocol__widget_8c.html#a9d55210413d6a313478f81cf76ecf1b7":[61,0,119,98], +"remmina__protocol__widget_8c.html#a9ed3110b7b030bccd0ff9ed70e86da2d":[61,0,119,49], "remmina__protocol__widget_8c.html#aa0b0a97022961c198c3343dd2433d7cb":[61,0,119,6], -"remmina__protocol__widget_8c.html#aa41324b7175c46bb42b978332db95d22":[61,0,119,25], -"remmina__protocol__widget_8c.html#aa674c14f3a46dd5eb6b53d6f8ce6bd31":[61,0,119,68], -"remmina__protocol__widget_8c.html#aa6d9f2f558fcd9e7fe58eefcde1c3c5c":[61,0,119,98], -"remmina__protocol__widget_8c.html#aa88afa1e3f04974974a8be324b0a930e":[61,0,119,103], -"remmina__protocol__widget_8c.html#aa9639b76ac0a92647ce08bdfe943d113":[61,0,119,29], -"remmina__protocol__widget_8c.html#aab2f304822ccfd4979854ef1afd81771":[61,0,119,53], -"remmina__protocol__widget_8c.html#aadd106cec729a80405c6097e4c662044":[61,0,119,90], -"remmina__protocol__widget_8c.html#aaf355ea7103fc57a4cbc7b815cde2995":[61,0,119,50], -"remmina__protocol__widget_8c.html#ab224a0f643d291f86ede54e373bd0a6f":[61,0,119,44], -"remmina__protocol__widget_8c.html#ab2b4a7c615a472ad391d1c06ea1f00cc":[61,0,119,16], -"remmina__protocol__widget_8c.html#ab4c6435ef92e34a94270069ce1861907":[61,0,119,47], -"remmina__protocol__widget_8c.html#ab863cc1442a992adfa323bc77ab88504":[61,0,119,81], -"remmina__protocol__widget_8c.html#ab9632c73b32531b7bea976e10204670b":[61,0,119,33], -"remmina__protocol__widget_8c.html#abdf99138612d02bc3921b0b77bdc89cb":[61,0,119,43], -"remmina__protocol__widget_8c.html#ac1f95eb1e31c05ae0bc4027496ceafb0":[61,0,119,63], -"remmina__protocol__widget_8c.html#ac3e5a7f14aef4adb2e57d35e9c180b3b":[61,0,119,30], -"remmina__protocol__widget_8c.html#ac705ffa194e3c3457e9a0a1bd6c79be8":[61,0,119,93], -"remmina__protocol__widget_8c.html#ac9abaedb8cc35838ef1444423a81507d":[61,0,119,110], -"remmina__protocol__widget_8c.html#ac9da39853a32523057759a498bf6ac0a":[61,0,119,102], -"remmina__protocol__widget_8c.html#acf40f566116cf43af26891cd37af4eb1":[61,0,119,83], -"remmina__protocol__widget_8c.html#acf75fd4bac28a3d53da064b2905f23c1":[61,0,119,69], -"remmina__protocol__widget_8c.html#ad637ec849c497e4a0d4c723396aa6fba":[61,0,119,67], -"remmina__protocol__widget_8c.html#ad6e2d00646e8268aa0e8bbe31b77db48":[61,0,119,86], -"remmina__protocol__widget_8c.html#ad8df6a87e19b7751b26820ef4a668de9":[61,0,119,46], -"remmina__protocol__widget_8c.html#adbe15328275677cb38bd8c8a2d5e039d":[61,0,119,79], -"remmina__protocol__widget_8c.html#add3775989fb5ed7a7f1f7c9b5980a94e":[61,0,119,112], -"remmina__protocol__widget_8c.html#adfac12e7a563dc06fb2f0c8307f40fee":[61,0,119,105], -"remmina__protocol__widget_8c.html#ae2522242b3f39ee84ee8cf75170de0c0":[61,0,119,22], -"remmina__protocol__widget_8c.html#ae609b351fff17c235251b0ba7c480da5":[61,0,119,42], -"remmina__protocol__widget_8c.html#aeaa588b63800d3762b738fbbfd4a1736":[61,0,119,107], -"remmina__protocol__widget_8c.html#aeaf728bb767c1bbdda6a0d8dc3553565":[61,0,119,14], -"remmina__protocol__widget_8c.html#aebc7c7d34c470081a52aa35d998ce868":[61,0,119,66], -"remmina__protocol__widget_8c.html#aecd801fbe5399bbeb5832657bce193cb":[61,0,119,100], +"remmina__protocol__widget_8c.html#aa41324b7175c46bb42b978332db95d22":[61,0,119,26], +"remmina__protocol__widget_8c.html#aa674c14f3a46dd5eb6b53d6f8ce6bd31":[61,0,119,69], +"remmina__protocol__widget_8c.html#aa6d9f2f558fcd9e7fe58eefcde1c3c5c":[61,0,119,99], +"remmina__protocol__widget_8c.html#aa88afa1e3f04974974a8be324b0a930e":[61,0,119,104], +"remmina__protocol__widget_8c.html#aa905484fffd7eaa072b834db6ffb642c":[61,0,119,13], +"remmina__protocol__widget_8c.html#aa9639b76ac0a92647ce08bdfe943d113":[61,0,119,30], +"remmina__protocol__widget_8c.html#aab2f304822ccfd4979854ef1afd81771":[61,0,119,54], +"remmina__protocol__widget_8c.html#aadd106cec729a80405c6097e4c662044":[61,0,119,91], +"remmina__protocol__widget_8c.html#aaf355ea7103fc57a4cbc7b815cde2995":[61,0,119,51], +"remmina__protocol__widget_8c.html#ab224a0f643d291f86ede54e373bd0a6f":[61,0,119,45], +"remmina__protocol__widget_8c.html#ab2b4a7c615a472ad391d1c06ea1f00cc":[61,0,119,17], +"remmina__protocol__widget_8c.html#ab4c6435ef92e34a94270069ce1861907":[61,0,119,48], +"remmina__protocol__widget_8c.html#ab863cc1442a992adfa323bc77ab88504":[61,0,119,82], +"remmina__protocol__widget_8c.html#ab9632c73b32531b7bea976e10204670b":[61,0,119,34], +"remmina__protocol__widget_8c.html#abdf99138612d02bc3921b0b77bdc89cb":[61,0,119,44], +"remmina__protocol__widget_8c.html#ac1f95eb1e31c05ae0bc4027496ceafb0":[61,0,119,64], +"remmina__protocol__widget_8c.html#ac3e5a7f14aef4adb2e57d35e9c180b3b":[61,0,119,31], +"remmina__protocol__widget_8c.html#ac705ffa194e3c3457e9a0a1bd6c79be8":[61,0,119,94], +"remmina__protocol__widget_8c.html#ac9abaedb8cc35838ef1444423a81507d":[61,0,119,111], +"remmina__protocol__widget_8c.html#ac9da39853a32523057759a498bf6ac0a":[61,0,119,103], +"remmina__protocol__widget_8c.html#acf40f566116cf43af26891cd37af4eb1":[61,0,119,84], +"remmina__protocol__widget_8c.html#acf75fd4bac28a3d53da064b2905f23c1":[61,0,119,70], +"remmina__protocol__widget_8c.html#ad637ec849c497e4a0d4c723396aa6fba":[61,0,119,68], +"remmina__protocol__widget_8c.html#ad6e2d00646e8268aa0e8bbe31b77db48":[61,0,119,87], +"remmina__protocol__widget_8c.html#ad8df6a87e19b7751b26820ef4a668de9":[61,0,119,47], +"remmina__protocol__widget_8c.html#adbe15328275677cb38bd8c8a2d5e039d":[61,0,119,80], +"remmina__protocol__widget_8c.html#add3775989fb5ed7a7f1f7c9b5980a94e":[61,0,119,113], +"remmina__protocol__widget_8c.html#adfac12e7a563dc06fb2f0c8307f40fee":[61,0,119,106], +"remmina__protocol__widget_8c.html#ae2522242b3f39ee84ee8cf75170de0c0":[61,0,119,23], +"remmina__protocol__widget_8c.html#ae609b351fff17c235251b0ba7c480da5":[61,0,119,43], +"remmina__protocol__widget_8c.html#aeaa588b63800d3762b738fbbfd4a1736":[61,0,119,108], +"remmina__protocol__widget_8c.html#aeaf728bb767c1bbdda6a0d8dc3553565":[61,0,119,15], +"remmina__protocol__widget_8c.html#aebc7c7d34c470081a52aa35d998ce868":[61,0,119,67], +"remmina__protocol__widget_8c.html#aecd801fbe5399bbeb5832657bce193cb":[61,0,119,101], "remmina__protocol__widget_8c.html#aeffe07c6412286d99ba04f05fe74aeac":[61,0,119,11], -"remmina__protocol__widget_8c.html#af4a20ef0ff8cc86feeba345498179e48":[61,0,119,13], -"remmina__protocol__widget_8c.html#af9b6a2c2665010ab09a6d9943f9850bd":[61,0,119,39], -"remmina__protocol__widget_8c.html#affb2413c00f0681fe08f90523f7e1471":[61,0,119,85], +"remmina__protocol__widget_8c.html#af4a20ef0ff8cc86feeba345498179e48":[61,0,119,14], +"remmina__protocol__widget_8c.html#af9b6a2c2665010ab09a6d9943f9850bd":[61,0,119,40], +"remmina__protocol__widget_8c.html#affb2413c00f0681fe08f90523f7e1471":[61,0,119,86], "remmina__protocol__widget_8c_source.html":[61,0,119], "remmina__protocol__widget_8h.html":[61,0,120], "remmina__protocol__widget_8h.html#a05b5edfc3d3d0dcff1745d1d35aaca5c":[61,0,120,73], @@ -248,6 +249,5 @@ var NAVTREEINDEX8 = "remmina__protocol__widget_8h.html#a12eddf3428a53201ee0a2ec422d2fa4a":[61,0,120,74], "remmina__protocol__widget_8h.html#a13e14fa81f7ca52942415a7caf5b932c":[61,0,120,59], "remmina__protocol__widget_8h.html#a14684e3222e6afb1b43d77634a174767":[61,0,120,81], -"remmina__protocol__widget_8h.html#a15368afcbeb770f8cf25941bd49e7b54":[61,0,120,65], -"remmina__protocol__widget_8h.html#a1585ea6908dd5c0a9b0f47d409916435":[61,0,120,39] +"remmina__protocol__widget_8h.html#a15368afcbeb770f8cf25941bd49e7b54":[61,0,120,65] }; diff --git a/public/navtreeindex9.js b/public/navtreeindex9.js index 10c1731c3..ba1088c6e 100644 --- a/public/navtreeindex9.js +++ b/public/navtreeindex9.js @@ -1,5 +1,6 @@ var NAVTREEINDEX9 = { +"remmina__protocol__widget_8h.html#a1585ea6908dd5c0a9b0f47d409916435":[61,0,120,39], "remmina__protocol__widget_8h.html#a172fa9cf2ce196c9846a3e47ea9036b4":[61,0,120,77], "remmina__protocol__widget_8h.html#a1cae52cad394f317c712eb4fd709d261":[61,0,120,72], "remmina__protocol__widget_8h.html#a2067c19b160eb43bddda6c6c6e8d6045":[61,0,120,35], @@ -248,6 +249,5 @@ var NAVTREEINDEX9 = "remmina__ssh_8c.html#aa8aee72091b09cde34c0e0efadde719a":[61,0,133,4], "remmina__ssh_8c.html#aad84c6609cb431d48121ae5e0902441b":[61,0,133,2], "remmina__ssh_8c.html#ab1ac2a91d14c557598f168f66ba130eb":[61,0,133,27], -"remmina__ssh_8c.html#ab6d8bdad543b3caead2b2b0339484798":[61,0,133,16], -"remmina__ssh_8c.html#ab8f07d5ab2ee8aa8423a11808b6cb100":[61,0,133,26] +"remmina__ssh_8c.html#ab6d8bdad543b3caead2b2b0339484798":[61,0,133,16] }; diff --git a/public/plugin_8h_source.html b/public/plugin_8h_source.html index 529f96eba..ac6f72cc8 100644 --- a/public/plugin_8h_source.html +++ b/public/plugin_8h_source.html @@ -136,7 +136,7 @@ $(document).ready(function(){initNavTree('plugin_8h_source.html','');});
    const gchar * domain
    Definition: plugin.h:94
    const gchar * domain
    Definition: plugin.h:128
    void _remmina_audit(const gchar *fun, const gchar *fmt,...)
    Definition: remmina_log.c:313
    -
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    +
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    const gchar * domain
    Definition: plugin.h:104
    RemminaPluginType type
    Definition: plugin.h:151
    const gchar * name
    Definition: plugin.h:92
    diff --git a/public/rcw_8c_source.html b/public/rcw_8c_source.html index 3a5708dfb..1ebd88a8b 100644 --- a/public/rcw_8c_source.html +++ b/public/rcw_8c_source.html @@ -87,10 +87,10 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2009-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 
    38 #include "config.h"
    39 
    40 #ifdef GDK_WINDOWING_X11
    41 #include <cairo/cairo-xlib.h>
    42 #else
    43 #include <cairo/cairo.h>
    44 #endif
    45 #include <gdk/gdk.h>
    46 #include <gdk/gdkkeysyms.h>
    47 #include <glib/gi18n.h>
    48 #include <stdlib.h>
    49 
    50 #include "remmina.h"
    51 #include "remmina_main.h"
    52 #include "rcw.h"
    54 #include "remmina_applet_menu.h"
    55 #include "remmina_file.h"
    56 #include "remmina_file_manager.h"
    57 #include "remmina_log.h"
    58 #include "remmina_message_panel.h"
    59 #include "remmina_ext_exec.h"
    60 #include "remmina_plugin_manager.h"
    61 #include "remmina_pref.h"
    63 #include "remmina_public.h"
    65 #include "remmina_unlock.h"
    66 #include "remmina_utils.h"
    67 #include "remmina_widget_pool.h"
    69 
    70 #ifdef GDK_WINDOWING_WAYLAND
    71 #include <gdk/gdkwayland.h>
    72 #endif
    73 
    74 
    75 #define DEBUG_KB_GRABBING 0
    76 #include "remmina_exec.h"
    77 
    80 
    81 G_DEFINE_TYPE(RemminaConnectionWindow, rcw, GTK_TYPE_WINDOW)
    82 
    83 #define MOTION_TIME 100
    84 
    85 /* default timeout used to hide the floating toolbar when switching profile */
    86 #define TB_HIDE_TIME_TIME 1500
    87 
    88 #define FULL_SCREEN_TARGET_MONITOR_UNDEFINED -1
    89 
    90 struct _RemminaConnectionWindowPriv {
    91  GtkNotebook * notebook;
    92  GtkWidget * floating_toolbar_widget;
    93  GtkWidget * overlay;
    94  GtkWidget * revealer;
    95  GtkWidget * overlay_ftb_overlay;
    96 
    97  GtkWidget * floating_toolbar_label;
    98  gdouble floating_toolbar_opacity;
    99 
    100  /* Various delayed and timer event source ids */
    101  guint acs_eventsourceid; // timeout
    102  guint spf_eventsourceid; // idle
    103  guint grab_retry_eventsourceid; // timeout
    104  guint delayed_grab_eventsourceid;
    105  guint ftb_hide_eventsource; // timeout
    106  guint tar_eventsource; // timeout
    107  guint hidetb_eventsource; // timeout
    108  guint dwp_eventsourceid; // timeout
    109 
    110  GtkWidget * toolbar;
    111  GtkWidget * grid;
    112 
    113  /* Toolitems that need to be handled */
    114  GtkToolItem * toolitem_menu;
    115  GtkToolItem * toolitem_autofit;
    116  GtkToolItem * toolitem_fullscreen;
    117  GtkToolItem * toolitem_switch_page;
    118  GtkToolItem * toolitem_dynres;
    119  GtkToolItem * toolitem_scale;
    120  GtkToolItem * toolitem_grab;
    121  GtkToolItem * toolitem_multimon;
    122  GtkToolItem * toolitem_preferences;
    123  GtkToolItem * toolitem_tools;
    124  GtkToolItem * toolitem_new;
    125  GtkToolItem * toolitem_duplicate;
    126  GtkToolItem * toolitem_screenshot;
    127  GtkWidget * fullscreen_option_button;
    128  GtkWidget * fullscreen_scaler_button;
    129  GtkWidget * scaler_option_button;
    130 
    131  GtkWidget * pin_button;
    132  gboolean pin_down;
    133 
    134  gboolean sticky;
    135 
    136  /* Flag to turn off toolbar signal handling when toolbar is
    137  * reconfiguring, usually due to a tab switch */
    138  gboolean toolbar_is_reconfiguring;
    139 
    140  /* This is the current view mode, i.e. VIEWPORT_FULLSCREEN_MODE,
    141  * as saved on the "viwemode" profile preference file */
    142  gint view_mode;
    143 
    144  /* Status variables used when in fullscreen mode. Needed
    145  * to restore a fullscreen mode after coming from scrolled */
    146  gint fss_view_mode;
    147  /* Status variables used when in scrolled window mode. Needed
    148  * to restore a scrolled window mode after coming from fullscreen */
    149  gint ss_width, ss_height;
    150  gboolean ss_maximized;
    151 
    152  gboolean kbcaptured;
    153  gboolean pointer_captured;
    154  gboolean hostkey_activated;
    155  gboolean hostkey_used;
    156 
    157  gboolean pointer_entered;
    158 
    159  RemminaConnectionWindowOnDeleteConfirmMode on_delete_confirm_mode;
    160 };
    161 
    162 typedef struct _RemminaConnectionObject {
    165 
    166  GtkWidget * proto;
    167  GtkWidget * aspectframe;
    168  GtkWidget * viewport;
    169 
    170  GtkWidget * scrolled_container;
    171 
    173 
    174  gboolean connected;
    175  gboolean dynres_unlocked;
    176 
    179 
    180 enum {
    183 };
    184 
    185 static guint rcw_signals[LAST_SIGNAL] =
    186 { 0 };
    187 
    188 static RemminaConnectionWindow *rcw_create_scrolled(gint width, gint height, gboolean maximize);
    189 static RemminaConnectionWindow *rcw_create_fullscreen(GtkWindow *old, gint view_mode);
    190 static gboolean rcw_hostkey_func(RemminaProtocolWidget *gp, guint keyval, gboolean release);
    191 static GtkWidget *rco_create_tab_page(RemminaConnectionObject *cnnobj);
    192 static GtkWidget *rco_create_tab_label(RemminaConnectionObject *cnnobj);
    193 
    195 static GtkWidget *rcw_create_toolbar(RemminaConnectionWindow *cnnwin, gint mode);
    196 static void rcw_place_toolbar(GtkToolbar *toolbar, GtkGrid *grid, GtkWidget *sibling, int toolbar_placement);
    197 static void rcw_keyboard_grab(RemminaConnectionWindow *cnnwin);
    198 static GtkWidget *rcw_append_new_page(RemminaConnectionWindow *cnnwin, RemminaConnectionObject *cnnobj);
    199 
    200 
    201 static void rcw_ftb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data);
    202 
    203 static const GtkTargetEntry dnd_targets_ftb[] =
    204 {
    205  {
    206  (char *)"text/x-remmina-ftb",
    207  GTK_TARGET_SAME_APP | GTK_TARGET_OTHER_WIDGET,
    208  0
    209  },
    210 };
    211 
    212 static const GtkTargetEntry dnd_targets_tb[] =
    213 {
    214  {
    215  (char *)"text/x-remmina-tb",
    216  GTK_TARGET_SAME_APP,
    217  0
    218  },
    219 };
    220 
    222 {
    223  TRACE_CALL(__func__);
    224  GtkCssProvider *provider;
    225 
    226  provider = gtk_css_provider_new();
    227 
    228  /* It’s important to remove padding, border and shadow from GtkViewport or
    229  * we will never know its internal area size, because GtkViweport::viewport_get_view_allocation,
    230  * which returns the internal size of the GtkViewport, is private and we cannot access it */
    231 
    232 #if GTK_CHECK_VERSION(3, 14, 0)
    233  gtk_css_provider_load_from_data(provider,
    234  "#remmina-cw-viewport, #remmina-cw-aspectframe {\n"
    235  " padding:0;\n"
    236  " border:0;\n"
    237  " background-color: black;\n"
    238  "}\n"
    239  "GtkDrawingArea {\n"
    240  "}\n"
    241  "GtkToolbar {\n"
    242  " -GtkWidget-window-dragging: 0;\n"
    243  "}\n"
    244  "#remmina-connection-window-fullscreen {\n"
    245  " border-color: black;\n"
    246  "}\n"
    247  "#remmina-small-button {\n"
    248  " outline-offset: 0;\n"
    249  " outline-width: 0;\n"
    250  " padding: 0;\n"
    251  " border: 0;\n"
    252  "}\n"
    253  "#remmina-pin-button {\n"
    254  " outline-offset: 0;\n"
    255  " outline-width: 0;\n"
    256  " padding: 2px;\n"
    257  " border: 0;\n"
    258  "}\n"
    259  "#remmina-tab-page {\n"
    260  " background-color: black;\n"
    261  "}\n"
    262  "#remmina-scrolled-container {\n"
    263  "}\n"
    264  "#remmina-scrolled-container.undershoot {\n"
    265  " background: none;\n"
    266  "}\n"
    267  "#remmina-tab-page {\n"
    268  "}\n"
    269  "#ftbbox-upper {\n"
    270  " background-color: white;\n"
    271  " color: black;\n"
    272  " border-style: none solid solid solid;\n"
    273  " border-width: 1px;\n"
    274  " border-radius: 4px;\n"
    275  " padding: 0px;\n"
    276  "}\n"
    277  "#ftbbox-lower {\n"
    278  " background-color: white;\n"
    279  " color: black;\n"
    280  " border-style: solid solid none solid;\n"
    281  " border-width: 1px;\n"
    282  " border-radius: 4px;\n"
    283  " padding: 0px;\n"
    284  "}\n"
    285  "#ftb-handle {\n"
    286  "}\n"
    287  ".message_panel {\n"
    288  " border: 0px solid;\n"
    289  " padding: 20px 20px 20px 20px;\n"
    290  "}\n"
    291  ".message_panel entry {\n"
    292  " background-image: none;\n"
    293  " border-width: 4px;\n"
    294  " border-radius: 8px;\n"
    295  "}\n"
    296  ".message_panel .title_label {\n"
    297  " font-size: 2em; \n"
    298  "}\n"
    299  , -1, NULL);
    300 
    301 #else
    302  gtk_css_provider_load_from_data(provider,
    303  "#remmina-cw-viewport, #remmina-cw-aspectframe {\n"
    304  " padding:0;\n"
    305  " border:0;\n"
    306  " background-color: black;\n"
    307  "}\n"
    308  "#remmina-cw-message-panel {\n"
    309  "}\n"
    310  "GtkDrawingArea {\n"
    311  "}\n"
    312  "GtkToolbar {\n"
    313  " -GtkWidget-window-dragging: 0;\n"
    314  "}\n"
    315  "#remmina-connection-window-fullscreen {\n"
    316  " border-color: black;\n"
    317  "}\n"
    318  "#remmina-small-button {\n"
    319  " -GtkWidget-focus-padding: 0;\n"
    320  " -GtkWidget-focus-line-width: 0;\n"
    321  " padding: 0;\n"
    322  " border: 0;\n"
    323  "}\n"
    324  "#remmina-pin-button {\n"
    325  " -GtkWidget-focus-padding: 0;\n"
    326  " -GtkWidget-focus-line-width: 0;\n"
    327  " padding: 2px;\n"
    328  " border: 0;\n"
    329  "}\n"
    330  "#remmina-scrolled-container {\n"
    331  "}\n"
    332  "#remmina-scrolled-container.undershoot {\n"
    333  " background: none\n"
    334  "}\n"
    335  "#remmina-tab-page {\n"
    336  "}\n"
    337  "#ftbbox-upper {\n"
    338  " border-style: none solid solid solid;\n"
    339  " border-width: 1px;\n"
    340  " border-radius: 4px;\n"
    341  " padding: 0px;\n"
    342  "}\n"
    343  "#ftbbox-lower {\n"
    344  " border-style: solid solid none solid;\n"
    345  " border-width: 1px;\n"
    346  " border-radius: 4px;\n"
    347  " padding: 0px;\n"
    348  "}\n"
    349  "#ftb-handle {\n"
    350  "}\n"
    351 
    352  , -1, NULL);
    353 #endif
    354 
    355  gtk_style_context_add_provider_for_screen(gdk_screen_get_default(),
    356  GTK_STYLE_PROVIDER(provider),
    357  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    358 
    359  g_object_unref(provider);
    360 
    361  /* Define a signal used to notify all rcws of toolbar move */
    362  rcw_signals[TOOLBARPLACE_SIGNAL] = g_signal_new("toolbar-place", G_TYPE_FROM_CLASS(klass),
    363  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaConnectionWindowClass, toolbar_place), NULL, NULL,
    364  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    365 }
    366 
    368 {
    369  GtkWidget *po;
    370 
    371  if (!cnnwin->priv->notebook)
    372  return NULL;
    373  po = gtk_notebook_get_nth_page(GTK_NOTEBOOK(cnnwin->priv->notebook), npage);
    374  return g_object_get_data(G_OBJECT(po), "cnnobj");
    375 }
    376 
    378 {
    379  gint np;
    380 
    381  if (cnnwin != NULL && cnnwin->priv != NULL && cnnwin->priv->notebook != NULL) {
    382  np = gtk_notebook_get_current_page(GTK_NOTEBOOK(cnnwin->priv->notebook));
    383  if (np < 0)
    384  return NULL;
    385  return rcw_get_cnnobj_at_page(cnnwin, np);
    386  } else {
    387  return NULL;
    388  }
    389 }
    390 
    391 static RemminaScaleMode get_current_allowed_scale_mode(RemminaConnectionObject *cnnobj, gboolean *dynres_avail, gboolean *scale_avail)
    392 {
    393  TRACE_CALL(__func__);
    394  RemminaScaleMode scalemode;
    395  gboolean plugin_has_dynres, plugin_can_scale;
    396 
    397  scalemode = remmina_protocol_widget_get_current_scale_mode(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    398 
    399  plugin_has_dynres = remmina_protocol_widget_query_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    401 
    402  plugin_can_scale = remmina_protocol_widget_query_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    404 
    405  /* Forbid scalemode REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES when not possible */
    406  if ((!plugin_has_dynres) && scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES)
    408 
    409  /* Forbid scalemode REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED when not possible */
    410  if (!plugin_can_scale && scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED)
    412 
    413  if (scale_avail)
    414  *scale_avail = plugin_can_scale;
    415  if (dynres_avail)
    416  *dynres_avail = (plugin_has_dynres && cnnobj->dynres_unlocked);
    417 
    418  return scalemode;
    419 }
    420 
    422 {
    423  TRACE_CALL(__func__);
    424 
    425  /* Disconnects the connection which is currently in view in the notebook */
    426  remmina_protocol_widget_close_connection(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    427 }
    428 
    430 {
    431  TRACE_CALL(__func__);
    432  GdkDisplay *display;
    433 
    434 #if GTK_CHECK_VERSION(3, 20, 0)
    435  GdkSeat *seat;
    436 #else
    437  GdkDeviceManager *manager;
    438  GdkDevice *keyboard = NULL;
    439 #endif
    440 
    441  if (cnnwin->priv->grab_retry_eventsourceid) {
    442  g_source_remove(cnnwin->priv->grab_retry_eventsourceid);
    443  cnnwin->priv->grab_retry_eventsourceid = 0;
    444  }
    445  if (cnnwin->priv->delayed_grab_eventsourceid) {
    446  g_source_remove(cnnwin->priv->delayed_grab_eventsourceid);
    447  cnnwin->priv->delayed_grab_eventsourceid = 0;
    448  }
    449 
    450  display = gtk_widget_get_display(GTK_WIDGET(cnnwin));
    451 #if GTK_CHECK_VERSION(3, 20, 0)
    452  seat = gdk_display_get_default_seat(display);
    453  // keyboard = gdk_seat_get_pointer(seat);
    454 #else
    455  manager = gdk_display_get_device_manager(display);
    456  keyboard = gdk_device_manager_get_client_pointer(manager);
    457 #endif
    458 
    459  if (!cnnwin->priv->kbcaptured && !cnnwin->priv->pointer_captured)
    460  return;
    461 
    462 #if DEBUG_KB_GRABBING
    463  printf("DEBUG_KB_GRABBING: --- ungrabbing\n");
    464 #endif
    465 
    466 
    467 
    468 #if GTK_CHECK_VERSION(3, 20, 0)
    469  /* We can use gtk_seat_grab()/_ungrab() only after GTK 3.24 */
    470  gdk_seat_ungrab(seat);
    471 #else
    472  if (keyboard != NULL) {
    473  if (gdk_device_get_source(keyboard) != GDK_SOURCE_KEYBOARD)
    474  keyboard = gdk_device_get_associated_device(keyboard);
    475  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
    476  gdk_device_ungrab(keyboard, GDK_CURRENT_TIME);
    477  G_GNUC_END_IGNORE_DEPRECATIONS
    478  }
    479 #endif
    480  cnnwin->priv->kbcaptured = FALSE;
    481  cnnwin->priv->pointer_captured = FALSE;
    482 }
    483 
    484 static gboolean rcw_keyboard_grab_retry(gpointer user_data)
    485 {
    486  TRACE_CALL(__func__);
    487  RemminaConnectionWindow *cnnwin = (RemminaConnectionWindow *)user_data;
    488 
    489 #if DEBUG_KB_GRABBING
    490  printf("%s retry grab\n", __func__);
    491 #endif
    492  rcw_keyboard_grab(cnnwin);
    493  cnnwin->priv->grab_retry_eventsourceid = 0;
    494  return G_SOURCE_REMOVE;
    495 }
    496 
    498 {
    499  TRACE_CALL(__func__);
    500 #if GTK_CHECK_VERSION(3, 20, 0)
    501  GdkSeat *seat;
    502  GdkDisplay *display;
    503  if (!cnnwin->priv->pointer_captured)
    504  return;
    505 
    506  display = gtk_widget_get_display(GTK_WIDGET(cnnwin));
    507  seat = gdk_display_get_default_seat(display);
    508  gdk_seat_ungrab(seat);
    509 #endif
    510 }
    511 
    513 {
    514  TRACE_CALL(__func__);
    515  /* This function in Wayland is useless and generates a spurious leave-notify event.
    516  * Should we remove it ? https://gitlab.gnome.org/GNOME/mutter/-/issues/2450#note_1588081 */
    517 #if GTK_CHECK_VERSION(3, 20, 0)
    518  GdkSeat *seat;
    519  GdkDisplay *display;
    520  GdkGrabStatus ggs;
    521 
    522 
    523  if (cnnwin->priv->pointer_captured) {
    524 #if DEBUG_KB_GRABBING
    525  printf("DEBUG_KB_GRABBING: pointer_captured is true, it should not\n");
    526 #endif
    527  return;
    528  }
    529 
    530  display = gtk_widget_get_display(GTK_WIDGET(cnnwin));
    531  seat = gdk_display_get_default_seat(display);
    532  ggs = gdk_seat_grab(seat, gtk_widget_get_window(GTK_WIDGET(cnnwin)),
    533  GDK_SEAT_CAPABILITY_ALL_POINTING, TRUE, NULL, NULL, NULL, NULL);
    534  if (ggs != GDK_GRAB_SUCCESS) {
    535 #if DEBUG_KB_GRABBING
    536  printf("DEBUG_KB_GRABBING: GRAB of POINTER failed. GdkGrabStatus: %d\n", (int)ggs);
    537 #endif
    538  } else {
    539  cnnwin->priv->pointer_captured = TRUE;
    540  }
    541 
    542 #endif
    543 }
    544 
    546 {
    547  TRACE_CALL(__func__);
    548  GdkDisplay *display;
    549 
    550 #if GTK_CHECK_VERSION(3, 20, 0)
    551  GdkSeat *seat;
    552 #else
    553  GdkDeviceManager *manager;
    554 #endif
    555  GdkGrabStatus ggs;
    556  GdkDevice *keyboard = NULL;
    557 
    558  if (cnnwin->priv->kbcaptured) {
    559 #if DEBUG_KB_GRABBING
    560  printf("DEBUG_KB_GRABBING: %s not grabbing because already grabbed.\n", __func__);
    561 #endif
    562  return;
    563  }
    564 
    565  display = gtk_widget_get_display(GTK_WIDGET(cnnwin));
    566 #if GTK_CHECK_VERSION(3, 20, 0)
    567  seat = gdk_display_get_default_seat(display);
    568  keyboard = gdk_seat_get_pointer(seat);
    569 #else
    570  manager = gdk_display_get_device_manager(display);
    571  keyboard = gdk_device_manager_get_client_pointer(manager);
    572 #endif
    573 
    574  if (keyboard != NULL) {
    575  if (gdk_device_get_source(keyboard) != GDK_SOURCE_KEYBOARD)
    576  keyboard = gdk_device_get_associated_device(keyboard);
    577 
    578 
    579 #if DEBUG_KB_GRABBING
    580  printf("DEBUG_KB_GRABBING: profile asks for grabbing, let’s try.\n");
    581 #endif
    582  /* Up to GTK version 3.20 we can grab the keyboard with gdk_device_grab().
    583  * in GTK 3.20 gdk_seat_grab() should be used instead of gdk_device_grab().
    584  * There is a bug in GTK up to 3.22: When gdk_device_grab() fails
    585  * the widget is hidden:
    586  * https://gitlab.gnome.org/GNOME/gtk/commit/726ad5a5ae7c4f167e8dd454cd7c250821c400ab
    587  * The bugfix will be released with GTK 3.24.
    588  * Also please note that the newer gdk_seat_grab() is still calling gdk_device_grab().
    589  *
    590  * Warning: gdk_seat_grab() will call XGrabKeyboard() or XIGrabDevice()
    591  * which in turn will generate a core X input event FocusOut and FocusIn
    592  * but not Xinput2 events.
    593  * In some cases, GTK is unable to neutralize FocusIn and FocusOut core
    594  * events (ie: i3wm+Plasma with GDK_CORE_DEVICE_EVENTS=1 because detail=NotifyNonlinear
    595  * instead of detail=NotifyAncestor/detail=NotifyInferior)
    596  * Receiving a FocusOut event for Remmina at this time will cause an infinite loop.
    597  * Therefore is important for GTK to use Xinput2 instead of core X events
    598  * by unsetting GDK_CORE_DEVICE_EVENTS
    599  */
    600 #if GTK_CHECK_VERSION(3, 20, 0)
    601  ggs = gdk_seat_grab(seat, gtk_widget_get_window(GTK_WIDGET(cnnwin)),
    602  GDK_SEAT_CAPABILITY_KEYBOARD, TRUE, NULL, NULL, NULL, NULL);
    603 #else
    604  ggs = gdk_device_grab(keyboard, gtk_widget_get_window(GTK_WIDGET(cnnwin)), GDK_OWNERSHIP_WINDOW,
    605  TRUE, GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, GDK_CURRENT_TIME);
    606 #endif
    607  if (ggs != GDK_GRAB_SUCCESS) {
    608 #if DEBUG_KB_GRABBING
    609  printf("GRAB of keyboard failed.\n");
    610 #endif
    611  /* Reschedule grabbing in half a second if not already done */
    612  if (cnnwin->priv->grab_retry_eventsourceid == 0)
    613  cnnwin->priv->grab_retry_eventsourceid = g_timeout_add(500, (GSourceFunc)rcw_keyboard_grab_retry, cnnwin);
    614  } else {
    615 #if DEBUG_KB_GRABBING
    616  printf("Keyboard grabbed\n");
    617 #endif
    618  if (cnnwin->priv->grab_retry_eventsourceid != 0) {
    619  g_source_remove(cnnwin->priv->grab_retry_eventsourceid);
    620  cnnwin->priv->grab_retry_eventsourceid = 0;
    621  }
    622  cnnwin->priv->kbcaptured = TRUE;
    623  }
    624  } else {
    625  rcw_kp_ungrab(cnnwin);
    626  }
    627 }
    628 
    630 {
    631  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    632  GtkNotebook *notebook = GTK_NOTEBOOK(priv->notebook);
    633  GtkWidget *w;
    634  RemminaConnectionObject *cnnobj;
    635  gint i, n;
    636 
    637  if (GTK_IS_WIDGET(notebook)) {
    638  n = gtk_notebook_get_n_pages(notebook);
    639  for (i = n - 1; i >= 0; i--) {
    640  w = gtk_notebook_get_nth_page(notebook, i);
    641  cnnobj = (RemminaConnectionObject *)g_object_get_data(G_OBJECT(w), "cnnobj");
    642  /* Do close the connection on this tab */
    643  remmina_protocol_widget_close_connection(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    644  }
    645  }
    646 }
    647 
    649 {
    650  TRACE_CALL(__func__);
    651  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    652  GtkNotebook *notebook = GTK_NOTEBOOK(priv->notebook);
    653  GtkWidget *dialog;
    654  gint i, n, nopen;
    655 
    656  if (!REMMINA_IS_CONNECTION_WINDOW(cnnwin))
    657  return TRUE;
    658 
    659  if (cnnwin->priv->on_delete_confirm_mode != RCW_ONDELETE_NOCONFIRM) {
    660  n = gtk_notebook_get_n_pages(notebook);
    661  nopen = 0;
    662  /* count all non-closed connections */
    663  for(i = 0; i < n; i ++) {
    664  RemminaConnectionObject *cnnobj = rcw_get_cnnobj_at_page(cnnwin, i);
    666  nopen ++;
    667  }
    668  if (nopen > 1) {
    669  dialog = gtk_message_dialog_new(GTK_WINDOW(cnnwin), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
    670  GTK_BUTTONS_YES_NO,
    671  _("Are you sure you want to close %i active connections in the current window?"), nopen);
    672  i = gtk_dialog_run(GTK_DIALOG(dialog));
    673  gtk_widget_destroy(dialog);
    674  if (i != GTK_RESPONSE_YES)
    675  return FALSE;
    676  }
    677  else if (nopen == 1) {
    678  if (remmina_pref.confirm_close) {
    679  dialog = gtk_message_dialog_new(GTK_WINDOW(cnnwin), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
    680  GTK_BUTTONS_YES_NO,
    681  _("Are you sure you want to close this last active connection?"));
    682  i = gtk_dialog_run(GTK_DIALOG(dialog));
    683  gtk_widget_destroy(dialog);
    684  if (i != GTK_RESPONSE_YES)
    685  return FALSE;
    686  }
    687  }
    688  }
    690 
    691  return TRUE;
    692 }
    693 
    694 static gboolean rcw_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
    695 {
    696  TRACE_CALL(__func__);
    697  rcw_delete(RCW(widget));
    698  return TRUE;
    699 }
    700 
    701 static void rcw_destroy(GtkWidget *widget, gpointer data)
    702 {
    703  TRACE_CALL(__func__);
    705  RemminaConnectionWindow *cnnwin;
    706 
    707  if (!REMMINA_IS_CONNECTION_WINDOW(widget))
    708  return;
    709 
    710  cnnwin = (RemminaConnectionWindow *)widget;
    711  priv = cnnwin->priv;
    712 
    713  if (priv->kbcaptured)
    714  rcw_kp_ungrab(cnnwin);
    715 
    716  if (priv->acs_eventsourceid) {
    717  g_source_remove(priv->acs_eventsourceid);
    718  priv->acs_eventsourceid = 0;
    719  }
    720  if (priv->spf_eventsourceid) {
    721  g_source_remove(priv->spf_eventsourceid);
    722  priv->spf_eventsourceid = 0;
    723  }
    724  if (priv->grab_retry_eventsourceid) {
    725  g_source_remove(priv->grab_retry_eventsourceid);
    726  priv->grab_retry_eventsourceid = 0;
    727  }
    728  if (cnnwin->priv->delayed_grab_eventsourceid) {
    729  g_source_remove(cnnwin->priv->delayed_grab_eventsourceid);
    730  cnnwin->priv->delayed_grab_eventsourceid = 0;
    731  }
    732  if (priv->ftb_hide_eventsource) {
    733  g_source_remove(priv->ftb_hide_eventsource);
    734  priv->ftb_hide_eventsource = 0;
    735  }
    736  if (priv->tar_eventsource) {
    737  g_source_remove(priv->tar_eventsource);
    738  priv->tar_eventsource = 0;
    739  }
    740  if (priv->hidetb_eventsource) {
    741  g_source_remove(priv->hidetb_eventsource);
    742  priv->hidetb_eventsource = 0;
    743  }
    744  if (priv->dwp_eventsourceid) {
    745  g_source_remove(priv->dwp_eventsourceid);
    746  priv->dwp_eventsourceid = 0;
    747  }
    748 
    749  /* There is no need to destroy priv->floating_toolbar_widget,
    750  * because it’s our child and will be destroyed automatically */
    751 
    752  cnnwin->priv = NULL;
    753  g_free(priv);
    754 }
    755 
    756 gboolean rcw_notify_widget_toolbar_placement(GtkWidget *widget, gpointer data)
    757 {
    758  TRACE_CALL(__func__);
    759  GType rcwtype;
    760 
    761  rcwtype = rcw_get_type();
    762  if (G_TYPE_CHECK_INSTANCE_TYPE(widget, rcwtype)) {
    763  g_signal_emit_by_name(G_OBJECT(widget), "toolbar-place");
    764  return TRUE;
    765  }
    766  return FALSE;
    767 }
    768 
    769 static gboolean rcw_tb_drag_failed(GtkWidget *widget, GdkDragContext *context,
    770  GtkDragResult result, gpointer user_data)
    771 {
    772  TRACE_CALL(__func__);
    774  RemminaConnectionWindow *cnnwin;
    775 
    776 
    777  cnnwin = (RemminaConnectionWindow *)user_data;
    778  priv = cnnwin->priv;
    779 
    780  if (priv->toolbar)
    781  gtk_widget_show(GTK_WIDGET(priv->toolbar));
    782 
    783  return TRUE;
    784 }
    785 
    786 static gboolean rcw_tb_drag_drop(GtkWidget *widget, GdkDragContext *context,
    787  gint x, gint y, guint time, gpointer user_data)
    788 {
    789  TRACE_CALL(__func__);
    790  GtkAllocation wa;
    791  gint new_toolbar_placement;
    793  RemminaConnectionWindow *cnnwin;
    794 
    795  cnnwin = (RemminaConnectionWindow *)user_data;
    796  priv = cnnwin->priv;
    797 
    798  gtk_widget_get_allocation(widget, &wa);
    799 
    800  if (wa.width * y >= wa.height * x) {
    801  if (wa.width * y > wa.height * (wa.width - x))
    802  new_toolbar_placement = TOOLBAR_PLACEMENT_BOTTOM;
    803  else
    804  new_toolbar_placement = TOOLBAR_PLACEMENT_LEFT;
    805  } else {
    806  if (wa.width * y > wa.height * (wa.width - x))
    807  new_toolbar_placement = TOOLBAR_PLACEMENT_RIGHT;
    808  else
    809  new_toolbar_placement = TOOLBAR_PLACEMENT_TOP;
    810  }
    811 
    812  gtk_drag_finish(context, TRUE, TRUE, time);
    813 
    814  if (new_toolbar_placement != remmina_pref.toolbar_placement) {
    815  /* Save new position */
    816  remmina_pref.toolbar_placement = new_toolbar_placement;
    818 
    819  /* Signal all windows that the toolbar must be moved */
    821  }
    822  if (priv->toolbar)
    823  gtk_widget_show(GTK_WIDGET(priv->toolbar));
    824 
    825  return TRUE;
    826 }
    827 
    828 static void rcw_tb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
    829 {
    830  TRACE_CALL(__func__);
    831 
    832  cairo_surface_t *surface;
    833  cairo_t *cr;
    834  GtkAllocation wa;
    835  double dashes[] = { 10 };
    836 
    837  gtk_widget_get_allocation(widget, &wa);
    838 
    839  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 16, 16);
    840  cr = cairo_create(surface);
    841  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
    842  cairo_set_line_width(cr, 4);
    843  cairo_set_dash(cr, dashes, 1, 0);
    844  cairo_rectangle(cr, 0, 0, 16, 16);
    845  cairo_stroke(cr);
    846  cairo_destroy(cr);
    847 
    848  gtk_widget_hide(widget);
    849 
    850  gtk_drag_set_icon_surface(context, surface);
    851 }
    852 
    854 {
    855  TRACE_CALL(__func__);
    856  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    857  RemminaConnectionObject *cnnobj;
    858 
    859  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    860  if (!cnnobj) return;
    861 
    862  priv->floating_toolbar_opacity = (1.0 - TOOLBAR_OPACITY_MIN) / ((gdouble)TOOLBAR_OPACITY_LEVEL)
    863  * ((gdouble)(TOOLBAR_OPACITY_LEVEL - remmina_file_get_int(cnnobj->remmina_file, "toolbar_opacity", 0)))
    864  + TOOLBAR_OPACITY_MIN;
    865  if (priv->floating_toolbar_widget)
    866  gtk_widget_set_opacity(GTK_WIDGET(priv->overlay_ftb_overlay), priv->floating_toolbar_opacity);
    867 }
    868 
    869 static gboolean rcw_floating_toolbar_make_invisible(gpointer data)
    870 {
    871  TRACE_CALL(__func__);
    873 
    874  gtk_widget_set_opacity(GTK_WIDGET(priv->overlay_ftb_overlay), 0.0);
    875  priv->ftb_hide_eventsource = 0;
    876  return G_SOURCE_REMOVE;
    877 }
    878 
    879 static void rcw_floating_toolbar_show(RemminaConnectionWindow *cnnwin, gboolean show)
    880 {
    881  TRACE_CALL(__func__);
    882  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    883 
    884  if (priv->floating_toolbar_widget == NULL)
    885  return;
    886 
    887  if (show || priv->pin_down) {
    888  /* Make the FTB no longer transparent, in case we have an hidden toolbar */
    890  /* Remove outstanding hide events, if not yet active */
    891  if (priv->ftb_hide_eventsource) {
    892  g_source_remove(priv->ftb_hide_eventsource);
    893  priv->ftb_hide_eventsource = 0;
    894  }
    895  } else {
    896  /* If we are hiding and the toolbar must be made invisible, schedule
    897  * a later toolbar hide */
    899  if (priv->ftb_hide_eventsource == 0)
    900  priv->ftb_hide_eventsource = g_timeout_add(1000, rcw_floating_toolbar_make_invisible, priv);
    901  }
    902 
    903  gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer), show || priv->pin_down);
    904 }
    905 
    906 static void rco_get_desktop_size(RemminaConnectionObject *cnnobj, gint *width, gint *height)
    907 {
    908  TRACE_CALL(__func__);
    909  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    910 
    911 
    914  if (*width == 0) {
    915  /* Before connecting we do not have real remote width/height,
    916  * so we ask profile values */
    919  }
    920 }
    921 
    922 void rco_set_scrolled_policy(RemminaScaleMode scalemode, GtkScrolledWindow *scrolled_window)
    923 {
    924  TRACE_CALL(__func__);
    925 
    926  gtk_scrolled_window_set_policy(scrolled_window,
    927  scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC,
    928  scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC);
    929 }
    930 
    931 static GtkWidget *rco_create_scrolled_container(RemminaScaleMode scalemode, int view_mode)
    932 {
    933  GtkWidget *scrolled_container;
    934 
    935  if (view_mode == VIEWPORT_FULLSCREEN_MODE) {
    936  scrolled_container = remmina_scrolled_viewport_new();
    937  } else {
    938  scrolled_container = gtk_scrolled_window_new(NULL, NULL);
    939  rco_set_scrolled_policy(scalemode, GTK_SCROLLED_WINDOW(scrolled_container));
    940  gtk_container_set_border_width(GTK_CONTAINER(scrolled_container), 0);
    941  gtk_widget_set_can_focus(scrolled_container, FALSE);
    942  }
    943 
    944  gtk_widget_set_name(scrolled_container, "remmina-scrolled-container");
    945  gtk_widget_show(scrolled_container);
    946 
    947  return scrolled_container;
    948 }
    949 
    951 {
    952  TRACE_CALL(__func__);
    953 
    954  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    955  RemminaConnectionObject *cnnobj;
    956  gint dwidth, dheight;
    957  GtkAllocation nba, ca, ta;
    958 
    959  cnnwin->priv->tar_eventsource = 0;
    960 
    961  if (priv->toolbar_is_reconfiguring)
    962  return G_SOURCE_REMOVE;
    963 
    964  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return FALSE;
    965 
    966  if (cnnobj->connected && GTK_IS_SCROLLED_WINDOW(cnnobj->scrolled_container)) {
    967  rco_get_desktop_size(cnnobj, &dwidth, &dheight);
    968  gtk_widget_get_allocation(GTK_WIDGET(priv->notebook), &nba);
    969  gtk_widget_get_allocation(cnnobj->scrolled_container, &ca);
    970  gtk_widget_get_allocation(priv->toolbar, &ta);
    971  if (remmina_pref.toolbar_placement == TOOLBAR_PLACEMENT_LEFT ||
    973  gtk_window_resize(GTK_WINDOW(cnnobj->cnnwin), MAX(1, dwidth + ta.width + nba.width - ca.width),
    974  MAX(1, dheight + nba.height - ca.height));
    975  else
    976  gtk_window_resize(GTK_WINDOW(cnnobj->cnnwin), MAX(1, dwidth + nba.width - ca.width),
    977  MAX(1, dheight + ta.height + nba.height - ca.height));
    978  gtk_container_check_resize(GTK_CONTAINER(cnnobj->cnnwin));
    979  }
    980  if (GTK_IS_SCROLLED_WINDOW(cnnobj->scrolled_container)) {
    981  RemminaScaleMode scalemode = get_current_allowed_scale_mode(cnnobj, NULL, NULL);
    982  rco_set_scrolled_policy(scalemode, GTK_SCROLLED_WINDOW(cnnobj->scrolled_container));
    983  }
    984 
    985  return G_SOURCE_REMOVE;
    986 }
    987 
    988 static void rcw_toolbar_autofit(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    989 {
    990  TRACE_CALL(__func__);
    991  RemminaConnectionObject *cnnobj;
    992 
    993  if (cnnwin->priv->toolbar_is_reconfiguring)
    994  return;
    995  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    996 
    997  if (GTK_IS_SCROLLED_WINDOW(cnnobj->scrolled_container)) {
    998  if ((gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(cnnwin))) & GDK_WINDOW_STATE_MAXIMIZED) != 0)
    999  gtk_window_unmaximize(GTK_WINDOW(cnnwin));
    1000 
    1001  /* It’s tricky to make the toolbars disappear automatically, while keeping scrollable.
    1002  * Please tell me if you know a better way to do this */
    1003  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
    1004 
    1005  cnnwin->priv->tar_eventsource = g_timeout_add(200, (GSourceFunc)rcw_toolbar_autofit_restore, cnnwin);
    1006  }
    1007 }
    1008 
    1009 void rco_get_monitor_geometry(RemminaConnectionObject *cnnobj, GdkRectangle *sz)
    1010 {
    1011  TRACE_CALL(__func__);
    1012 
    1013  /* Fill sz with the monitor (or workarea) size and position
    1014  * of the monitor (or workarea) where cnnobj->cnnwin is located */
    1015 
    1016  GdkRectangle monitor_geometry;
    1017 
    1018  sz->x = sz->y = sz->width = sz->height = 0;
    1019 
    1020  if (!cnnobj)
    1021  return;
    1022  if (!cnnobj->cnnwin)
    1023  return;
    1024  if (!gtk_widget_is_visible(GTK_WIDGET(cnnobj->cnnwin)))
    1025  return;
    1026 
    1027 #if GTK_CHECK_VERSION(3, 22, 0)
    1028  GdkDisplay *display;
    1029  GdkMonitor *monitor;
    1030  display = gtk_widget_get_display(GTK_WIDGET(cnnobj->cnnwin));
    1031  monitor = gdk_display_get_monitor_at_window(display, gtk_widget_get_window(GTK_WIDGET(cnnobj->cnnwin)));
    1032 #else
    1033  GdkScreen *screen;
    1034  gint monitor;
    1035  screen = gtk_window_get_screen(GTK_WINDOW(cnnobj->cnnwin));
    1036  monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(GTK_WIDGET(cnnobj->cnnwin)));
    1037 #endif
    1038 
    1039 #if GTK_CHECK_VERSION(3, 22, 0)
    1040  gdk_monitor_get_workarea(monitor, &monitor_geometry);
    1041  /* Under Wayland, GTK 3.22, all values returned by gdk_monitor_get_geometry()
    1042  * and gdk_monitor_get_workarea() seem to have been divided by the
    1043  * gdk scale factor, so we need to adjust the returned rect
    1044  * undoing the division */
    1045 #ifdef GDK_WINDOWING_WAYLAND
    1046  if (GDK_IS_WAYLAND_DISPLAY(display)) {
    1047  int monitor_scale_factor = gdk_monitor_get_scale_factor(monitor);
    1048  monitor_geometry.width *= monitor_scale_factor;
    1049  monitor_geometry.height *= monitor_scale_factor;
    1050  }
    1051 #endif
    1052 #elif gdk_screen_get_monitor_workarea
    1053  gdk_screen_get_monitor_workarea(screen, monitor, &monitor_geometry);
    1054 #else
    1055  gdk_screen_get_monitor_geometry(screen, monitor, &monitor_geometry);
    1056 #endif
    1057  *sz = monitor_geometry;
    1058 }
    1059 
    1061 {
    1062  TRACE_CALL(__func__);
    1063  gboolean scroll_required = FALSE;
    1064 
    1065  GdkRectangle monitor_geometry;
    1066  gint rd_width, rd_height;
    1067  gint bordersz;
    1068  gint scalemode;
    1069 
    1070  scalemode = remmina_protocol_widget_get_current_scale_mode(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1071 
    1072  /* Get remote destkop size */
    1073  rco_get_desktop_size(cnnobj, &rd_width, &rd_height);
    1074 
    1075  /* Get our monitor size */
    1076  rco_get_monitor_geometry(cnnobj, &monitor_geometry);
    1077 
    1078  if (!remmina_protocol_widget_get_expand(REMMINA_PROTOCOL_WIDGET(cnnobj->proto)) &&
    1079  (monitor_geometry.width < rd_width || monitor_geometry.height < rd_height) &&
    1081  scroll_required = TRUE;
    1082 
    1083  switch (cnnobj->cnnwin->priv->view_mode) {
    1085  gtk_window_resize(GTK_WINDOW(cnnobj->cnnwin), monitor_geometry.width, monitor_geometry.height);
    1086  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container),
    1087  (scroll_required ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER),
    1088  (scroll_required ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER));
    1089  break;
    1090 
    1092  bordersz = scroll_required ? SCROLL_BORDER_SIZE : 0;
    1093  gtk_window_resize(GTK_WINDOW(cnnobj->cnnwin), monitor_geometry.width, monitor_geometry.height);
    1094  if (REMMINA_IS_SCROLLED_VIEWPORT(cnnobj->scrolled_container))
    1095  /* Put a border around Notebook content (RemminaScrolledViewpord), so we can
    1096  * move the mouse over the border to scroll */
    1097  gtk_container_set_border_width(GTK_CONTAINER(cnnobj->scrolled_container), bordersz);
    1098 
    1099  break;
    1100 
    1101  case SCROLLED_WINDOW_MODE:
    1102  if (remmina_file_get_int(cnnobj->remmina_file, "viewmode", UNDEFINED_MODE) == UNDEFINED_MODE) {
    1103  /* ToDo: is this really needed ? When ? */
    1104  gtk_window_set_default_size(GTK_WINDOW(cnnobj->cnnwin),
    1105  MIN(rd_width, monitor_geometry.width), MIN(rd_height, monitor_geometry.height));
    1106  if (rd_width >= monitor_geometry.width || rd_height >= monitor_geometry.height) {
    1107  gtk_window_maximize(GTK_WINDOW(cnnobj->cnnwin));
    1108  remmina_file_set_int(cnnobj->remmina_file, "window_maximize", TRUE);
    1109  } else {
    1110  rcw_toolbar_autofit(NULL, cnnobj->cnnwin);
    1111  remmina_file_set_int(cnnobj->remmina_file, "window_maximize", FALSE);
    1112  }
    1113  } else {
    1114  if (remmina_file_get_int(cnnobj->remmina_file, "window_maximize", FALSE))
    1115  gtk_window_maximize(GTK_WINDOW(cnnobj->cnnwin));
    1116  }
    1117  break;
    1118 
    1119  default:
    1120  break;
    1121  }
    1122 }
    1123 
    1124 static void rcw_set_tooltip(GtkWidget *item, const gchar *tip, guint key1, guint key2)
    1125 {
    1126  TRACE_CALL(__func__);
    1127  gchar *s1;
    1128  gchar *s2;
    1129 
    1130  if (remmina_pref.hostkey && key1) {
    1131  if (key2)
    1132  s1 = g_strdup_printf(" (%s + %s,%s)", gdk_keyval_name(remmina_pref.hostkey),
    1133  gdk_keyval_name(gdk_keyval_to_upper(key1)), gdk_keyval_name(gdk_keyval_to_upper(key2)));
    1134  else if (key1 == remmina_pref.hostkey)
    1135  s1 = g_strdup_printf(" (%s)", gdk_keyval_name(remmina_pref.hostkey));
    1136  else
    1137  s1 = g_strdup_printf(" (%s + %s)", gdk_keyval_name(remmina_pref.hostkey),
    1138  gdk_keyval_name(gdk_keyval_to_upper(key1)));
    1139  } else {
    1140  s1 = NULL;
    1141  }
    1142  s2 = g_strdup_printf("%s%s", tip, s1 ? s1 : "");
    1143  gtk_widget_set_tooltip_text(item, s2);
    1144  g_free(s2);
    1145  g_free(s1);
    1146 }
    1147 
    1149 {
    1150  TRACE_CALL(__func__);
    1151  RemminaScaleMode scalemode;
    1152  gboolean scaledexpandedmode;
    1153  int rdwidth, rdheight;
    1154  gfloat aratio;
    1155 
    1156  if (!cnnobj->plugin_can_scale) {
    1157  /* If we have a plugin that cannot scale,
    1158  * (i.e. SFTP plugin), then we expand proto */
    1159  gtk_widget_set_halign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    1160  gtk_widget_set_valign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    1161  } else {
    1162  /* Plugin can scale */
    1163 
    1164  scalemode = get_current_allowed_scale_mode(cnnobj, NULL, NULL);
    1165  scaledexpandedmode = remmina_protocol_widget_get_expand(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1166 
    1167  /* Check if we need aspectframe and create/destroy it accordingly */
    1168  if (scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED && !scaledexpandedmode) {
    1169  /* We need an aspectframe as a parent of proto */
    1170  rdwidth = remmina_protocol_widget_get_width(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1171  rdheight = remmina_protocol_widget_get_height(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1172  aratio = (gfloat)rdwidth / (gfloat)rdheight;
    1173  if (!cnnobj->aspectframe) {
    1174  /* We need a new aspectframe */
    1175  cnnobj->aspectframe = gtk_aspect_frame_new(NULL, 0.5, 0.5, aratio, FALSE);
    1176  gtk_widget_set_name(cnnobj->aspectframe, "remmina-cw-aspectframe");
    1177  gtk_frame_set_shadow_type(GTK_FRAME(cnnobj->aspectframe), GTK_SHADOW_NONE);
    1178  g_object_ref(cnnobj->proto);
    1179  gtk_container_remove(GTK_CONTAINER(cnnobj->viewport), cnnobj->proto);
    1180  gtk_container_add(GTK_CONTAINER(cnnobj->viewport), cnnobj->aspectframe);
    1181  gtk_container_add(GTK_CONTAINER(cnnobj->aspectframe), cnnobj->proto);
    1182  g_object_unref(cnnobj->proto);
    1183  gtk_widget_show(cnnobj->aspectframe);
    1184  if (cnnobj != NULL && cnnobj->cnnwin != NULL && cnnobj->cnnwin->priv->notebook != NULL)
    1185  rcw_grab_focus(cnnobj->cnnwin);
    1186  } else {
    1187  gtk_aspect_frame_set(GTK_ASPECT_FRAME(cnnobj->aspectframe), 0.5, 0.5, aratio, FALSE);
    1188  }
    1189  } else {
    1190  /* We do not need an aspectframe as a parent of proto */
    1191  if (cnnobj->aspectframe) {
    1192  /* We must remove the old aspectframe reparenting proto to viewport */
    1193  g_object_ref(cnnobj->aspectframe);
    1194  g_object_ref(cnnobj->proto);
    1195  gtk_container_remove(GTK_CONTAINER(cnnobj->aspectframe), cnnobj->proto);
    1196  gtk_container_remove(GTK_CONTAINER(cnnobj->viewport), cnnobj->aspectframe);
    1197  g_object_unref(cnnobj->aspectframe);
    1198  cnnobj->aspectframe = NULL;
    1199  gtk_container_add(GTK_CONTAINER(cnnobj->viewport), cnnobj->proto);
    1200  g_object_unref(cnnobj->proto);
    1201  if (cnnobj != NULL && cnnobj->cnnwin != NULL && cnnobj->cnnwin->priv->notebook != NULL)
    1202  rcw_grab_focus(cnnobj->cnnwin);
    1203  }
    1204  }
    1205 
    1207  /* We have a plugin that can be scaled, and the scale button
    1208  * has been pressed. Give it the correct WxH maintaining aspect
    1209  * ratio of remote destkop size */
    1210  gtk_widget_set_halign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    1211  gtk_widget_set_valign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    1212  } else {
    1213  /* Plugin can scale, but no scaling is active. Ensure that we have
    1214  * aspectframe with a ratio of 1 */
    1215  gtk_widget_set_halign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_CENTER);
    1216  gtk_widget_set_valign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_CENTER);
    1217  }
    1218  }
    1219 }
    1220 
    1221 static void nb_set_current_page(GtkNotebook *notebook, GtkWidget *page)
    1222 {
    1223  gint np, i;
    1224 
    1225  np = gtk_notebook_get_n_pages(notebook);
    1226  for (i = 0; i < np; i++) {
    1227  if (gtk_notebook_get_nth_page(notebook, i) == page) {
    1228  gtk_notebook_set_current_page(notebook, i);
    1229  break;
    1230  }
    1231  }
    1232 }
    1233 
    1234 static void nb_migrate_message_panels(GtkWidget *frompage, GtkWidget *topage)
    1235 {
    1236  /* Migrate a single connection tab from a notebook to another one */
    1237  GList *lst, *l;
    1238 
    1239  /* Reparent message panels */
    1240  lst = gtk_container_get_children(GTK_CONTAINER(frompage));
    1241  for (l = lst; l != NULL; l = l->next) {
    1242  if (REMMINA_IS_MESSAGE_PANEL(l->data)) {
    1243  g_object_ref(l->data);
    1244  gtk_container_remove(GTK_CONTAINER(frompage), GTK_WIDGET(l->data));
    1245  gtk_container_add(GTK_CONTAINER(topage), GTK_WIDGET(l->data));
    1246  g_object_unref(l->data);
    1247  gtk_box_reorder_child(GTK_BOX(topage), GTK_WIDGET(l->data), 0);
    1248  }
    1249  }
    1250  g_list_free(lst);
    1251 
    1252 }
    1253 
    1255 {
    1256  /* Migrate a complete notebook from a window to another */
    1257 
    1258  gchar *tag;
    1259  gint cp, np, i;
    1260  GtkNotebook *from_notebook;
    1261  GtkWidget *frompage, *newpage, *old_scrolled_container;
    1262  RemminaConnectionObject *cnnobj;
    1263  RemminaScaleMode scalemode;
    1264 
    1265  /* Migrate TAG */
    1266  tag = g_strdup((gchar *)g_object_get_data(G_OBJECT(from), "tag"));
    1267  g_object_set_data_full(G_OBJECT(to), "tag", tag, (GDestroyNotify)g_free);
    1268 
    1269  /* Migrate notebook content */
    1270  from_notebook = from->priv->notebook;
    1271  if (from_notebook && GTK_IS_NOTEBOOK(from_notebook)) {
    1272 
    1273  cp = gtk_notebook_get_current_page(from_notebook);
    1274  np = gtk_notebook_get_n_pages(from_notebook);
    1275  /* Create pages on dest notebook and migrate
    1276  * page content */
    1277  for (i = 0; i < np; i++) {
    1278  frompage = gtk_notebook_get_nth_page(from_notebook, i);
    1279  cnnobj = g_object_get_data(G_OBJECT(frompage), "cnnobj");
    1280 
    1281  /* A scrolled container must be recreated, because it can be different on the new window/page
    1282  depending on view_mode */
    1283  scalemode = get_current_allowed_scale_mode(cnnobj, NULL, NULL);
    1284  old_scrolled_container = cnnobj->scrolled_container;
    1285  cnnobj->scrolled_container = rco_create_scrolled_container(scalemode, to->priv->view_mode);
    1286 
    1287  newpage = rcw_append_new_page(to, cnnobj);
    1288 
    1289  nb_migrate_message_panels(frompage, newpage);
    1290 
    1291  /* Reparent the viewport (which is inside scrolled_container) to the new page */
    1292  g_object_ref(cnnobj->viewport);
    1293  gtk_container_remove(GTK_CONTAINER(old_scrolled_container), cnnobj->viewport);
    1294  gtk_container_add(GTK_CONTAINER(cnnobj->scrolled_container), cnnobj->viewport);
    1295  g_object_unref(cnnobj->viewport);
    1296 
    1297  /* Destroy old scrolled_container. Not really needed, it will be destroyed
    1298  * when removing the page from the notepad */
    1299  gtk_widget_destroy(old_scrolled_container);
    1300 
    1301  }
    1302 
    1303  /* Remove all the pages from source notebook */
    1304  for (i = np - 1; i >= 0; i--)
    1305  gtk_notebook_remove_page(from_notebook, i);
    1306  gtk_notebook_set_current_page(to->priv->notebook, cp);
    1307 
    1308  }
    1309 }
    1310 
    1311 static void rcw_switch_viewmode(RemminaConnectionWindow *cnnwin, int newmode)
    1312 {
    1313  GdkWindowState s;
    1314  RemminaConnectionWindow *newwin;
    1315  gint old_width, old_height;
    1316  int old_mode;
    1317 
    1318  old_mode = cnnwin->priv->view_mode;
    1319  if (old_mode == newmode)
    1320  return;
    1321 
    1322  if (newmode == VIEWPORT_FULLSCREEN_MODE || newmode == SCROLLED_FULLSCREEN_MODE) {
    1323  if (old_mode == SCROLLED_WINDOW_MODE) {
    1324  /* We are leaving SCROLLED_WINDOW_MODE, save W,H, and maximized
    1325  * status before self destruction of cnnwin */
    1326  gtk_window_get_size(GTK_WINDOW(cnnwin), &old_width, &old_height);
    1327  s = gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(cnnwin)));
    1328  }
    1329  newwin = rcw_create_fullscreen(GTK_WINDOW(cnnwin), cnnwin->priv->fss_view_mode);
    1330  rcw_migrate(cnnwin, newwin);
    1331  if (old_mode == SCROLLED_WINDOW_MODE) {
    1332  newwin->priv->ss_maximized = (s & GDK_WINDOW_STATE_MAXIMIZED) ? TRUE : FALSE;
    1333  newwin->priv->ss_width = old_width;
    1334  newwin->priv->ss_height = old_height;
    1335  }
    1336  } else {
    1337  newwin = rcw_create_scrolled(cnnwin->priv->ss_width, cnnwin->priv->ss_height,
    1338  cnnwin->priv->ss_maximized);
    1339  rcw_migrate(cnnwin, newwin);
    1340  if (old_mode == VIEWPORT_FULLSCREEN_MODE || old_mode == SCROLLED_FULLSCREEN_MODE)
    1341  /* We are leaving a FULLSCREEN mode, save some parameters
    1342  * status before self destruction of cnnwin */
    1343  newwin->priv->fss_view_mode = old_mode;
    1344  }
    1345 
    1346  /* Prevent unreleased hostkey from old window to be released here */
    1347  newwin->priv->hostkey_used = TRUE;
    1348 }
    1349 
    1350 
    1351 static void rcw_toolbar_fullscreen(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1352 {
    1353  TRACE_CALL(__func__);
    1354 
    1355  RemminaConnectionObject *cnnobj;
    1356 
    1357  if (cnnwin->priv->toolbar_is_reconfiguring)
    1358  return;
    1359 
    1360  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1361 
    1362  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    1363 
    1364  if (remmina_protocol_widget_get_multimon(gp) >= 1) {
    1365  REMMINA_DEBUG("Fullscreen on all monitor");
    1366  gdk_window_set_fullscreen_mode(gtk_widget_get_window(GTK_WIDGET(toggle)), GDK_FULLSCREEN_ON_ALL_MONITORS);
    1367  } else {
    1368  REMMINA_DEBUG("Fullscreen on one monitor");
    1369  }
    1370 
    1371  if ((toggle != NULL && toggle == cnnwin->priv->toolitem_fullscreen)) {
    1372  if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle))) {
    1374  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_multimon), TRUE);
    1375  rcw_switch_viewmode(cnnwin, cnnwin->priv->fss_view_mode);
    1376  } else {
    1378  }
    1379  } else
    1380  if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_multimon))) {
    1381  rcw_switch_viewmode(cnnwin, cnnwin->priv->fss_view_mode);
    1382  } else {
    1384  }
    1385 }
    1386 
    1387 static void rco_viewport_fullscreen_mode(GtkWidget *widget, RemminaConnectionObject *cnnobj)
    1388 {
    1389  TRACE_CALL(__func__);
    1390  RemminaConnectionWindow *newwin;
    1391 
    1392  if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
    1393  return;
    1394  cnnobj->cnnwin->priv->fss_view_mode = VIEWPORT_FULLSCREEN_MODE;
    1395  newwin = rcw_create_fullscreen(GTK_WINDOW(cnnobj->cnnwin), VIEWPORT_FULLSCREEN_MODE);
    1396  rcw_migrate(cnnobj->cnnwin, newwin);
    1397 }
    1398 
    1399 static void rco_scrolled_fullscreen_mode(GtkWidget *widget, RemminaConnectionObject *cnnobj)
    1400 {
    1401  TRACE_CALL(__func__);
    1402  RemminaConnectionWindow *newwin;
    1403 
    1404  if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
    1405  return;
    1406  cnnobj->cnnwin->priv->fss_view_mode = SCROLLED_FULLSCREEN_MODE;
    1407  newwin = rcw_create_fullscreen(GTK_WINDOW(cnnobj->cnnwin), SCROLLED_FULLSCREEN_MODE);
    1408  rcw_migrate(cnnobj->cnnwin, newwin);
    1409 }
    1410 
    1411 static void rcw_fullscreen_option_popdown(GtkWidget *widget, RemminaConnectionWindow *cnnwin)
    1412 {
    1413  TRACE_CALL(__func__);
    1414  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1415 
    1416  priv->sticky = FALSE;
    1417  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->fullscreen_option_button), FALSE);
    1418  rcw_floating_toolbar_show(cnnwin, FALSE);
    1419 }
    1420 
    1421 void rcw_toolbar_fullscreen_option(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1422 {
    1423  TRACE_CALL(__func__);
    1424  RemminaConnectionObject *cnnobj;
    1425  GtkWidget *menu;
    1426  GtkWidget *menuitem;
    1427  GSList *group;
    1428 
    1429  if (cnnwin->priv->toolbar_is_reconfiguring)
    1430  return;
    1431 
    1432  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1433 
    1434  if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
    1435  return;
    1436 
    1437  cnnwin->priv->sticky = TRUE;
    1438 
    1439  menu = gtk_menu_new();
    1440 
    1441  menuitem = gtk_radio_menu_item_new_with_label(NULL, _("Viewport fullscreen mode"));
    1442  gtk_widget_show(menuitem);
    1443  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1444  group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
    1445  if (cnnwin->priv->view_mode == VIEWPORT_FULLSCREEN_MODE)
    1446  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
    1447  g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(rco_viewport_fullscreen_mode), cnnobj);
    1448 
    1449  menuitem = gtk_radio_menu_item_new_with_label(group, _("Scrolled fullscreen"));
    1450  gtk_widget_show(menuitem);
    1451  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1452  if (cnnwin->priv->view_mode == SCROLLED_FULLSCREEN_MODE)
    1453  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
    1454  g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(rco_scrolled_fullscreen_mode), cnnobj);
    1455 
    1456  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_fullscreen_option_popdown), cnnwin);
    1457 
    1458 #if GTK_CHECK_VERSION(3, 22, 0)
    1459  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    1460  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    1461 #else
    1462  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, cnnwin->priv->toolitem_fullscreen, 0,
    1463  gtk_get_current_event_time());
    1464 #endif
    1465 }
    1466 
    1467 
    1468 static void rcw_scaler_option_popdown(GtkWidget *widget, RemminaConnectionWindow *cnnwin)
    1469 {
    1470  TRACE_CALL(__func__);
    1471  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1472 
    1473  if (priv->toolbar_is_reconfiguring)
    1474  return;
    1475  priv->sticky = FALSE;
    1476  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->scaler_option_button), FALSE);
    1477  rcw_floating_toolbar_show(cnnwin, FALSE);
    1478 }
    1479 
    1480 static void rcw_scaler_expand(GtkWidget *widget, RemminaConnectionWindow *cnnwin)
    1481 {
    1482  TRACE_CALL(__func__);
    1483  RemminaConnectionObject *cnnobj;
    1484 
    1485  if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
    1486  return;
    1487  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    1488  if (!cnnobj)
    1489  return;
    1490  remmina_protocol_widget_set_expand(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), TRUE);
    1491  remmina_file_set_int(cnnobj->remmina_file, "scaler_expand", TRUE);
    1493 }
    1494 static void rcw_scaler_keep_aspect(GtkWidget *widget, RemminaConnectionWindow *cnnwin)
    1495 {
    1496  TRACE_CALL(__func__);
    1497  RemminaConnectionObject *cnnobj;
    1498 
    1499  if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
    1500  return;
    1501  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    1502  if (!cnnobj)
    1503  return;
    1504 
    1505  remmina_protocol_widget_set_expand(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), FALSE);
    1506  remmina_file_set_int(cnnobj->remmina_file, "scaler_expand", FALSE);
    1508 }
    1509 
    1510 static void rcw_toolbar_scaler_option(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1511 {
    1512  TRACE_CALL(__func__);
    1514  RemminaConnectionObject *cnnobj;
    1515  GtkWidget *menu;
    1516  GtkWidget *menuitem;
    1517  GSList *group;
    1518  gboolean scaler_expand;
    1519 
    1520  if (cnnwin->priv->toolbar_is_reconfiguring)
    1521  return;
    1522 
    1523  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1524  priv = cnnwin->priv;
    1525 
    1526  if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
    1527  return;
    1528 
    1529  scaler_expand = remmina_protocol_widget_get_expand(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1530 
    1531  priv->sticky = TRUE;
    1532 
    1533  menu = gtk_menu_new();
    1534 
    1535  menuitem = gtk_radio_menu_item_new_with_label(NULL, _("Keep aspect ratio when scaled"));
    1536  gtk_widget_show(menuitem);
    1537  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1538  group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
    1539  if (!scaler_expand)
    1540  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
    1541  g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(rcw_scaler_keep_aspect), cnnwin);
    1542 
    1543  menuitem = gtk_radio_menu_item_new_with_label(group, _("Fill client window when scaled"));
    1544  gtk_widget_show(menuitem);
    1545  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1546  if (scaler_expand)
    1547  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
    1548  g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(rcw_scaler_expand), cnnwin);
    1549 
    1550  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_scaler_option_popdown), cnnwin);
    1551 
    1552 #if GTK_CHECK_VERSION(3, 22, 0)
    1553  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    1554  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    1555 #else
    1556  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, priv->toolitem_scale, 0,
    1557  gtk_get_current_event_time());
    1558 #endif
    1559 }
    1560 
    1561 void rco_switch_page_activate(GtkMenuItem *menuitem, RemminaConnectionObject *cnnobj)
    1562 {
    1563  TRACE_CALL(__func__);
    1564  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    1565  gint page_num;
    1566 
    1567  page_num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "new-page-num"));
    1568  gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->notebook), page_num);
    1569 }
    1570 
    1572 {
    1573  TRACE_CALL(__func__);
    1574  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1575 
    1576  priv->sticky = FALSE;
    1577 
    1578  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_switch_page), FALSE);
    1579  rcw_floating_toolbar_show(cnnwin, FALSE);
    1580 }
    1581 
    1582 static void rcw_toolbar_switch_page(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1583 {
    1584  TRACE_CALL(__func__);
    1585 
    1586  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1587  RemminaConnectionObject *cnnobj;
    1588 
    1589  GtkWidget *menu;
    1590  GtkWidget *menuitem;
    1591  GtkWidget *image;
    1592  gint i, n;
    1593 
    1594  if (priv->toolbar_is_reconfiguring)
    1595  return;
    1596  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1597 
    1598  if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle)))
    1599  return;
    1600 
    1601  priv->sticky = TRUE;
    1602 
    1603  menu = gtk_menu_new();
    1604 
    1605  n = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook));
    1606  for (i = 0; i < n; i++) {
    1607  cnnobj = rcw_get_cnnobj_at_page(cnnobj->cnnwin, i);
    1608 
    1609  menuitem = gtk_menu_item_new_with_label(remmina_file_get_string(cnnobj->remmina_file, "name"));
    1610  gtk_widget_show(menuitem);
    1611  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1612 
    1613  image = gtk_image_new_from_icon_name(remmina_file_get_icon_name(cnnobj->remmina_file), GTK_ICON_SIZE_MENU);
    1614  gtk_widget_show(image);
    1615 
    1616  g_object_set_data(G_OBJECT(menuitem), "new-page-num", GINT_TO_POINTER(i));
    1617  g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(rco_switch_page_activate), cnnobj);
    1618  if (i == gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->notebook)))
    1619  gtk_widget_set_sensitive(menuitem, FALSE);
    1620  }
    1621 
    1622  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_toolbar_switch_page_popdown),
    1623  cnnwin);
    1624 
    1625 #if GTK_CHECK_VERSION(3, 22, 0)
    1626  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    1627  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    1628 #else
    1629  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, widget, 0, gtk_get_current_event_time());
    1630 #endif
    1631 }
    1632 
    1634 {
    1635  TRACE_CALL(__func__);
    1636  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    1637  GtkToolItem *toolitem;
    1638  RemminaScaleMode sc;
    1639 
    1640  toolitem = priv->toolitem_autofit;
    1641  if (toolitem) {
    1642  if (priv->view_mode != SCROLLED_WINDOW_MODE) {
    1643  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    1644  } else {
    1645  sc = get_current_allowed_scale_mode(cnnobj, NULL, NULL);
    1646  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), sc == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_NONE);
    1647  }
    1648  }
    1649 }
    1650 
    1651 static void rco_change_scalemode(RemminaConnectionObject *cnnobj, gboolean bdyn, gboolean bscale)
    1652 {
    1653  RemminaScaleMode scalemode;
    1654  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    1655 
    1656  if (bdyn)
    1658  else if (bscale)
    1660  else
    1662 
    1663  remmina_protocol_widget_set_current_scale_mode(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), scalemode);
    1664  remmina_file_set_int(cnnobj->remmina_file, "scale", scalemode);
    1665  gtk_widget_set_sensitive(GTK_WIDGET(priv->scaler_option_button), scalemode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED);
    1667 
    1668  remmina_protocol_widget_call_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    1670 
    1671  if (cnnobj->cnnwin->priv->view_mode != SCROLLED_WINDOW_MODE)
    1672  rco_check_resize(cnnobj);
    1673  if (GTK_IS_SCROLLED_WINDOW(cnnobj->scrolled_container)) {
    1674  rco_set_scrolled_policy(scalemode, GTK_SCROLLED_WINDOW(cnnobj->scrolled_container));
    1675  }
    1676 }
    1677 
    1678 static void rcw_toolbar_dynres(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1679 {
    1680  TRACE_CALL(__func__);
    1681  gboolean bdyn, bscale;
    1682  RemminaConnectionObject *cnnobj;
    1683 
    1684  if (cnnwin->priv->toolbar_is_reconfiguring)
    1685  return;
    1686  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1687 
    1688  if (cnnobj->connected) {
    1689  bdyn = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle));
    1690  bscale = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(cnnobj->cnnwin->priv->toolitem_scale));
    1691 
    1692  if (bdyn && bscale) {
    1693  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnobj->cnnwin->priv->toolitem_scale), FALSE);
    1694  bscale = FALSE;
    1695  }
    1696 
    1697  rco_change_scalemode(cnnobj, bdyn, bscale);
    1698  }
    1699 }
    1700 
    1701 static void rcw_toolbar_scaled_mode(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1702 {
    1703  TRACE_CALL(__func__);
    1704  gboolean bdyn, bscale;
    1705  RemminaConnectionObject *cnnobj;
    1706 
    1707  if (cnnwin->priv->toolbar_is_reconfiguring)
    1708  return;
    1709  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1710 
    1711  bdyn = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(cnnobj->cnnwin->priv->toolitem_dynres));
    1712  bscale = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle));
    1713 
    1714  if (bdyn && bscale) {
    1715  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnobj->cnnwin->priv->toolitem_dynres), FALSE);
    1716  bdyn = FALSE;
    1717  }
    1718 
    1719  rco_change_scalemode(cnnobj, bdyn, bscale);
    1720 }
    1721 
    1722 static void rcw_toolbar_multi_monitor_mode(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1723 {
    1724  TRACE_CALL(__func__);
    1725  RemminaConnectionObject *cnnobj;
    1726 
    1727  if (cnnwin->priv->toolbar_is_reconfiguring)
    1728  return;
    1729 
    1730  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1731 
    1732  if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle))) {
    1733  REMMINA_DEBUG("Saving multimon as 1");
    1734  remmina_file_set_int(cnnobj->remmina_file, "multimon", 1);
    1736  remmina_protocol_widget_call_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    1738  if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_fullscreen)))
    1739  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_fullscreen), TRUE);
    1740  } else {
    1741  REMMINA_DEBUG("Saving multimon as 0");
    1742  remmina_file_set_int(cnnobj->remmina_file, "multimon", 0);
    1744  rcw_toolbar_fullscreen(NULL, cnnwin);
    1745  }
    1746 }
    1747 
    1748 static void rcw_toolbar_open_main(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1749 {
    1750  TRACE_CALL(__func__);
    1751 
    1752  if (cnnwin->priv->toolbar_is_reconfiguring)
    1753  return;
    1754 
    1756 }
    1757 
    1758 static void rcw_toolbar_preferences_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1759 {
    1760  TRACE_CALL(__func__);
    1761  RemminaConnectionObject *cnnobj;
    1762 
    1763  if (cnnwin->priv->toolbar_is_reconfiguring)
    1764  return;
    1765  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1766 
    1767  cnnobj->cnnwin->priv->sticky = FALSE;
    1768 
    1769  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnobj->cnnwin->priv->toolitem_preferences), FALSE);
    1770  rcw_floating_toolbar_show(cnnwin, FALSE);
    1771 }
    1772 
    1773 void rcw_toolbar_menu_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1774 {
    1775  TRACE_CALL(__func__);
    1776  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1777 
    1778  if (priv->toolbar_is_reconfiguring)
    1779  return;
    1780 
    1781  priv->sticky = FALSE;
    1782 
    1783  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_menu), FALSE);
    1784  rcw_floating_toolbar_show(cnnwin, FALSE);
    1785 }
    1786 
    1787 void rcw_toolbar_tools_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1788 {
    1789  TRACE_CALL(__func__);
    1790  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    1791 
    1792  if (priv->toolbar_is_reconfiguring)
    1793  return;
    1794 
    1795  priv->sticky = FALSE;
    1796 
    1797  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_tools), FALSE);
    1798  rcw_floating_toolbar_show(cnnwin, FALSE);
    1799 }
    1800 
    1801 static void rco_call_protocol_feature_radio(GtkMenuItem *menuitem, RemminaConnectionObject *cnnobj)
    1802 {
    1803  TRACE_CALL(__func__);
    1804  RemminaProtocolFeature *feature;
    1805  gpointer value;
    1806 
    1807  if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) {
    1808  feature = (RemminaProtocolFeature *)g_object_get_data(G_OBJECT(menuitem), "feature-type");
    1809  value = g_object_get_data(G_OBJECT(menuitem), "feature-value");
    1810 
    1811  remmina_file_set_string(cnnobj->remmina_file, (const gchar *)feature->opt2, (const gchar *)value);
    1812  remmina_protocol_widget_call_feature_by_ref(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), feature);
    1813  }
    1814 }
    1815 
    1816 static void rco_call_protocol_feature_check(GtkMenuItem *menuitem, RemminaConnectionObject *cnnobj)
    1817 {
    1818  TRACE_CALL(__func__);
    1819  RemminaProtocolFeature *feature;
    1820  gboolean value;
    1821 
    1822  feature = (RemminaProtocolFeature *)g_object_get_data(G_OBJECT(menuitem), "feature-type");
    1823  value = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
    1824  remmina_file_set_int(cnnobj->remmina_file, (const gchar *)feature->opt2, value);
    1825  remmina_protocol_widget_call_feature_by_ref(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), feature);
    1826 }
    1827 
    1828 static void rco_call_protocol_feature_activate(GtkMenuItem *menuitem, RemminaConnectionObject *cnnobj)
    1829 {
    1830  TRACE_CALL(__func__);
    1831  RemminaProtocolFeature *feature;
    1832 
    1833  feature = (RemminaProtocolFeature *)g_object_get_data(G_OBJECT(menuitem), "feature-type");
    1834  remmina_protocol_widget_call_feature_by_ref(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), feature);
    1835 }
    1836 
    1838  GtkWidget *menu, const RemminaProtocolFeature *feature, const gchar *domain, gboolean enabled)
    1839 {
    1840  TRACE_CALL(__func__);
    1841  GtkWidget *menuitem;
    1842  GSList *group;
    1843  gint i;
    1844  const gchar **list;
    1845  const gchar *value;
    1846 
    1847  group = NULL;
    1848  value = remmina_file_get_string(remminafile, (const gchar *)feature->opt2);
    1849  list = (const gchar **)feature->opt3;
    1850  for (i = 0; list[i]; i += 2) {
    1851  menuitem = gtk_radio_menu_item_new_with_label(group, g_dgettext(domain, list[i + 1]));
    1852  group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
    1853  gtk_widget_show(menuitem);
    1854  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1855 
    1856  if (enabled) {
    1857  g_object_set_data(G_OBJECT(menuitem), "feature-type", (gpointer)feature);
    1858  g_object_set_data(G_OBJECT(menuitem), "feature-value", (gpointer)list[i]);
    1859 
    1860  if (value && g_strcmp0(list[i], value) == 0)
    1861  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
    1862 
    1863  g_signal_connect(G_OBJECT(menuitem), "toggled",
    1864  G_CALLBACK(rco_call_protocol_feature_radio), cnnobj);
    1865  } else {
    1866  gtk_widget_set_sensitive(menuitem, FALSE);
    1867  }
    1868  }
    1869 }
    1870 
    1872  GtkWidget *menu, const RemminaProtocolFeature *feature,
    1873  const gchar *domain, gboolean enabled)
    1874 {
    1875  TRACE_CALL(__func__);
    1876  GtkWidget *menuitem;
    1877 
    1878  menuitem = gtk_check_menu_item_new_with_label(g_dgettext(domain, (const gchar *)feature->opt3));
    1879  gtk_widget_show(menuitem);
    1880  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1881 
    1882  if (enabled) {
    1883  g_object_set_data(G_OBJECT(menuitem), "feature-type", (gpointer)feature);
    1884 
    1885  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
    1886  remmina_file_get_int(cnnobj->remmina_file, (const gchar *)feature->opt2, FALSE));
    1887 
    1888  g_signal_connect(G_OBJECT(menuitem), "toggled",
    1889  G_CALLBACK(rco_call_protocol_feature_check), cnnobj);
    1890  } else {
    1891  gtk_widget_set_sensitive(menuitem, FALSE);
    1892  }
    1893 }
    1894 
    1895 static void rcw_toolbar_preferences(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1896 {
    1897  TRACE_CALL(__func__);
    1899  RemminaConnectionObject *cnnobj;
    1900  const RemminaProtocolFeature *feature;
    1901  GtkWidget *menu;
    1902  GtkWidget *menuitem;
    1903  gboolean separator;
    1904  gchar *domain;
    1905  gboolean enabled;
    1906 
    1907  if (cnnwin->priv->toolbar_is_reconfiguring)
    1908  return;
    1909  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1910  priv = cnnobj->cnnwin->priv;
    1911 
    1912  if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle)))
    1913  return;
    1914 
    1915  priv->sticky = TRUE;
    1916 
    1917  separator = FALSE;
    1918 
    1919  domain = remmina_protocol_widget_get_domain(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    1920  menu = gtk_menu_new();
    1921  for (feature = remmina_protocol_widget_get_features(REMMINA_PROTOCOL_WIDGET(cnnobj->proto)); feature && feature->type;
    1922  feature++) {
    1923  if (feature->type != REMMINA_PROTOCOL_FEATURE_TYPE_PREF)
    1924  continue;
    1925 
    1926  if (separator) {
    1927  menuitem = gtk_separator_menu_item_new();
    1928  gtk_widget_show(menuitem);
    1929  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    1930  separator = FALSE;
    1931  }
    1932  enabled = remmina_protocol_widget_query_feature_by_ref(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), feature);
    1933  switch (GPOINTER_TO_INT(feature->opt1)) {
    1934  case REMMINA_PROTOCOL_FEATURE_PREF_RADIO:
    1935  rcw_toolbar_preferences_radio(cnnobj, cnnobj->remmina_file, menu, feature,
    1936  domain, enabled);
    1937  separator = TRUE;
    1938  break;
    1939  case REMMINA_PROTOCOL_FEATURE_PREF_CHECK:
    1940  rcw_toolbar_preferences_check(cnnobj, menu, feature,
    1941  domain, enabled);
    1942  break;
    1943  }
    1944  }
    1945 
    1946  g_free(domain);
    1947 
    1948  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_toolbar_preferences_popdown), cnnwin);
    1949 
    1950 #if GTK_CHECK_VERSION(3, 22, 0)
    1951  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    1952  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    1953 #else
    1954  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, widget, 0, gtk_get_current_event_time());
    1955 #endif
    1956 }
    1957 
    1959 {
    1960  TRACE_CALL(__func__);
    1961  gchar *s;
    1962 
    1963  switch (menuitem->item_type) {
    1966  break;
    1969  break;
    1971  s = g_strdup_printf("%s,%s", menuitem->protocol, menuitem->name);
    1973  g_free(s);
    1974  break;
    1975  }
    1976 }
    1977 
    1978 static void rcw_toolbar_menu(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    1979 {
    1980  TRACE_CALL(__func__);
    1982  RemminaConnectionObject *cnnobj;
    1983  GtkWidget *menu;
    1984  GtkWidget *menuitem = NULL;
    1985 
    1986  if (cnnwin->priv->toolbar_is_reconfiguring)
    1987  return;
    1988 
    1989  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    1990  priv = cnnobj->cnnwin->priv;
    1991 
    1992  if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle)))
    1993  return;
    1994 
    1995  priv->sticky = TRUE;
    1996 
    1997  menu = remmina_applet_menu_new();
    1998  remmina_applet_menu_set_hide_count(REMMINA_APPLET_MENU(menu), remmina_pref.applet_hide_count);
    1999  remmina_applet_menu_populate(REMMINA_APPLET_MENU(menu));
    2000 
    2001  g_signal_connect(G_OBJECT(menu), "launch-item", G_CALLBACK(rcw_toolbar_menu_on_launch_item), NULL);
    2002  //g_signal_connect(G_OBJECT(menu), "edit-item", G_CALLBACK(rcw_toolbar_menu_on_edit_item), NULL);
    2003  menuitem = gtk_separator_menu_item_new();
    2004  gtk_widget_show(menuitem);
    2005  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    2006 #if GTK_CHECK_VERSION(3, 22, 0)
    2007  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    2008  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    2009 #else
    2010  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, widget, 0, gtk_get_current_event_time());
    2011 #endif
    2012  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_toolbar_menu_popdown), cnnwin);
    2013 }
    2014 
    2015 static void rcw_toolbar_tools(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2016 {
    2017  TRACE_CALL(__func__);
    2019  RemminaConnectionObject *cnnobj;
    2020  const RemminaProtocolFeature *feature;
    2021  GtkWidget *menu;
    2022  GtkWidget *menuitem = NULL;
    2023  GtkMenu *submenu_keystrokes;
    2024  const gchar *domain;
    2025  gboolean enabled;
    2026  gchar **keystrokes;
    2027  gchar **keystroke_values;
    2028  gint i;
    2029 
    2030  if (cnnwin->priv->toolbar_is_reconfiguring)
    2031  return;
    2032  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2033  priv = cnnobj->cnnwin->priv;
    2034 
    2035  if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle)))
    2036  return;
    2037 
    2038  priv->sticky = TRUE;
    2039 
    2040  domain = remmina_protocol_widget_get_domain(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    2041  menu = gtk_menu_new();
    2042  for (feature = remmina_protocol_widget_get_features(REMMINA_PROTOCOL_WIDGET(cnnobj->proto)); feature && feature->type;
    2043  feature++) {
    2044  if (feature->type != REMMINA_PROTOCOL_FEATURE_TYPE_TOOL)
    2045  continue;
    2046 
    2047  if (feature->opt1)
    2048  menuitem = gtk_menu_item_new_with_label(g_dgettext(domain, (const gchar *)feature->opt1));
    2049  if (feature->opt3)
    2050  rcw_set_tooltip(menuitem, "", GPOINTER_TO_UINT(feature->opt3), 0);
    2051  gtk_widget_show(menuitem);
    2052  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    2053 
    2054  enabled = remmina_protocol_widget_query_feature_by_ref(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), feature);
    2055  if (enabled) {
    2056  g_object_set_data(G_OBJECT(menuitem), "feature-type", (gpointer)feature);
    2057 
    2058  g_signal_connect(G_OBJECT(menuitem), "activate",
    2059  G_CALLBACK(rco_call_protocol_feature_activate), cnnobj);
    2060  } else {
    2061  gtk_widget_set_sensitive(menuitem, FALSE);
    2062  }
    2063  }
    2064 
    2065  /* If the plugin accepts keystrokes include the keystrokes menu */
    2066  if (remmina_protocol_widget_plugin_receives_keystrokes(REMMINA_PROTOCOL_WIDGET(cnnobj->proto))) {
    2067  /* Get the registered keystrokes list */
    2068  keystrokes = g_strsplit(remmina_pref.keystrokes, STRING_DELIMITOR, -1);
    2069  if (g_strv_length(keystrokes)) {
    2070  /* Add a keystrokes submenu */
    2071  menuitem = gtk_menu_item_new_with_label(_("Keystrokes"));
    2072  submenu_keystrokes = GTK_MENU(gtk_menu_new());
    2073  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(submenu_keystrokes));
    2074  gtk_widget_show(menuitem);
    2075  gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    2076  /* Add each registered keystroke */
    2077  for (i = 0; i < g_strv_length(keystrokes); i++) {
    2078  keystroke_values = g_strsplit(keystrokes[i], STRING_DELIMITOR2, -1);
    2079  if (g_strv_length(keystroke_values) > 1) {
    2080  /* Add the keystroke if no description was available */
    2081  menuitem = gtk_menu_item_new_with_label(
    2082  g_strdup(keystroke_values[strlen(keystroke_values[0]) ? 0 : 1]));
    2083  g_object_set_data(G_OBJECT(menuitem), "keystrokes", g_strdup(keystroke_values[1]));
    2084  g_signal_connect_swapped(G_OBJECT(menuitem), "activate",
    2086  REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    2087  gtk_widget_show(menuitem);
    2088  gtk_menu_shell_append(GTK_MENU_SHELL(submenu_keystrokes), menuitem);
    2089  }
    2090  g_strfreev(keystroke_values);
    2091  }
    2092  menuitem = gtk_menu_item_new_with_label(_("Send clipboard content as keystrokes"));
    2093  static gchar k_tooltip[] =
    2094  N_("CAUTION: Pasted text will be sent as a sequence of key-codes as if typed on your local keyboard.\n"
    2095  "\n"
    2096  " • For best results use same keyboard settings for both, client and server.\n"
    2097  "\n"
    2098  " • If client-keyboard is different from server-keyboard the received text can contain wrong or erroneous characters.\n"
    2099  "\n"
    2100  " • Unicode characters and other special characters that can't be translated to local key-codes won’t be sent to the server.\n"
    2101  "\n");
    2102  gtk_widget_set_tooltip_text(menuitem, k_tooltip);
    2103  gtk_menu_shell_append(GTK_MENU_SHELL(submenu_keystrokes), menuitem);
    2104  g_signal_connect_swapped(G_OBJECT(menuitem), "activate",
    2106  REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    2107  gtk_widget_show(menuitem);
    2108  }
    2109  g_strfreev(keystrokes);
    2110  }
    2111 
    2112  g_signal_connect(G_OBJECT(menu), "deactivate", G_CALLBACK(rcw_toolbar_tools_popdown), cnnwin);
    2113 
    2114 #if GTK_CHECK_VERSION(3, 22, 0)
    2115  gtk_menu_popup_at_widget(GTK_MENU(menu), GTK_WIDGET(toggle),
    2116  GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    2117 #else
    2118  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, remmina_public_popup_position, widget, 0, gtk_get_current_event_time());
    2119 #endif
    2120 }
    2121 
    2122 static void rcw_toolbar_duplicate(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2123 {
    2124  TRACE_CALL(__func__);
    2125 
    2126  RemminaConnectionObject *cnnobj;
    2127 
    2128  if (cnnwin->priv->toolbar_is_reconfiguring)
    2129  return;
    2130  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2131 
    2133 
    2135 }
    2136 
    2137 static void rcw_toolbar_screenshot(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2138 {
    2139  TRACE_CALL(__func__);
    2140 
    2141  GdkPixbuf *screenshot;
    2142  GdkWindow *active_window;
    2143  cairo_t *cr;
    2144  gint width, height;
    2145  GString *pngstr;
    2146  gchar *pngname;
    2147  GtkWidget *dialog;
    2150  RemminaConnectionObject *cnnobj;
    2151  cairo_surface_t *srcsurface;
    2152  cairo_format_t cairo_format;
    2153  cairo_surface_t *surface;
    2154  int stride;
    2155 
    2156  if (cnnwin->priv->toolbar_is_reconfiguring)
    2157  return;
    2158  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2159 
    2160  GDateTime *date = g_date_time_new_now_utc();
    2161 
    2162  // We will take a screenshot of the currently displayed RemminaProtocolWidget.
    2163  gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    2164 
    2165  gchar *denyclip = remmina_pref_get_value("deny_screenshot_clipboard");
    2166 
    2167  REMMINA_DEBUG("deny_screenshot_clipboard is set to %s", denyclip);
    2168 
    2169  GtkClipboard *c = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
    2170 
    2171  // Ask the plugin if it can give us a screenshot
    2173  // Good, we have a screenshot from the plugin !
    2174 
    2175  REMMINA_DEBUG("Screenshot from plugin: w=%d h=%d bpp=%d bytespp=%d\n",
    2176  rpsd.width, rpsd.height, rpsd.bitsPerPixel, rpsd.bytesPerPixel);
    2177 
    2178  width = rpsd.width;
    2179  height = rpsd.height;
    2180 
    2181  if (rpsd.bitsPerPixel == 32)
    2182  cairo_format = CAIRO_FORMAT_ARGB32;
    2183  else if (rpsd.bitsPerPixel == 24)
    2184  cairo_format = CAIRO_FORMAT_RGB24;
    2185  else
    2186  cairo_format = CAIRO_FORMAT_RGB16_565;
    2187 
    2188  stride = cairo_format_stride_for_width(cairo_format, width);
    2189 
    2190  srcsurface = cairo_image_surface_create_for_data(rpsd.buffer, cairo_format, width, height, stride);
    2191  // Transfer the PixBuf in the main clipboard selection
    2192  if (denyclip && (g_strcmp0(denyclip, "true")))
    2193  gtk_clipboard_set_image(c, gdk_pixbuf_get_from_surface(
    2194  srcsurface, 0, 0, width, height));
    2195  surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
    2196  cr = cairo_create(surface);
    2197  cairo_set_source_surface(cr, srcsurface, 0, 0);
    2198  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    2199  cairo_paint(cr);
    2200  cairo_surface_destroy(srcsurface);
    2201 
    2202  free(rpsd.buffer);
    2203  } else {
    2204  // The plugin is not releasing us a screenshot, just try to catch one via GTK
    2205 
    2206  /* Warn the user if image is distorted */
    2207  if (cnnobj->plugin_can_scale &&
    2209  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
    2210  _("Turn off scaling to avoid screenshot distortion."));
    2211  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
    2212  gtk_widget_show(dialog);
    2213  }
    2214 
    2215  // Get the screenshot.
    2216  active_window = gtk_widget_get_window(GTK_WIDGET(gp));
    2217  // width = gdk_window_get_width(gtk_widget_get_window(GTK_WIDGET(cnnobj->cnnwin)));
    2218  width = gdk_window_get_width(active_window);
    2219  // height = gdk_window_get_height(gtk_widget_get_window(GTK_WIDGET(cnnobj->cnnwin)));
    2220  height = gdk_window_get_height(active_window);
    2221 
    2222  screenshot = gdk_pixbuf_get_from_window(active_window, 0, 0, width, height);
    2223  if (screenshot == NULL)
    2224  g_print("gdk_pixbuf_get_from_window failed\n");
    2225 
    2226  // Transfer the PixBuf in the main clipboard selection
    2227  if (denyclip && (g_strcmp0(denyclip, "true")))
    2228  gtk_clipboard_set_image(c, screenshot);
    2229  // Prepare the destination Cairo surface.
    2230  surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
    2231  cr = cairo_create(surface);
    2232 
    2233  // Copy the source pixbuf to the surface and paint it.
    2234  gdk_cairo_set_source_pixbuf(cr, screenshot, 0, 0);
    2235  cairo_paint(cr);
    2236 
    2237  // Deallocate screenshot pixbuf
    2238  g_object_unref(screenshot);
    2239  }
    2240 
    2241  //home/antenore/Pictures/remmina_%p_%h_%Y %m %d-%H%M%S.png pngname
    2242  //home/antenore/Pictures/remmina_st_ _2018 9 24-151958.240374.png
    2243 
    2244  pngstr = g_string_new(g_strdup_printf("%s/%s.png",
    2245  remmina_pref.screenshot_path,
    2246  remmina_pref.screenshot_name));
    2247  remmina_utils_string_replace_all(pngstr, "%p",
    2248  remmina_file_get_string(cnnobj->remmina_file, "name"));
    2249  remmina_utils_string_replace_all(pngstr, "%h",
    2250  remmina_file_get_string(cnnobj->remmina_file, "server"));
    2251  remmina_utils_string_replace_all(pngstr, "%Y",
    2252  g_strdup_printf("%d", g_date_time_get_year(date)));
    2253  remmina_utils_string_replace_all(pngstr, "%m", g_strdup_printf("%02d",
    2254  g_date_time_get_month(date)));
    2255  remmina_utils_string_replace_all(pngstr, "%d",
    2256  g_strdup_printf("%02d", g_date_time_get_day_of_month(date)));
    2257  remmina_utils_string_replace_all(pngstr, "%H",
    2258  g_strdup_printf("%02d", g_date_time_get_hour(date)));
    2259  remmina_utils_string_replace_all(pngstr, "%M",
    2260  g_strdup_printf("%02d", g_date_time_get_minute(date)));
    2261  remmina_utils_string_replace_all(pngstr, "%S",
    2262  g_strdup_printf("%02d", g_date_time_get_second(date)));
    2263  g_date_time_unref(date);
    2264  pngname = g_string_free(pngstr, FALSE);
    2265 
    2266  cairo_surface_write_to_png(surface, pngname);
    2267 
    2268  /* send a desktop notification */
    2269  if (g_file_test(pngname, G_FILE_TEST_EXISTS))
    2270  remmina_public_send_notification("remmina-screenshot-is-ready-id", _("Screenshot taken"), pngname);
    2271 
    2272  //Clean up and return.
    2273  cairo_destroy(cr);
    2274  cairo_surface_destroy(surface);
    2275 }
    2276 
    2277 static void rcw_toolbar_minimize(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2278 {
    2279  TRACE_CALL(__func__);
    2280 
    2281  if (cnnwin->priv->toolbar_is_reconfiguring)
    2282  return;
    2283 
    2284  rcw_floating_toolbar_show(cnnwin, FALSE);
    2285  gtk_window_iconify(GTK_WINDOW(cnnwin));
    2286 }
    2287 
    2288 static void rcw_toolbar_disconnect(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2289 {
    2290  TRACE_CALL(__func__);
    2291  RemminaConnectionObject *cnnobj;
    2292 
    2293  if (cnnwin->priv->toolbar_is_reconfiguring)
    2294  return;
    2295  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2297 }
    2298 
    2299 static void rcw_toolbar_grab(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    2300 {
    2301  TRACE_CALL(__func__);
    2302  gboolean capture;
    2303  RemminaConnectionObject *cnnobj;
    2304 
    2305  if (cnnwin->priv->toolbar_is_reconfiguring)
    2306  return;
    2307  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2308 
    2309  capture = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle));
    2310 
    2311  if (cnnobj->connected){
    2312  remmina_file_set_int(cnnobj->remmina_file, "keyboard_grab", capture);
    2313  }
    2314 
    2315  if (capture && cnnobj->connected) {
    2316 
    2317 #if DEBUG_KB_GRABBING
    2318  printf("DEBUG_KB_GRABBING: Grabbing for button\n");
    2319 #endif
    2320  rcw_keyboard_grab(cnnobj->cnnwin);
    2321  if (cnnobj->cnnwin->priv->pointer_entered)
    2322  rcw_pointer_grab(cnnobj->cnnwin);
    2323  } else {
    2324  rcw_kp_ungrab(cnnobj->cnnwin);
    2325  }
    2326 }
    2327 
    2328 static GtkWidget *
    2330 {
    2331  TRACE_CALL(__func__);
    2332  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    2333  RemminaConnectionObject *cnnobj;
    2334  GtkWidget *toolbar;
    2335  GtkToolItem *toolitem;
    2336  GtkWidget *widget;
    2337  GtkWidget *arrow;
    2338 
    2339  GdkDisplay *display;
    2340  gint n_monitors;
    2341 
    2342  display = gdk_display_get_default();
    2343  n_monitors = gdk_display_get_n_monitors(display);
    2344 
    2345  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    2346 
    2347  priv->toolbar_is_reconfiguring = TRUE;
    2348 
    2349  toolbar = gtk_toolbar_new();
    2350  gtk_widget_show(toolbar);
    2351  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
    2352 
    2353  /* Main actions */
    2354 
    2355  /* Menu */
    2356  toolitem = gtk_toggle_tool_button_new();
    2357  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "view-more-symbolic");
    2358  gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), _("_Menu"));
    2359  gtk_tool_item_set_tooltip_text(toolitem, _("Menu"));
    2360  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2361  gtk_widget_show(GTK_WIDGET(toolitem));
    2362  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_menu), cnnwin);
    2363  priv->toolitem_menu = toolitem;
    2364 
    2365  /* Open Main window */
    2366  toolitem = gtk_tool_button_new(NULL, "Open Remmina Main window");
    2367  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "go-home-symbolic");
    2368  gtk_tool_item_set_tooltip_text(toolitem, _("Open the Remmina main window"));
    2369  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2370  gtk_widget_show(GTK_WIDGET(toolitem));
    2371  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_open_main), cnnwin);
    2372 
    2373  priv->toolitem_new = toolitem;
    2374 
    2375  /* Duplicate session */
    2376  toolitem = gtk_tool_button_new(NULL, "Duplicate connection");
    2377  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-duplicate-symbolic");
    2378  gtk_tool_item_set_tooltip_text(toolitem, _("Duplicate current connection"));
    2379  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2380  gtk_widget_show(GTK_WIDGET(toolitem));
    2381  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_duplicate), cnnwin);
    2382  if (!cnnobj)
    2383  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2384 
    2385  priv->toolitem_duplicate = toolitem;
    2386 
    2387  /* Separator */
    2388  toolitem = gtk_separator_tool_item_new();
    2389  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2390  gtk_widget_show(GTK_WIDGET(toolitem));
    2391 
    2392  /* Auto-Fit */
    2393  toolitem = gtk_tool_button_new(NULL, NULL);
    2394  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-fit-window-symbolic");
    2395  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Resize the window to fit in remote resolution"),
    2396  remmina_pref.shortcutkey_autofit, 0);
    2397  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_autofit), cnnwin);
    2398  priv->toolitem_autofit = toolitem;
    2399  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2400  gtk_widget_show(GTK_WIDGET(toolitem));
    2401 
    2402 
    2403  /* Fullscreen toggle */
    2404  toolitem = gtk_toggle_tool_button_new();
    2405  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-fullscreen-symbolic");
    2406  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Toggle fullscreen mode"),
    2407  remmina_pref.shortcutkey_fullscreen, 0);
    2408  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2409  gtk_widget_show(GTK_WIDGET(toolitem));
    2410  priv->toolitem_fullscreen = toolitem;
    2411  if (kioskmode) {
    2412  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem), FALSE);
    2413  } else {
    2414  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem), mode != SCROLLED_WINDOW_MODE);
    2415  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_fullscreen), cnnwin);
    2416  }
    2417 
    2418  /* Fullscreen drop-down options */
    2419  toolitem = gtk_tool_item_new();
    2420  gtk_widget_show(GTK_WIDGET(toolitem));
    2421  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2422  widget = gtk_toggle_button_new();
    2423  gtk_widget_show(widget);
    2424  gtk_container_set_border_width(GTK_CONTAINER(widget), 0);
    2425  gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
    2426 #if GTK_CHECK_VERSION(3, 20, 0)
    2427  gtk_widget_set_focus_on_click(GTK_WIDGET(widget), FALSE);
    2428  if (remmina_pref.small_toolbutton)
    2429  gtk_widget_set_name(widget, "remmina-small-button");
    2430 
    2431 #else
    2432  gtk_button_set_focus_on_click(GTK_BUTTON(widget), FALSE);
    2433 #endif
    2434  gtk_container_add(GTK_CONTAINER(toolitem), widget);
    2435 
    2436 #if GTK_CHECK_VERSION(3, 14, 0)
    2437  arrow = gtk_image_new_from_icon_name("org.remmina.Remmina-pan-down-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
    2438 #else
    2439  arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
    2440 #endif
    2441  gtk_widget_show(arrow);
    2442  gtk_container_add(GTK_CONTAINER(widget), arrow);
    2443  g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(rcw_toolbar_fullscreen_option), cnnwin);
    2444  priv->fullscreen_option_button = widget;
    2445  if (mode == SCROLLED_WINDOW_MODE)
    2446  gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);
    2447 
    2448  /* Multi monitor */
    2449  if (n_monitors > 1) {
    2450  toolitem = gtk_toggle_tool_button_new();
    2451  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-multi-monitor-symbolic");
    2452  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Multi monitor"),
    2453  remmina_pref.shortcutkey_multimon, 0);
    2454  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2455  gtk_widget_show(GTK_WIDGET(toolitem));
    2456  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_multi_monitor_mode), cnnwin);
    2457  priv->toolitem_multimon = toolitem;
    2458  if (!cnnobj)
    2459  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2460  else
    2461  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem),
    2462  remmina_file_get_int(cnnobj->remmina_file, "multimon", FALSE));
    2463  }
    2464 
    2465  /* Dynamic Resolution Update */
    2466  toolitem = gtk_toggle_tool_button_new();
    2467  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-dynres-symbolic");
    2468  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Toggle dynamic resolution update"),
    2469  remmina_pref.shortcutkey_dynres, 0);
    2470  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2471  gtk_widget_show(GTK_WIDGET(toolitem));
    2472  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_dynres), cnnwin);
    2473  priv->toolitem_dynres = toolitem;
    2474 
    2475  /* Scaler button */
    2476  toolitem = gtk_toggle_tool_button_new();
    2477  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-scale-symbolic");
    2478  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Toggle scaled mode"), remmina_pref.shortcutkey_scale, 0);
    2479  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2480  gtk_widget_show(GTK_WIDGET(toolitem));
    2481  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_scaled_mode), cnnwin);
    2482  priv->toolitem_scale = toolitem;
    2483 
    2484  /* Scaler aspect ratio dropdown menu */
    2485  toolitem = gtk_tool_item_new();
    2486  gtk_widget_show(GTK_WIDGET(toolitem));
    2487  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2488  widget = gtk_toggle_button_new();
    2489  gtk_widget_show(widget);
    2490  gtk_container_set_border_width(GTK_CONTAINER(widget), 0);
    2491  gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
    2492 #if GTK_CHECK_VERSION(3, 20, 0)
    2493  gtk_widget_set_focus_on_click(GTK_WIDGET(widget), FALSE);
    2494 #else
    2495  gtk_button_set_focus_on_click(GTK_BUTTON(widget), FALSE);
    2496 #endif
    2497  if (remmina_pref.small_toolbutton)
    2498  gtk_widget_set_name(widget, "remmina-small-button");
    2499  gtk_container_add(GTK_CONTAINER(toolitem), widget);
    2500 #if GTK_CHECK_VERSION(3, 14, 0)
    2501  arrow = gtk_image_new_from_icon_name("org.remmina.Remmina-pan-down-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
    2502 #else
    2503  arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
    2504 #endif
    2505  gtk_widget_show(arrow);
    2506  gtk_container_add(GTK_CONTAINER(widget), arrow);
    2507  g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(rcw_toolbar_scaler_option), cnnwin);
    2508  priv->scaler_option_button = widget;
    2509 
    2510  /* Separator */
    2511  toolitem = gtk_separator_tool_item_new();
    2512  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2513  gtk_widget_show(GTK_WIDGET(toolitem));
    2514 
    2515  /* Switch tabs */
    2516  toolitem = gtk_toggle_tool_button_new();
    2517  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-switch-page-symbolic");
    2518  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Switch tab pages"), remmina_pref.shortcutkey_prevtab,
    2519  remmina_pref.shortcutkey_nexttab);
    2520  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2521  gtk_widget_show(GTK_WIDGET(toolitem));
    2522  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_switch_page), cnnwin);
    2523  priv->toolitem_switch_page = toolitem;
    2524 
    2525  /* Grab keyboard button */
    2526  toolitem = gtk_toggle_tool_button_new();
    2527  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-keyboard-symbolic");
    2528  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Grab all keyboard events"),
    2529  remmina_pref.shortcutkey_grab, 0);
    2530  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2531  gtk_widget_show(GTK_WIDGET(toolitem));
    2532  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_grab), cnnwin);
    2533  priv->toolitem_grab = toolitem;
    2534  if (!cnnobj)
    2535  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2536  else {
    2537  const gchar *protocol = remmina_file_get_string(cnnobj->remmina_file, "protocol");
    2538  if (g_strcmp0(protocol, "SFTP") == 0 || g_strcmp0(protocol, "SSH") == 0)
    2539  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2540  }
    2541 
    2542  /* Preferences */
    2543  toolitem = gtk_toggle_tool_button_new();
    2544  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-preferences-system-symbolic");
    2545  gtk_tool_item_set_tooltip_text(toolitem, _("Preferences"));
    2546  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2547  gtk_widget_show(GTK_WIDGET(toolitem));
    2548  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_preferences), cnnwin);
    2549  priv->toolitem_preferences = toolitem;
    2550 
    2551  /* Tools */
    2552  toolitem = gtk_toggle_tool_button_new();
    2553  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-system-run-symbolic");
    2554  gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), _("_Tools"));
    2555  gtk_tool_item_set_tooltip_text(toolitem, _("Tools"));
    2556  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2557  gtk_widget_show(GTK_WIDGET(toolitem));
    2558  g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_tools), cnnwin);
    2559  priv->toolitem_tools = toolitem;
    2560 
    2561  /* Separator */
    2562  toolitem = gtk_separator_tool_item_new();
    2563  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2564  gtk_widget_show(GTK_WIDGET(toolitem));
    2565 
    2566  toolitem = gtk_tool_button_new(NULL, "_Screenshot");
    2567  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-camera-photo-symbolic");
    2568  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Screenshot"), remmina_pref.shortcutkey_screenshot, 0);
    2569  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2570  gtk_widget_show(GTK_WIDGET(toolitem));
    2571  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_screenshot), cnnwin);
    2572  priv->toolitem_screenshot = toolitem;
    2573 
    2574  /* Separator */
    2575  toolitem = gtk_separator_tool_item_new();
    2576  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2577  gtk_widget_show(GTK_WIDGET(toolitem));
    2578 
    2579  /* Minimize */
    2580  toolitem = gtk_tool_button_new(NULL, "_Bottom");
    2581  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-go-bottom-symbolic");
    2582  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Minimize window"), remmina_pref.shortcutkey_minimize, 0);
    2583  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2584  gtk_widget_show(GTK_WIDGET(toolitem));
    2585  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_minimize), cnnwin);
    2586  if (kioskmode)
    2587  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2588 
    2589  /* Disconnect */
    2590  toolitem = gtk_tool_button_new(NULL, "_Disconnect");
    2591  gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "org.remmina.Remmina-disconnect-symbolic");
    2592  rcw_set_tooltip(GTK_WIDGET(toolitem), _("Disconnect"), remmina_pref.shortcutkey_disconnect, 0);
    2593  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    2594  gtk_widget_show(GTK_WIDGET(toolitem));
    2595  g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(rcw_toolbar_disconnect), cnnwin);
    2596 
    2597  priv->toolbar_is_reconfiguring = FALSE;
    2598  return toolbar;
    2599 }
    2600 
    2601 static void rcw_place_toolbar(GtkToolbar *toolbar, GtkGrid *grid, GtkWidget *sibling, int toolbar_placement)
    2602 {
    2603  /* Place the toolbar inside the grid and set its orientation */
    2604 
    2605  if (toolbar_placement == TOOLBAR_PLACEMENT_LEFT || toolbar_placement == TOOLBAR_PLACEMENT_RIGHT)
    2606  gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_VERTICAL);
    2607  else
    2608  gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
    2609 
    2610 
    2611  switch (toolbar_placement) {
    2612  case TOOLBAR_PLACEMENT_TOP:
    2613  gtk_widget_set_hexpand(GTK_WIDGET(toolbar), TRUE);
    2614  gtk_widget_set_vexpand(GTK_WIDGET(toolbar), FALSE);
    2615  gtk_grid_attach_next_to(GTK_GRID(grid), GTK_WIDGET(toolbar), sibling, GTK_POS_TOP, 1, 1);
    2616  break;
    2618  gtk_widget_set_vexpand(GTK_WIDGET(toolbar), TRUE);
    2619  gtk_widget_set_hexpand(GTK_WIDGET(toolbar), FALSE);
    2620  gtk_grid_attach_next_to(GTK_GRID(grid), GTK_WIDGET(toolbar), sibling, GTK_POS_RIGHT, 1, 1);
    2621  break;
    2623  gtk_widget_set_hexpand(GTK_WIDGET(toolbar), TRUE);
    2624  gtk_widget_set_vexpand(GTK_WIDGET(toolbar), FALSE);
    2625  gtk_grid_attach_next_to(GTK_GRID(grid), GTK_WIDGET(toolbar), sibling, GTK_POS_BOTTOM, 1, 1);
    2626  break;
    2628  gtk_widget_set_vexpand(GTK_WIDGET(toolbar), TRUE);
    2629  gtk_widget_set_hexpand(GTK_WIDGET(toolbar), FALSE);
    2630  gtk_grid_attach_next_to(GTK_GRID(grid), GTK_WIDGET(toolbar), sibling, GTK_POS_LEFT, 1, 1);
    2631  break;
    2632  }
    2633 }
    2634 
    2636 {
    2637  TRACE_CALL(__func__);
    2638  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    2639  GtkToolItem *toolitem;
    2640  gboolean bval, dynres_avail, scale_avail;
    2641  gboolean test_floating_toolbar;
    2642  RemminaScaleMode scalemode;
    2643 
    2644  priv->toolbar_is_reconfiguring = TRUE;
    2645 
    2647 
    2648  toolitem = priv->toolitem_switch_page;
    2649  if (kioskmode)
    2650  bval = FALSE;
    2651  else
    2652  bval = (gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook)) > 1);
    2653  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), bval);
    2654 
    2655  if (cnnobj->remmina_file->filename)
    2656  gtk_widget_set_sensitive(GTK_WIDGET(priv->toolitem_duplicate), TRUE);
    2657  else
    2658  gtk_widget_set_sensitive(GTK_WIDGET(priv->toolitem_duplicate), FALSE);
    2659 
    2660  scalemode = get_current_allowed_scale_mode(cnnobj, &dynres_avail, &scale_avail);
    2661  gtk_widget_set_sensitive(GTK_WIDGET(priv->toolitem_dynres), dynres_avail && cnnobj->connected);
    2662  gtk_widget_set_sensitive(GTK_WIDGET(priv->toolitem_scale), scale_avail && cnnobj->connected);
    2663 
    2664  switch (scalemode) {
    2666  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_dynres), FALSE);
    2667  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_scale), FALSE);
    2668  gtk_widget_set_sensitive(GTK_WIDGET(priv->scaler_option_button), FALSE);
    2669  break;
    2671  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_dynres), FALSE);
    2672  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_scale), TRUE);
    2673  gtk_widget_set_sensitive(GTK_WIDGET(priv->scaler_option_button), TRUE && cnnobj->connected);
    2674  break;
    2676  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_dynres), TRUE);
    2677  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_scale), FALSE);
    2678  gtk_widget_set_sensitive(GTK_WIDGET(priv->scaler_option_button), FALSE);
    2679  break;
    2680  }
    2681 
    2682  /* REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON */
    2683  toolitem = priv->toolitem_multimon;
    2684  if (toolitem) {
    2685  gint hasmultimon = remmina_protocol_widget_query_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    2687 
    2688  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), cnnobj->connected);
    2689  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem),
    2690  remmina_file_get_int(cnnobj->remmina_file, "multimon", FALSE));
    2691  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), hasmultimon);
    2692  }
    2693 
    2694  toolitem = priv->toolitem_grab;
    2695  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), cnnobj->connected);
    2696  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem),
    2697  remmina_file_get_int(cnnobj->remmina_file, "keyboard_grab", FALSE));
    2698  const gchar *protocol = remmina_file_get_string(cnnobj->remmina_file, "protocol");
    2699  if (g_strcmp0(protocol, "SFTP") == 0 || g_strcmp0(protocol, "SSH") == 0) {
    2700  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), FALSE);
    2701  gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem), FALSE);
    2702  remmina_file_set_int(cnnobj->remmina_file, "keyboard_grab", FALSE);
    2703  }
    2704 
    2705  toolitem = priv->toolitem_preferences;
    2706  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), cnnobj->connected);
    2707  bval = remmina_protocol_widget_query_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    2709  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), bval && cnnobj->connected);
    2710 
    2711  toolitem = priv->toolitem_tools;
    2712  bval = remmina_protocol_widget_query_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    2714  gtk_widget_set_sensitive(GTK_WIDGET(toolitem), bval && cnnobj->connected);
    2715 
    2716  gtk_widget_set_sensitive(GTK_WIDGET(priv->toolitem_screenshot), cnnobj->connected);
    2717 
    2718  gtk_window_set_title(GTK_WINDOW(cnnobj->cnnwin), remmina_file_get_string(cnnobj->remmina_file, "name"));
    2719 
    2720  test_floating_toolbar = (priv->floating_toolbar_widget != NULL);
    2721 
    2722  if (test_floating_toolbar) {
    2723  const gchar *str = remmina_file_get_string(cnnobj->remmina_file, "name");
    2724  const gchar *format;
    2725  GdkRGBA rgba;
    2726  gchar *bg;
    2727 
    2728  bg = g_strdup(remmina_pref.grab_color);
    2729  if (!gdk_rgba_parse(&rgba, bg)) {
    2730  REMMINA_DEBUG("%s cannot be parsed as a color", bg);
    2731  bg = g_strdup("#00FF00");
    2732  } else {
    2733  REMMINA_DEBUG("Using %s as background color", bg);
    2734  }
    2735 
    2736  if (remmina_file_get_int(cnnobj->remmina_file, "keyboard_grab", FALSE)) {
    2737  if (remmina_pref_get_boolean("grab_color_switch"))
    2738  format = g_strconcat("<span bgcolor=\"", bg, "\" size=\"large\"><b>(G:ON) - \%s</b></span>", NULL);
    2739  else
    2740  format = "<big><b>(G:ON) - \%s</b></big>";
    2741  } else {
    2742  format = "<big><b>(G:OFF) - \%s</b></big>";
    2743  }
    2744  gchar *markup;
    2745 
    2746  markup = g_markup_printf_escaped(format, str);
    2747  gtk_label_set_markup(GTK_LABEL(priv->floating_toolbar_label), markup);
    2748  g_free(markup);
    2749  g_free(bg);
    2750  }
    2751 
    2752  priv->toolbar_is_reconfiguring = FALSE;
    2753 }
    2754 
    2756 {
    2757  TRACE_CALL(__func__);
    2758  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    2759 
    2760  if (priv->view_mode == SCROLLED_WINDOW_MODE) {
    2761  if (remmina_pref.hide_connection_toolbar)
    2762  gtk_widget_hide(priv->toolbar);
    2763  else
    2764  gtk_widget_show(priv->toolbar);
    2765  }
    2766 }
    2767 
    2768 #if DEBUG_KB_GRABBING
    2769 static void print_crossing_event(GdkEventCrossing *event) {
    2770  printf("DEBUG_KB_GRABBING: --- Crossing event detail: ");
    2771  switch (event->detail) {
    2772  case GDK_NOTIFY_ANCESTOR: printf("GDK_NOTIFY_ANCESTOR"); break;
    2773  case GDK_NOTIFY_VIRTUAL: printf("GDK_NOTIFY_VIRTUAL"); break;
    2774  case GDK_NOTIFY_NONLINEAR: printf("GDK_NOTIFY_NONLINEAR"); break;
    2775  case GDK_NOTIFY_NONLINEAR_VIRTUAL: printf("GDK_NOTIFY_NONLINEAR_VIRTUAL"); break;
    2776  case GDK_NOTIFY_UNKNOWN: printf("GDK_NOTIFY_UNKNOWN"); break;
    2777  case GDK_NOTIFY_INFERIOR: printf("GDK_NOTIFY_INFERIOR"); break;
    2778  default: printf("unknown");
    2779  }
    2780  printf("\n");
    2781  printf("DEBUG_KB_GRABBING: --- Crossing event mode=");
    2782  switch (event->mode) {
    2783  case GDK_CROSSING_NORMAL: printf("GDK_CROSSING_NORMAL"); break;
    2784  case GDK_CROSSING_GRAB: printf("GDK_CROSSING_GRAB"); break;
    2785  case GDK_CROSSING_UNGRAB: printf("GDK_CROSSING_UNGRAB"); break;
    2786  case GDK_CROSSING_GTK_GRAB: printf("GDK_CROSSING_GTK_GRAB"); break;
    2787  case GDK_CROSSING_GTK_UNGRAB: printf("GDK_CROSSING_GTK_UNGRAB"); break;
    2788  case GDK_CROSSING_STATE_CHANGED: printf("GDK_CROSSING_STATE_CHANGED"); break;
    2789  case GDK_CROSSING_TOUCH_BEGIN: printf("GDK_CROSSING_TOUCH_BEGIN"); break;
    2790  case GDK_CROSSING_TOUCH_END: printf("GDK_CROSSING_TOUCH_END"); break;
    2791  case GDK_CROSSING_DEVICE_SWITCH: printf("GDK_CROSSING_DEVICE_SWITCH"); break;
    2792  default: printf("unknown");
    2793  }
    2794  printf("\n");
    2795 }
    2796 #endif
    2797 
    2798 static gboolean rcw_floating_toolbar_on_enter(GtkWidget *widget, GdkEventCrossing *event,
    2799  RemminaConnectionWindow *cnnwin)
    2800 {
    2801  TRACE_CALL(__func__);
    2802  rcw_floating_toolbar_show(cnnwin, TRUE);
    2803  return TRUE;
    2804 }
    2805 
    2806 static gboolean rcw_floating_toolbar_on_leave(GtkWidget *widget, GdkEventCrossing *event,
    2807  RemminaConnectionWindow *cnnwin)
    2808 {
    2809  TRACE_CALL(__func__);
    2810  if (event->detail != GDK_NOTIFY_INFERIOR)
    2811  rcw_floating_toolbar_show(cnnwin, FALSE);
    2812  return TRUE;
    2813 }
    2814 
    2815 
    2816 static gboolean rcw_on_enter_notify_event(GtkWidget *widget, GdkEventCrossing *event,
    2817  gpointer user_data)
    2818 {
    2819  TRACE_CALL(__func__);
    2820 #if DEBUG_KB_GRABBING
    2821  printf("DEBUG_KB_GRABBING: enter-notify-event on rcw received\n");
    2822  print_crossing_event(event);
    2823 #endif
    2824  return FALSE;
    2825 }
    2826 
    2827 
    2828 
    2829 static gboolean rcw_on_leave_notify_event(GtkWidget *widget, GdkEventCrossing *event,
    2830  gpointer user_data)
    2831 {
    2832  TRACE_CALL(__func__);
    2834 
    2835 #if DEBUG_KB_GRABBING
    2836  printf("DEBUG_KB_GRABBING: leave-notify-event on rcw received\n");
    2837  print_crossing_event(event);
    2838 #endif
    2839 
    2840  if (event->mode != GDK_CROSSING_NORMAL && event->mode != GDK_CROSSING_UNGRAB) {
    2841 #if DEBUG_KB_GRABBING
    2842  printf("DEBUG_KB_GRABBING: ignored because mode is not GDK_CROSSING_NORMAL GDK_CROSSING_UNGRAB\n");
    2843 #endif
    2844  return FALSE;
    2845  }
    2846 
    2847  if (cnnwin->priv->delayed_grab_eventsourceid) {
    2848  g_source_remove(cnnwin->priv->delayed_grab_eventsourceid);
    2849  cnnwin->priv->delayed_grab_eventsourceid = 0;
    2850  }
    2851 
    2852  /* Workaround for https://gitlab.gnome.org/GNOME/mutter/-/issues/2450#note_1586570 */
    2853  if (event->mode != GDK_CROSSING_UNGRAB) {
    2854  rcw_kp_ungrab(cnnwin);
    2855  rcw_pointer_ungrab(cnnwin);
    2856  } else {
    2857 #if DEBUG_KB_GRABBING
    2858  printf("DEBUG_KB_GRABBING: not ungrabbing, this event seems to be an unwanted event from GTK\n");
    2859 #endif
    2860  }
    2861 
    2862  return FALSE;
    2863 }
    2864 
    2865 
    2866 static gboolean rco_leave_protocol_widget(GtkWidget *widget, GdkEventCrossing *event,
    2867  RemminaConnectionObject *cnnobj)
    2868 {
    2869  TRACE_CALL(__func__);
    2870 
    2871 #if DEBUG_KB_GRABBING
    2872  printf("DEBUG_KB_GRABBING: received leave event on RCO.\n");
    2873  print_crossing_event(event);
    2874 #endif
    2875 
    2876  if (cnnobj->cnnwin->priv->delayed_grab_eventsourceid) {
    2877  g_source_remove(cnnobj->cnnwin->priv->delayed_grab_eventsourceid);
    2878  cnnobj->cnnwin->priv->delayed_grab_eventsourceid = 0;
    2879  }
    2880 
    2881  cnnobj->cnnwin->priv->pointer_entered = FALSE;
    2882 
    2883  /* Ungrab only if the leave is due to normal mouse motion and not to an inferior */
    2884  if (event->mode == GDK_CROSSING_NORMAL && event->detail != GDK_NOTIFY_INFERIOR)
    2885  rcw_kp_ungrab(cnnobj->cnnwin);
    2886 
    2887  return FALSE;
    2888 }
    2889 
    2890 
    2891 gboolean rco_enter_protocol_widget(GtkWidget *widget, GdkEventCrossing *event,
    2892  RemminaConnectionObject *cnnobj)
    2893 {
    2894  TRACE_CALL(__func__);
    2895  gboolean active;
    2896 
    2897 #if DEBUG_KB_GRABBING
    2898  printf("DEBUG_KB_GRABBING: %s: enter on protocol widget event received\n", __func__);
    2899  print_crossing_event(event);
    2900 #endif
    2901 
    2902  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    2903  if (!priv->sticky && event->mode == GDK_CROSSING_NORMAL)
    2904  rcw_floating_toolbar_show(cnnobj->cnnwin, FALSE);
    2905 
    2906  priv->pointer_entered = TRUE;
    2907 
    2908  if (event->mode == GDK_CROSSING_UNGRAB) {
    2909  // Someone steal our grab, take note and do not attempt to regrab
    2910  cnnobj->cnnwin->priv->kbcaptured = FALSE;
    2911  cnnobj->cnnwin->priv->pointer_captured = FALSE;
    2912  return FALSE;
    2913  }
    2914 
    2915  /* Check if we need grabbing */
    2916  active = gtk_window_is_active(GTK_WINDOW(cnnobj->cnnwin));
    2917  if (remmina_file_get_int(cnnobj->remmina_file, "keyboard_grab", FALSE) && active) {
    2918  rcw_keyboard_grab(cnnobj->cnnwin);
    2919  rcw_pointer_grab(cnnobj->cnnwin);
    2920  }
    2921 
    2922  return FALSE;
    2923 }
    2924 
    2926 {
    2927  TRACE_CALL(__func__);
    2928 
    2929 #if DEBUG_KB_GRABBING
    2930  printf("DEBUG_KB_GRABBING: %s\n", __func__);
    2931 #endif
    2932  if (cnnwin->priv->pointer_entered) {
    2933 #if DEBUG_KB_GRABBING
    2934  printf("DEBUG_KB_GRABBING: delayed requesting kb and pointer grab, because of pointer inside\n");
    2935 #endif
    2936  rcw_keyboard_grab(cnnwin);
    2937  rcw_pointer_grab(cnnwin);
    2938  }
    2939 #if DEBUG_KB_GRABBING
    2940  else {
    2941  printf("DEBUG_KB_GRABBING: %s not grabbing because pointer_entered is false\n", __func__);
    2942  }
    2943 #endif
    2944  cnnwin->priv->delayed_grab_eventsourceid = 0;
    2945  return G_SOURCE_REMOVE;
    2946 }
    2947 
    2949 {
    2950  /* This function is the default signal handler for focus-in-event,
    2951  * but can also be called after a window focus state change event
    2952  * from rcw_state_event(). So expect to be called twice
    2953  * when cnnwin gains the focus */
    2954 
    2955  TRACE_CALL(__func__);
    2956  RemminaConnectionObject *cnnobj;
    2957 
    2958  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2959 
    2960  if (cnnobj && cnnobj->connected && remmina_file_get_int(cnnobj->remmina_file, "keyboard_grab", FALSE)) {
    2961 #if DEBUG_KB_GRABBING
    2962  printf("DEBUG_KB_GRABBING: Received focus in on rcw, grabbing enabled: requesting kb grab, delayed\n");
    2963 #endif
    2964  if (cnnwin->priv->delayed_grab_eventsourceid == 0)
    2965  cnnwin->priv->delayed_grab_eventsourceid = g_timeout_add(300, (GSourceFunc)focus_in_delayed_grab, cnnwin);
    2966  }
    2967 #if DEBUG_KB_GRABBING
    2968  else {
    2969  printf("DEBUG_KB_GRABBING: Received focus in on rcw, but a condition will prevent to grab\n");
    2970  }
    2971 #endif
    2972 }
    2973 
    2975 {
    2976  /* This function is the default signal handler for focus-out-event,
    2977  * but can also be called after a window focus state change event
    2978  * from rcw_state_event(). So expect to be called twice
    2979  * when cnnwin loses the focus */
    2980 
    2981  TRACE_CALL(__func__);
    2982  RemminaConnectionObject *cnnobj;
    2983 
    2984  rcw_kp_ungrab(cnnwin);
    2985 
    2986  cnnwin->priv->hostkey_activated = FALSE;
    2987  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    2988 
    2989  if (REMMINA_IS_SCROLLED_VIEWPORT(cnnobj->scrolled_container))
    2990  remmina_scrolled_viewport_remove_motion(REMMINA_SCROLLED_VIEWPORT(cnnobj->scrolled_container));
    2991 
    2992  if (cnnobj->proto && cnnobj->scrolled_container)
    2993  remmina_protocol_widget_call_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    2995 }
    2996 
    2997 static gboolean
    2999 {
    3000  TRACE_CALL(__func__);
    3001  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    3002 
    3003  priv->hidetb_eventsource = 0;
    3004  rcw_floating_toolbar_show(cnnwin, FALSE);
    3005  return G_SOURCE_REMOVE;
    3006 }
    3007 
    3008 static gboolean rcw_floating_toolbar_on_scroll(GtkWidget *widget, GdkEventScroll *event,
    3009  RemminaConnectionWindow *cnnwin)
    3010 {
    3011  TRACE_CALL(__func__);
    3012  RemminaConnectionObject *cnnobj;
    3013 
    3014  int opacity;
    3015 
    3016  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    3017  if (!cnnobj)
    3018  return TRUE;
    3019 
    3020  opacity = remmina_file_get_int(cnnobj->remmina_file, "toolbar_opacity", 0);
    3021  switch (event->direction) {
    3022  case GDK_SCROLL_UP:
    3023  if (opacity > 0) {
    3024  remmina_file_set_int(cnnobj->remmina_file, "toolbar_opacity", opacity - 1);
    3026  return TRUE;
    3027  }
    3028  break;
    3029  case GDK_SCROLL_DOWN:
    3030  if (opacity < TOOLBAR_OPACITY_LEVEL) {
    3031  remmina_file_set_int(cnnobj->remmina_file, "toolbar_opacity", opacity + 1);
    3033  return TRUE;
    3034  }
    3035  break;
    3036 #if GTK_CHECK_VERSION(3, 4, 0)
    3037  case GDK_SCROLL_SMOOTH:
    3038  if (event->delta_y < 0 && opacity > 0) {
    3039  remmina_file_set_int(cnnobj->remmina_file, "toolbar_opacity", opacity - 1);
    3041  return TRUE;
    3042  }
    3043  if (event->delta_y > 0 && opacity < TOOLBAR_OPACITY_LEVEL) {
    3044  remmina_file_set_int(cnnobj->remmina_file, "toolbar_opacity", opacity + 1);
    3046  return TRUE;
    3047  }
    3048  break;
    3049 #endif
    3050  default:
    3051  break;
    3052  }
    3053  return TRUE;
    3054 }
    3055 
    3056 static gboolean rcw_after_configure_scrolled(gpointer user_data)
    3057 {
    3058  TRACE_CALL(__func__);
    3059  gint width, height;
    3060  GdkWindowState s;
    3061  gint ipg, npages;
    3062  RemminaConnectionWindow *cnnwin;
    3063 
    3064  cnnwin = (RemminaConnectionWindow *)user_data;
    3065 
    3066  if (!cnnwin || !cnnwin->priv)
    3067  return FALSE;
    3068 
    3069  s = gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(cnnwin)));
    3070 
    3071 
    3072  /* Changed window_maximize, window_width and window_height for all
    3073  * connections inside the notebook */
    3074  npages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(cnnwin->priv->notebook));
    3075  for (ipg = 0; ipg < npages; ipg++) {
    3076  RemminaConnectionObject *cnnobj;
    3077  cnnobj = g_object_get_data(
    3078  G_OBJECT(gtk_notebook_get_nth_page(GTK_NOTEBOOK(cnnwin->priv->notebook), ipg)),
    3079  "cnnobj");
    3080  if (s & GDK_WINDOW_STATE_MAXIMIZED) {
    3081  remmina_file_set_int(cnnobj->remmina_file, "window_maximize", TRUE);
    3082  } else {
    3083  gtk_window_get_size(GTK_WINDOW(cnnobj->cnnwin), &width, &height);
    3084  remmina_file_set_int(cnnobj->remmina_file, "window_width", width);
    3085  remmina_file_set_int(cnnobj->remmina_file, "window_height", height);
    3086  remmina_file_set_int(cnnobj->remmina_file, "window_maximize", FALSE);
    3087  }
    3088  }
    3089  cnnwin->priv->acs_eventsourceid = 0;
    3090  return FALSE;
    3091 }
    3092 
    3093 static gboolean rcw_on_configure(GtkWidget *widget, GdkEventConfigure *event,
    3094  gpointer data)
    3095 {
    3096  TRACE_CALL(__func__);
    3097  RemminaConnectionWindow *cnnwin;
    3098  RemminaConnectionObject *cnnobj;
    3099 
    3100  if (!REMMINA_IS_CONNECTION_WINDOW(widget))
    3101  return FALSE;
    3102 
    3103  cnnwin = (RemminaConnectionWindow *)widget;
    3104 
    3105  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return FALSE;
    3106 
    3107  if (cnnwin->priv->acs_eventsourceid) {
    3108  g_source_remove(cnnwin->priv->acs_eventsourceid);
    3109  cnnwin->priv->acs_eventsourceid = 0;
    3110  }
    3111 
    3112  if (gtk_widget_get_window(GTK_WIDGET(cnnwin))
    3113  && cnnwin->priv->view_mode == SCROLLED_WINDOW_MODE)
    3114  /* Under GNOME Shell we receive this configure_event BEFORE a window
    3115  * is really unmaximized, so we must read its new state and dimensions
    3116  * later, not now */
    3117  cnnwin->priv->acs_eventsourceid = g_timeout_add(500, rcw_after_configure_scrolled, cnnwin);
    3118 
    3119  if (cnnwin->priv->view_mode != SCROLLED_WINDOW_MODE)
    3120  /* Notify window of change so that scroll border can be hidden or shown if needed */
    3121  rco_check_resize(cnnobj);
    3122  return FALSE;
    3123 }
    3124 
    3126 {
    3127  TRACE_CALL(__func__);
    3128  if (cnnwin->priv->pin_down)
    3129  gtk_button_set_image(GTK_BUTTON(cnnwin->priv->pin_button),
    3130  gtk_image_new_from_icon_name("org.remmina.Remmina-pin-down-symbolic", GTK_ICON_SIZE_MENU));
    3131  else
    3132  gtk_button_set_image(GTK_BUTTON(cnnwin->priv->pin_button),
    3133  gtk_image_new_from_icon_name("org.remmina.Remmina-pin-up-symbolic", GTK_ICON_SIZE_MENU));
    3134 }
    3135 
    3136 static void rcw_toolbar_pin(GtkWidget *widget, RemminaConnectionWindow *cnnwin)
    3137 {
    3138  TRACE_CALL(__func__);
    3139  remmina_pref.toolbar_pin_down = cnnwin->priv->pin_down = !cnnwin->priv->pin_down;
    3141  rcw_update_pin(cnnwin);
    3142 }
    3143 
    3145 {
    3146  TRACE_CALL(__func__);
    3147 
    3148  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    3149  GtkWidget *ftb_widget;
    3150  GtkWidget *vbox;
    3151  GtkWidget *hbox;
    3152  GtkWidget *label;
    3153  GtkWidget *pinbutton;
    3154  GtkWidget *tb;
    3155 
    3156 
    3157  /* A widget to be used for GtkOverlay for GTK >= 3.10 */
    3158  ftb_widget = gtk_event_box_new();
    3159 
    3160  vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    3161  gtk_widget_show(vbox);
    3162 
    3163  gtk_container_add(GTK_CONTAINER(ftb_widget), vbox);
    3164 
    3165  tb = rcw_create_toolbar(cnnwin, mode);
    3166  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    3167  gtk_widget_show(hbox);
    3168 
    3169 
    3170  /* The pin button */
    3171  pinbutton = gtk_button_new();
    3172  gtk_widget_show(pinbutton);
    3173  gtk_box_pack_start(GTK_BOX(hbox), pinbutton, FALSE, FALSE, 0);
    3174  gtk_button_set_relief(GTK_BUTTON(pinbutton), GTK_RELIEF_NONE);
    3175 #if GTK_CHECK_VERSION(3, 20, 0)
    3176  gtk_widget_set_focus_on_click(GTK_WIDGET(pinbutton), FALSE);
    3177 #else
    3178  gtk_button_set_focus_on_click(GTK_BUTTON(pinbutton), FALSE);
    3179 #endif
    3180  gtk_widget_set_name(pinbutton, "remmina-pin-button");
    3181  g_signal_connect(G_OBJECT(pinbutton), "clicked", G_CALLBACK(rcw_toolbar_pin), cnnwin);
    3182  priv->pin_button = pinbutton;
    3183  priv->pin_down = remmina_pref.toolbar_pin_down;
    3184  rcw_update_pin(cnnwin);
    3185 
    3186 
    3187  label = gtk_label_new("");
    3188  gtk_label_set_max_width_chars(GTK_LABEL(label), 50);
    3189  gtk_widget_show(label);
    3190 
    3191  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
    3192 
    3193  priv->floating_toolbar_label = label;
    3194 
    3196  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    3197  gtk_box_pack_start(GTK_BOX(vbox), tb, FALSE, FALSE, 0);
    3198  } else {
    3199  gtk_box_pack_start(GTK_BOX(vbox), tb, FALSE, FALSE, 0);
    3200  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    3201  }
    3202 
    3203  priv->floating_toolbar_widget = ftb_widget;
    3204  gtk_widget_show(ftb_widget);
    3205 }
    3206 
    3207 static void rcw_toolbar_place_signal(RemminaConnectionWindow *cnnwin, gpointer data)
    3208 {
    3209  TRACE_CALL(__func__);
    3211 
    3212  priv = cnnwin->priv;
    3213  /* Detach old toolbar widget and reattach in new position in the grid */
    3214  if (priv->toolbar && priv->grid) {
    3215  g_object_ref(priv->toolbar);
    3216  gtk_container_remove(GTK_CONTAINER(priv->grid), priv->toolbar);
    3217  rcw_place_toolbar(GTK_TOOLBAR(priv->toolbar), GTK_GRID(priv->grid), GTK_WIDGET(priv->notebook), remmina_pref.toolbar_placement);
    3218  g_object_unref(priv->toolbar);
    3219  }
    3220 }
    3221 
    3222 
    3223 static void rcw_init(RemminaConnectionWindow *cnnwin)
    3224 {
    3225  TRACE_CALL(__func__);
    3227 
    3228  priv = g_new0(RemminaConnectionWindowPriv, 1);
    3229  cnnwin->priv = priv;
    3230 
    3231  priv->view_mode = SCROLLED_WINDOW_MODE;
    3232  if (kioskmode && kioskmode == TRUE)
    3233  priv->view_mode = VIEWPORT_FULLSCREEN_MODE;
    3234 
    3235  priv->floating_toolbar_opacity = 1.0;
    3236  priv->kbcaptured = FALSE;
    3237  priv->pointer_captured = FALSE;
    3238  priv->pointer_entered = FALSE;
    3239  priv->fss_view_mode = VIEWPORT_FULLSCREEN_MODE;
    3240  priv->ss_width = 640;
    3241  priv->ss_height = 480;
    3242  priv->ss_maximized = FALSE;
    3243 
    3244  remmina_widget_pool_register(GTK_WIDGET(cnnwin));
    3245 }
    3246 
    3247 static gboolean rcw_focus_in_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
    3248 {
    3249  TRACE_CALL(__func__);
    3250 #if DEBUG_KB_GRABBING
    3251  printf("DEBUG_KB_GRABBING: RCW focus-in-event received\n");
    3252 #endif
    3254  return FALSE;
    3255 }
    3256 
    3257 static gboolean rcw_focus_out_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
    3258 {
    3259  TRACE_CALL(__func__);
    3260 #if DEBUG_KB_GRABBING
    3261  printf("DEBUG_KB_GRABBING: RCW focus-out-event received\n");
    3262 #endif
    3264  return FALSE;
    3265 }
    3266 
    3267 
    3268 static gboolean rcw_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
    3269 {
    3270  TRACE_CALL(__func__);
    3271 
    3272  if (!REMMINA_IS_CONNECTION_WINDOW(widget))
    3273  return FALSE;
    3274 
    3275 #if DEBUG_KB_GRABBING
    3276  printf("DEBUG_KB_GRABBING: window-state-event received\n");
    3277 #endif
    3278 
    3279  if (event->changed_mask & GDK_WINDOW_STATE_FOCUSED) {
    3280  if (event->new_window_state & GDK_WINDOW_STATE_FOCUSED)
    3282  else
    3284  }
    3285 
    3286  return FALSE;
    3287 }
    3288 
    3289 static gboolean rcw_map_event(GtkWidget *widget, GdkEvent *event, gpointer data)
    3290 {
    3291  TRACE_CALL(__func__);
    3292 
    3293 
    3294 
    3296  RemminaConnectionObject *cnnobj;
    3298 
    3299  if (cnnwin->priv->toolbar_is_reconfiguring) return FALSE;
    3300  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return FALSE;
    3301 
    3302  gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    3303  REMMINA_DEBUG("Mapping: %s", gtk_widget_get_name(widget));
    3305  REMMINA_DEBUG("Called plugin mapping function");
    3306  return FALSE;
    3307 }
    3308 
    3309 static gboolean rcw_unmap_event(GtkWidget *widget, GdkEvent *event, gpointer data)
    3310 {
    3311  TRACE_CALL(__func__);
    3312 
    3314  RemminaConnectionObject *cnnobj;
    3316 
    3317  if (cnnwin->priv->toolbar_is_reconfiguring) return FALSE;
    3318  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return FALSE;
    3319 
    3320  gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    3321  REMMINA_DEBUG("Unmapping: %s", gtk_widget_get_name(widget));
    3323  REMMINA_DEBUG("Called plugin mapping function");
    3324  return FALSE;
    3325 }
    3326 
    3327 static gboolean rcw_map_event_fullscreen(GtkWidget *widget, GdkEvent *event, gpointer data)
    3328 {
    3329  TRACE_CALL(__func__);
    3330  RemminaConnectionObject *cnnobj;
    3331  gint target_monitor;
    3332 
    3333  REMMINA_DEBUG("Mapping: %s", gtk_widget_get_name(widget));
    3334 
    3335  if (!REMMINA_IS_CONNECTION_WINDOW(widget)) {
    3336  REMMINA_DEBUG("Remmina Connection Window undefined, cannot go fullscreen");
    3337  return FALSE;
    3338  }
    3339 
    3340  //RemminaConnectionWindow *cnnwin = (RemminaConnectionWindow *)data;
    3341  cnnobj = rcw_get_visible_cnnobj((RemminaConnectionWindow *)widget);
    3342  //cnnobj = g_object_get_data(G_OBJECT(widget), "cnnobj");
    3343  if (!cnnobj) {
    3344  REMMINA_DEBUG("Remmina Connection Object undefined, cannot go fullscreen");
    3345  return FALSE;
    3346  }
    3347 
    3348  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
    3349 
    3350  if (!gp)
    3351  REMMINA_DEBUG("Remmina Protocol Widget undefined, cannot go fullscreen");
    3352 
    3353  if (remmina_protocol_widget_get_multimon(gp) >= 1) {
    3354  REMMINA_DEBUG("Fullscreen on all monitor");
    3355  gdk_window_set_fullscreen_mode(gtk_widget_get_window(widget), GDK_FULLSCREEN_ON_ALL_MONITORS);
    3356  gdk_window_fullscreen(gtk_widget_get_window(widget));
    3357  return TRUE;
    3358  } else {
    3359  REMMINA_DEBUG("Fullscreen on one monitor");
    3360  }
    3361 
    3362  target_monitor = GPOINTER_TO_INT(data);
    3363 
    3364 #if GTK_CHECK_VERSION(3, 18, 0)
    3365  if (remmina_pref.fullscreen_on_auto) {
    3366  if (target_monitor == FULL_SCREEN_TARGET_MONITOR_UNDEFINED)
    3367  gtk_window_fullscreen(GTK_WINDOW(widget));
    3368  else
    3369  gtk_window_fullscreen_on_monitor(GTK_WINDOW(widget), gtk_window_get_screen(GTK_WINDOW(widget)),
    3370  target_monitor);
    3371  } else {
    3372  REMMINA_DEBUG("Fullscreen managed by WM or by the user, as per settings");
    3373  gtk_window_fullscreen(GTK_WINDOW(widget));
    3374  }
    3375 #else
    3376  REMMINA_DEBUG("Cannot fullscreen on a specific monitor, feature available from GTK 3.18");
    3377  gtk_window_fullscreen(GTK_WINDOW(widget));
    3378 #endif
    3379 
    3381  REMMINA_DEBUG("Called plugin mapping function");
    3382 
    3383  return FALSE;
    3384 }
    3385 
    3386 static RemminaConnectionWindow *
    3387 rcw_new(gboolean fullscreen, int full_screen_target_monitor)
    3388 {
    3389  TRACE_CALL(__func__);
    3390  RemminaConnectionWindow *cnnwin;
    3391 
    3392  cnnwin = RCW(g_object_new(REMMINA_TYPE_CONNECTION_WINDOW, NULL));
    3393  cnnwin->priv->on_delete_confirm_mode = RCW_ONDELETE_CONFIRM_IF_2_OR_MORE;
    3394 
    3395  if (fullscreen)
    3396  /* Put the window in fullscreen after it is mapped to have it appear on the same monitor */
    3397  g_signal_connect(G_OBJECT(cnnwin), "map-event", G_CALLBACK(rcw_map_event_fullscreen), GINT_TO_POINTER(full_screen_target_monitor));
    3398  else
    3399  g_signal_connect(G_OBJECT(cnnwin), "map-event", G_CALLBACK(rcw_map_event), NULL);
    3400  g_signal_connect(G_OBJECT(cnnwin), "unmap-event", G_CALLBACK(rcw_unmap_event), NULL);
    3401 
    3402  gtk_container_set_border_width(GTK_CONTAINER(cnnwin), 0);
    3403  g_signal_connect(G_OBJECT(cnnwin), "toolbar-place", G_CALLBACK(rcw_toolbar_place_signal), NULL);
    3404 
    3405  g_signal_connect(G_OBJECT(cnnwin), "delete-event", G_CALLBACK(rcw_delete_event), NULL);
    3406  g_signal_connect(G_OBJECT(cnnwin), "destroy", G_CALLBACK(rcw_destroy), NULL);
    3407 
    3408  /* Under Xorg focus-in-event and focus-out-event don’t work when keyboard is grabbed
    3409  * via gdk_device_grab. So we listen for window-state-event to detect focus in and focus out.
    3410  * But we must also listen focus-in-event and focus-out-event because some
    3411  * window managers missing _NET_WM_STATE_FOCUSED hint, does not update the window state
    3412  * in case of focus change */
    3413  g_signal_connect(G_OBJECT(cnnwin), "window-state-event", G_CALLBACK(rcw_state_event), NULL);
    3414  g_signal_connect(G_OBJECT(cnnwin), "focus-in-event", G_CALLBACK(rcw_focus_in_event), NULL);
    3415  g_signal_connect(G_OBJECT(cnnwin), "focus-out-event", G_CALLBACK(rcw_focus_out_event), NULL);
    3416 
    3417  g_signal_connect(G_OBJECT(cnnwin), "enter-notify-event", G_CALLBACK(rcw_on_enter_notify_event), NULL);
    3418  g_signal_connect(G_OBJECT(cnnwin), "leave-notify-event", G_CALLBACK(rcw_on_leave_notify_event), NULL);
    3419 
    3420 
    3421  g_signal_connect(G_OBJECT(cnnwin), "configure_event", G_CALLBACK(rcw_on_configure), NULL);
    3422 
    3423  return cnnwin;
    3424 }
    3425 
    3426 /* This function will be called for the first connection. A tag is set to the window so that
    3427  * other connections can determine if whether a new tab should be append to the same window
    3428  */
    3430 {
    3431  TRACE_CALL(__func__);
    3432  gchar *tag;
    3433 
    3434  switch (remmina_pref.tab_mode) {
    3435  case REMMINA_TAB_BY_GROUP:
    3436  tag = g_strdup(remmina_file_get_string(cnnobj->remmina_file, "group"));
    3437  break;
    3439  tag = g_strdup(remmina_file_get_string(cnnobj->remmina_file, "protocol"));
    3440  break;
    3441  default:
    3442  tag = NULL;
    3443  break;
    3444  }
    3445  g_object_set_data_full(G_OBJECT(cnnwin), "tag", tag, (GDestroyNotify)g_free);
    3446 }
    3447 
    3449 {
    3450  TRACE_CALL(__func__);
    3451  RemminaConnectionObject *cnnobj;
    3452 
    3453  if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return;
    3454 
    3455  if (GTK_IS_WIDGET(cnnobj->proto))
    3456  remmina_protocol_widget_grab_focus(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    3457 }
    3458 
    3459 static GtkWidget *nb_find_page_by_cnnobj(GtkNotebook *notebook, RemminaConnectionObject *cnnobj)
    3460 {
    3461  gint i, np;
    3462  GtkWidget *found_page, *pg;
    3463 
    3464  if (cnnobj == NULL || cnnobj->cnnwin == NULL || cnnobj->cnnwin->priv == NULL)
    3465  return NULL;
    3466  found_page = NULL;
    3467  np = gtk_notebook_get_n_pages(cnnobj->cnnwin->priv->notebook);
    3468  for (i = 0; i < np; i++) {
    3469  pg = gtk_notebook_get_nth_page(cnnobj->cnnwin->priv->notebook, i);
    3470  if (g_object_get_data(G_OBJECT(pg), "cnnobj") == cnnobj) {
    3471  found_page = pg;
    3472  break;
    3473  }
    3474  }
    3475 
    3476  return found_page;
    3477 }
    3478 
    3479 
    3481 {
    3482  TRACE_CALL(__func__);
    3483  RemminaConnectionObject *cnnobj = gp->cnnobj;
    3484  GtkWidget *page_to_remove;
    3485 
    3486 
    3487  if (cnnobj && cnnobj->scrolled_container && REMMINA_IS_SCROLLED_VIEWPORT(cnnobj->scrolled_container)) {
    3488  REMMINA_DEBUG("deleting motion");
    3489  remmina_scrolled_viewport_remove_motion(REMMINA_SCROLLED_VIEWPORT(cnnobj->scrolled_container));
    3490  }
    3491 
    3492  if (cnnobj && cnnobj->cnnwin) {
    3493  page_to_remove = nb_find_page_by_cnnobj(cnnobj->cnnwin->priv->notebook, cnnobj);
    3494  if (page_to_remove) {
    3495  gtk_notebook_remove_page(
    3496  cnnobj->cnnwin->priv->notebook,
    3497  gtk_notebook_page_num(cnnobj->cnnwin->priv->notebook, page_to_remove));
    3498  /* Invalidate pointers to objects destroyed by page removal */
    3499  cnnobj->aspectframe = NULL;
    3500  cnnobj->viewport = NULL;
    3501  cnnobj->scrolled_container = NULL;
    3502  /* we cannot invalidate cnnobj->proto, because it can be already been
    3503  * detached from the widget hierarchy in rco_on_disconnect() */
    3504  }
    3505  }
    3506  if (cnnobj) {
    3507  cnnobj->remmina_file = NULL;
    3508  g_free(cnnobj);
    3509  gp->cnnobj = NULL;
    3510  }
    3511 
    3513 }
    3514 
    3516 {
    3517  TRACE_CALL(__func__);
    3518  if (REMMINA_IS_PROTOCOL_WIDGET(cnnobj->proto)) {
    3520  remmina_protocol_widget_close_connection(REMMINA_PROTOCOL_WIDGET(cnnobj->proto));
    3521  else
    3523  }
    3524 }
    3525 
    3527 {
    3528  TRACE_CALL(__func__);
    3529  GtkWidget *hbox;
    3530  GtkWidget *widget;
    3531  GtkWidget *button;
    3532 
    3533  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
    3534  gtk_widget_show(hbox);
    3535 
    3536  widget = gtk_image_new_from_icon_name(remmina_file_get_icon_name(cnnobj->remmina_file), GTK_ICON_SIZE_MENU);
    3537  gtk_widget_show(widget);
    3538  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
    3539 
    3540  widget = gtk_label_new(remmina_file_get_string(cnnobj->remmina_file, "name"));
    3541  gtk_widget_set_valign(widget, GTK_ALIGN_CENTER);
    3542  gtk_widget_set_halign(widget, GTK_ALIGN_CENTER);
    3543 
    3544  gtk_widget_show(widget);
    3545  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
    3546 
    3547  button = gtk_button_new(); // The "x" to close the tab
    3548  gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
    3549 #if GTK_CHECK_VERSION(3, 20, 0)
    3550  gtk_widget_set_focus_on_click(GTK_WIDGET(widget), FALSE);
    3551 #else
    3552  gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
    3553 #endif
    3554  gtk_widget_set_name(button, "remmina-small-button");
    3555  gtk_widget_show(button);
    3556 
    3557  widget = gtk_image_new_from_icon_name("window-close", GTK_ICON_SIZE_MENU);
    3558  gtk_widget_show(widget);
    3559  gtk_container_add(GTK_CONTAINER(button), widget);
    3560 
    3561  gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
    3562 
    3563  g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(rco_on_close_button_clicked), cnnobj);
    3564 
    3565 
    3566  return hbox;
    3567 }
    3568 
    3570 {
    3571  GtkWidget *page;
    3572 
    3573  page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    3574  gtk_widget_set_name(page, "remmina-tab-page");
    3575 
    3576 
    3577  return page;
    3578 }
    3579 
    3581 {
    3582  TRACE_CALL(__func__);
    3583  GtkWidget *page, *label;
    3584  GtkNotebook *notebook;
    3585 
    3586  notebook = cnnwin->priv->notebook;
    3587 
    3588  page = rco_create_tab_page(cnnobj);
    3589  g_object_set_data(G_OBJECT(page), "cnnobj", cnnobj);
    3590  label = rco_create_tab_label(cnnobj);
    3591 
    3592  cnnobj->cnnwin = cnnwin;
    3593 
    3594  gtk_notebook_append_page(notebook, page, label);
    3595  gtk_notebook_set_tab_reorderable(notebook, page, TRUE);
    3596  gtk_notebook_set_tab_detachable(notebook, page, TRUE);
    3597  /* This trick prevents the tab label from being focused */
    3598  gtk_widget_set_can_focus(gtk_widget_get_parent(label), FALSE);
    3599 
    3600  if (gtk_widget_get_parent(cnnobj->scrolled_container) != NULL)
    3601  printf("REMMINA WARNING in %s: scrolled_container already has a parent\n", __func__);
    3602  gtk_box_pack_start(GTK_BOX(page), cnnobj->scrolled_container, TRUE, TRUE, 0);
    3603 
    3604  gtk_widget_show(page);
    3605 
    3606  return page;
    3607 }
    3608 
    3609 
    3611 {
    3612  TRACE_CALL(__func__);
    3613  GtkNotebook *notebook;
    3614  gint n;
    3615 
    3616  notebook = GTK_NOTEBOOK(cnnwin->priv->notebook);
    3617 
    3618  switch (cnnwin->priv->view_mode) {
    3619  case SCROLLED_WINDOW_MODE:
    3620  n = gtk_notebook_get_n_pages(notebook);
    3621  gtk_notebook_set_show_tabs(notebook, remmina_pref.always_show_tab ? TRUE : n > 1);
    3622  gtk_notebook_set_show_border(notebook, remmina_pref.always_show_tab ? TRUE : n > 1);
    3623  break;
    3624  default:
    3625  gtk_notebook_set_show_tabs(notebook, FALSE);
    3626  gtk_notebook_set_show_border(notebook, FALSE);
    3627  break;
    3628  }
    3629 }
    3630 
    3631 static gboolean rcw_on_switch_page_finalsel(gpointer user_data)
    3632 {
    3633  TRACE_CALL(__func__);
    3635  RemminaConnectionObject *cnnobj;
    3636 
    3637  if (!user_data)
    3638  return FALSE;
    3639 
    3640  cnnobj = (RemminaConnectionObject *)user_data;
    3641  if (!cnnobj->cnnwin)
    3642  return FALSE;
    3643 
    3644  priv = cnnobj->cnnwin->priv;
    3645 
    3646  if (GTK_IS_WIDGET(cnnobj->cnnwin)) {
    3647  rcw_floating_toolbar_show(cnnobj->cnnwin, TRUE);
    3648  if (!priv->hidetb_eventsource)
    3649  priv->hidetb_eventsource = g_timeout_add(TB_HIDE_TIME_TIME, (GSourceFunc)
    3651  rco_update_toolbar(cnnobj);
    3652  rcw_grab_focus(cnnobj->cnnwin);
    3653  if (priv->view_mode != SCROLLED_WINDOW_MODE)
    3654  rco_check_resize(cnnobj);
    3655  }
    3656  priv->spf_eventsourceid = 0;
    3657  return FALSE;
    3658 }
    3659 
    3660 static void rcw_on_switch_page(GtkNotebook *notebook, GtkWidget *newpage, guint page_num,
    3661  RemminaConnectionWindow *cnnwin)
    3662 {
    3663  TRACE_CALL(__func__);
    3664  RemminaConnectionWindowPriv *priv = cnnwin->priv;
    3665  RemminaConnectionObject *cnnobj_newpage;
    3666 
    3667  cnnobj_newpage = g_object_get_data(G_OBJECT(newpage), "cnnobj");
    3668  if (priv->spf_eventsourceid)
    3669  g_source_remove(priv->spf_eventsourceid);
    3670  priv->spf_eventsourceid = g_idle_add(rcw_on_switch_page_finalsel, cnnobj_newpage);
    3671 }
    3672 
    3673 static void rcw_on_page_added(GtkNotebook *notebook, GtkWidget *child, guint page_num,
    3674  RemminaConnectionWindow *cnnwin)
    3675 {
    3676  if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(cnnwin->priv->notebook)) > 0)
    3677  rcw_update_notebook(cnnwin);
    3678 }
    3679 
    3680 static void rcw_on_page_removed(GtkNotebook *notebook, GtkWidget *child, guint page_num,
    3681  RemminaConnectionWindow *cnnwin)
    3682 {
    3683  TRACE_CALL(__func__);
    3684 
    3685  if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(cnnwin->priv->notebook)) <= 0)
    3686  gtk_widget_destroy(GTK_WIDGET(cnnwin));
    3687 
    3688 }
    3689 
    3690 static GtkNotebook *
    3691 rcw_on_notebook_create_window(GtkNotebook *notebook, GtkWidget *page, gint x, gint y, gpointer data)
    3692 {
    3693  /* This signal callback is called by GTK when a detachable tab is dropped on the root window
    3694  * or in an existing window */
    3695 
    3696  TRACE_CALL(__func__);
    3697  RemminaConnectionWindow *srccnnwin;
    3698  RemminaConnectionWindow *dstcnnwin;
    3699  RemminaConnectionObject *cnnobj;
    3700  GdkWindow *window;
    3701  gchar *srctag;
    3702  gint width, height;
    3703 
    3704 #if GTK_CHECK_VERSION(3, 20, 0)
    3705  GdkSeat *seat;
    3706 #else
    3707  GdkDeviceManager *manager;
    3708 #endif
    3709  GdkDevice *device = NULL;
    3710 
    3711 #if GTK_CHECK_VERSION(3, 20, 0)
    3712  seat = gdk_display_get_default_seat(gdk_display_get_default());
    3713  device = gdk_seat_get_pointer(seat);
    3714 #else
    3715  manager = gdk_display_get_device_manager(gdk_display_get_default());
    3716  device = gdk_device_manager_get_client_pointer(manager);
    3717 #endif
    3718 
    3719  window = gdk_device_get_window_at_position(device, &x, &y);
    3720  srccnnwin = RCW(gtk_widget_get_toplevel(GTK_WIDGET(notebook)));
    3721  dstcnnwin = RCW(remmina_widget_pool_find_by_window(REMMINA_TYPE_CONNECTION_WINDOW, window));
    3722 
    3723  if (srccnnwin == dstcnnwin)
    3724  return NULL;
    3725 
    3726  if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(srccnnwin->priv->notebook)) == 1 && !dstcnnwin)
    3727  return NULL;
    3728 
    3729  cnnobj = (RemminaConnectionObject *)g_object_get_data(G_OBJECT(page), "cnnobj");
    3730 
    3731  if (!dstcnnwin) {
    3732  /* Drop is directed to a new rcw: create a new scrolled window to accommodate
    3733  * the dropped connectionand move our cnnobj there. Width and
    3734  * height of the new window are cloned from the current window */
    3735  srctag = (gchar *)g_object_get_data(G_OBJECT(srccnnwin), "tag");
    3736  gtk_window_get_size(GTK_WINDOW(srccnnwin), &width, &height);
    3737  dstcnnwin = rcw_create_scrolled(width, height, FALSE); // New dropped window is never maximized
    3738  g_object_set_data_full(G_OBJECT(dstcnnwin), "tag", g_strdup(srctag), (GDestroyNotify)g_free);
    3739  /* when returning, GTK will move the whole tab to the new notebook.
    3740  * Prepare cnnobj to be hosted in the new cnnwin */
    3741  cnnobj->cnnwin = dstcnnwin;
    3742  } else {
    3743  cnnobj->cnnwin = dstcnnwin;
    3744  }
    3745 
    3746  remmina_protocol_widget_set_hostkey_func(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    3747  (RemminaHostkeyFunc)rcw_hostkey_func);
    3748 
    3749  return GTK_NOTEBOOK(cnnobj->cnnwin->priv->notebook);
    3750 }
    3751 
    3752 static GtkNotebook *
    3754 {
    3755  TRACE_CALL(__func__);
    3756  GtkNotebook *notebook;
    3757 
    3758  notebook = GTK_NOTEBOOK(gtk_notebook_new());
    3759 
    3760  gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
    3761  gtk_widget_show(GTK_WIDGET(notebook));
    3762 
    3763  g_signal_connect(G_OBJECT(notebook), "create-window", G_CALLBACK(rcw_on_notebook_create_window), NULL);
    3764  g_signal_connect(G_OBJECT(notebook), "switch-page", G_CALLBACK(rcw_on_switch_page), cnnwin);
    3765  g_signal_connect(G_OBJECT(notebook), "page-added", G_CALLBACK(rcw_on_page_added), cnnwin);
    3766  g_signal_connect(G_OBJECT(notebook), "page-removed", G_CALLBACK(rcw_on_page_removed), cnnwin);
    3767  gtk_widget_set_can_focus(GTK_WIDGET(notebook), FALSE);
    3768 
    3769  return notebook;
    3770 }
    3771 
    3772 /* Create a scrolled toplevel window */
    3773 static RemminaConnectionWindow *rcw_create_scrolled(gint width, gint height, gboolean maximize)
    3774 {
    3775  TRACE_CALL(__func__);
    3776  RemminaConnectionWindow *cnnwin;
    3777  GtkWidget *grid;
    3778  GtkWidget *toolbar;
    3779  GtkNotebook *notebook;
    3780  GtkSettings *settings = gtk_settings_get_default();
    3781 
    3782  cnnwin = rcw_new(FALSE, 0);
    3783  gtk_widget_realize(GTK_WIDGET(cnnwin));
    3784 
    3785  gtk_window_set_default_size(GTK_WINDOW(cnnwin), width, height);
    3786  g_object_set(settings, "gtk-application-prefer-dark-theme", remmina_pref.dark_theme, NULL);
    3787 
    3788  /* Create the toolbar */
    3789  toolbar = rcw_create_toolbar(cnnwin, SCROLLED_WINDOW_MODE);
    3790 
    3791  /* Create the notebook */
    3792  notebook = rcw_create_notebook(cnnwin);
    3793 
    3794  /* Create the grid container for toolbars+notebook and populate it */
    3795  grid = gtk_grid_new();
    3796 
    3797 
    3798  gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(notebook), 0, 0, 1, 1);
    3799 
    3800  gtk_widget_set_hexpand(GTK_WIDGET(notebook), TRUE);
    3801  gtk_widget_set_vexpand(GTK_WIDGET(notebook), TRUE);
    3802 
    3803  rcw_place_toolbar(GTK_TOOLBAR(toolbar), GTK_GRID(grid), GTK_WIDGET(notebook), remmina_pref.toolbar_placement);
    3804 
    3805  gtk_container_add(GTK_CONTAINER(cnnwin), grid);
    3806 
    3807  /* Add drag capabilities to the toolbar */
    3808  gtk_drag_source_set(GTK_WIDGET(toolbar), GDK_BUTTON1_MASK,
    3809  dnd_targets_tb, sizeof dnd_targets_tb / sizeof *dnd_targets_tb, GDK_ACTION_MOVE);
    3810  g_signal_connect_after(GTK_WIDGET(toolbar), "drag-begin", G_CALLBACK(rcw_tb_drag_begin), NULL);
    3811  g_signal_connect(GTK_WIDGET(toolbar), "drag-failed", G_CALLBACK(rcw_tb_drag_failed), cnnwin);
    3812 
    3813  /* Add drop capabilities to the drop/dest target for the toolbar (the notebook) */
    3814  gtk_drag_dest_set(GTK_WIDGET(notebook), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
    3815  dnd_targets_tb, sizeof dnd_targets_tb / sizeof *dnd_targets_tb, GDK_ACTION_MOVE);
    3816  gtk_drag_dest_set_track_motion(GTK_WIDGET(notebook), TRUE);
    3817  g_signal_connect(GTK_WIDGET(notebook), "drag-drop", G_CALLBACK(rcw_tb_drag_drop), cnnwin);
    3818 
    3819  cnnwin->priv->view_mode = SCROLLED_WINDOW_MODE;
    3820  cnnwin->priv->toolbar = toolbar;
    3821  cnnwin->priv->grid = grid;
    3822  cnnwin->priv->notebook = notebook;
    3823  cnnwin->priv->ss_width = width;
    3824  cnnwin->priv->ss_height = height;
    3825  cnnwin->priv->ss_maximized = maximize;
    3826 
    3827  /* The notebook and all its child must be realized now, or a reparent will
    3828  * call unrealize() and will destroy a GtkSocket */
    3829  gtk_widget_show(grid);
    3830  gtk_widget_show(GTK_WIDGET(cnnwin));
    3831  GtkWindowGroup *wingrp = gtk_window_group_new();
    3832 
    3833  gtk_window_group_add_window(wingrp, GTK_WINDOW(cnnwin));
    3834  gtk_window_set_transient_for(GTK_WINDOW(cnnwin), NULL);
    3835 
    3836  if (maximize)
    3837  gtk_window_maximize(GTK_WINDOW(cnnwin));
    3838 
    3839 
    3841 
    3842  return cnnwin;
    3843 }
    3844 
    3846 {
    3847  TRACE_CALL(__func__);
    3848 
    3849  GtkWidget *revealer;
    3851 
    3852  priv = cnnwin->priv;
    3853 
    3854  if (priv->overlay_ftb_overlay != NULL) {
    3855  gtk_widget_destroy(priv->overlay_ftb_overlay);
    3856  priv->overlay_ftb_overlay = NULL;
    3857  priv->revealer = NULL;
    3858  }
    3859 
    3860  rcw_create_floating_toolbar(cnnwin, priv->fss_view_mode);
    3861 
    3862  priv->overlay_ftb_overlay = gtk_event_box_new();
    3863 
    3864  GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    3865 
    3866  gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
    3867 
    3868  GtkWidget *handle = gtk_drawing_area_new();
    3869 
    3870  gtk_widget_set_size_request(handle, 4, 4);
    3871  gtk_widget_set_name(handle, "ftb-handle");
    3872 
    3873  revealer = gtk_revealer_new();
    3874 
    3875  gtk_widget_set_halign(GTK_WIDGET(priv->overlay_ftb_overlay), GTK_ALIGN_CENTER);
    3876 
    3878  gtk_box_pack_start(GTK_BOX(vbox), handle, FALSE, FALSE, 0);
    3879  gtk_box_pack_start(GTK_BOX(vbox), revealer, FALSE, FALSE, 0);
    3880  gtk_revealer_set_transition_type(GTK_REVEALER(revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    3881  gtk_widget_set_valign(GTK_WIDGET(priv->overlay_ftb_overlay), GTK_ALIGN_END);
    3882  } else {
    3883  gtk_box_pack_start(GTK_BOX(vbox), revealer, FALSE, FALSE, 0);
    3884  gtk_box_pack_start(GTK_BOX(vbox), handle, FALSE, FALSE, 0);
    3885  gtk_revealer_set_transition_type(GTK_REVEALER(revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
    3886  gtk_widget_set_valign(GTK_WIDGET(priv->overlay_ftb_overlay), GTK_ALIGN_START);
    3887  }
    3888 
    3889 
    3890  gtk_container_add(GTK_CONTAINER(revealer), priv->floating_toolbar_widget);
    3891  gtk_widget_set_halign(GTK_WIDGET(revealer), GTK_ALIGN_CENTER);
    3892  gtk_widget_set_valign(GTK_WIDGET(revealer), GTK_ALIGN_START);
    3893 
    3894  priv->revealer = revealer;
    3895 
    3896  GtkWidget *fr;
    3897 
    3898  fr = gtk_frame_new(NULL);
    3899  gtk_container_add(GTK_CONTAINER(priv->overlay_ftb_overlay), fr);
    3900  gtk_container_add(GTK_CONTAINER(fr), vbox);
    3901 
    3902  gtk_widget_show(vbox);
    3903  gtk_widget_show(revealer);
    3904  gtk_widget_show(handle);
    3905  gtk_widget_show(priv->overlay_ftb_overlay);
    3906  gtk_widget_show(fr);
    3907 
    3909  gtk_widget_set_name(fr, "ftbbox-lower");
    3910  else
    3911  gtk_widget_set_name(fr, "ftbbox-upper");
    3912 
    3913  gtk_overlay_add_overlay(GTK_OVERLAY(priv->overlay), priv->overlay_ftb_overlay);
    3914 
    3915  rcw_floating_toolbar_show(cnnwin, TRUE);
    3916 
    3917  g_signal_connect(G_OBJECT(priv->overlay_ftb_overlay), "enter-notify-event", G_CALLBACK(rcw_floating_toolbar_on_enter), cnnwin);
    3918  g_signal_connect(G_OBJECT(priv->overlay_ftb_overlay), "leave-notify-event", G_CALLBACK(rcw_floating_toolbar_on_leave), cnnwin);
    3919  g_signal_connect(G_OBJECT(priv->overlay_ftb_overlay), "scroll-event", G_CALLBACK(rcw_floating_toolbar_on_scroll), cnnwin);
    3920  gtk_widget_add_events(
    3921  GTK_WIDGET(priv->overlay_ftb_overlay),
    3922  GDK_SCROLL_MASK
    3923 #if GTK_CHECK_VERSION(3, 4, 0)
    3924  | GDK_SMOOTH_SCROLL_MASK
    3925 #endif
    3926  );
    3927 
    3928  /* Add drag and drop capabilities to the source */
    3929  gtk_drag_source_set(GTK_WIDGET(priv->overlay_ftb_overlay), GDK_BUTTON1_MASK,
    3930  dnd_targets_ftb, sizeof dnd_targets_ftb / sizeof *dnd_targets_ftb, GDK_ACTION_MOVE);
    3931  g_signal_connect_after(GTK_WIDGET(priv->overlay_ftb_overlay), "drag-begin", G_CALLBACK(rcw_ftb_drag_begin), cnnwin);
    3932 
    3934  /* toolbar in fullscreenmode disabled, hide everything */
    3935  gtk_widget_hide(fr);
    3936 }
    3937 
    3938 
    3939 static gboolean rcw_ftb_drag_drop(GtkWidget *widget, GdkDragContext *context,
    3940  gint x, gint y, guint time, RemminaConnectionWindow *cnnwin)
    3941 {
    3942  TRACE_CALL(__func__);
    3943  GtkAllocation wa;
    3944  gint new_floating_toolbar_placement;
    3945  RemminaConnectionObject *cnnobj;
    3946 
    3947  gtk_widget_get_allocation(widget, &wa);
    3948 
    3949  if (y >= wa.height / 2)
    3950  new_floating_toolbar_placement = FLOATING_TOOLBAR_PLACEMENT_BOTTOM;
    3951  else
    3952  new_floating_toolbar_placement = FLOATING_TOOLBAR_PLACEMENT_TOP;
    3953 
    3954  gtk_drag_finish(context, TRUE, TRUE, time);
    3955 
    3956  if (new_floating_toolbar_placement != remmina_pref.floating_toolbar_placement) {
    3957  /* Destroy and recreate the FTB */
    3958  remmina_pref.floating_toolbar_placement = new_floating_toolbar_placement;
    3961  cnnobj = rcw_get_visible_cnnobj(cnnwin);
    3962  if (cnnobj) rco_update_toolbar(cnnobj);
    3963  }
    3964 
    3965  return TRUE;
    3966 }
    3967 
    3968 static void rcw_ftb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
    3969 {
    3970  TRACE_CALL(__func__);
    3971 
    3972  cairo_surface_t *surface;
    3973  cairo_t *cr;
    3974  GtkAllocation wa;
    3975  double dashes[] = { 10 };
    3976 
    3977  gtk_widget_get_allocation(widget, &wa);
    3978 
    3979  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, wa.width, wa.height);
    3980  cr = cairo_create(surface);
    3981  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
    3982  cairo_set_line_width(cr, 2);
    3983  cairo_set_dash(cr, dashes, 1, 0);
    3984  cairo_rectangle(cr, 0, 0, wa.width, wa.height);
    3985  cairo_stroke(cr);
    3986  cairo_destroy(cr);
    3987 
    3988  gtk_drag_set_icon_surface(context, surface);
    3989 }
    3990 
    3991 RemminaConnectionWindow *rcw_create_fullscreen(GtkWindow *old, gint view_mode)
    3992 {
    3993  TRACE_CALL(__func__);
    3994  RemminaConnectionWindow *cnnwin;
    3995  GtkNotebook *notebook;
    3996 
    3997 #if GTK_CHECK_VERSION(3, 22, 0)
    3998  gint n_monitors;
    3999  gint i;
    4000  GdkMonitor *old_monitor;
    4001  GdkDisplay *old_display;
    4002  GdkWindow *old_window;
    4003 #endif
    4004  gint full_screen_target_monitor;
    4005 
    4006  full_screen_target_monitor = FULL_SCREEN_TARGET_MONITOR_UNDEFINED;
    4007  if (old) {
    4008 #if GTK_CHECK_VERSION(3, 22, 0)
    4009  old_window = gtk_widget_get_window(GTK_WIDGET(old));
    4010  old_display = gdk_window_get_display(old_window);
    4011  old_monitor = gdk_display_get_monitor_at_window(old_display, old_window);
    4012  n_monitors = gdk_display_get_n_monitors(old_display);
    4013  for (i = 0; i < n_monitors; ++i) {
    4014  if (gdk_display_get_monitor(old_display, i) == old_monitor) {
    4015  full_screen_target_monitor = i;
    4016  break;
    4017  }
    4018  }
    4019 #else
    4020  full_screen_target_monitor = gdk_screen_get_monitor_at_window(
    4021  gdk_screen_get_default(),
    4022  gtk_widget_get_window(GTK_WIDGET(old)));
    4023 #endif
    4024  }
    4025 
    4026  cnnwin = rcw_new(TRUE, full_screen_target_monitor);
    4027  gtk_widget_set_name(GTK_WIDGET(cnnwin), "remmina-connection-window-fullscreen");
    4028  gtk_widget_realize(GTK_WIDGET(cnnwin));
    4029 
    4030  if (!view_mode)
    4031  view_mode = VIEWPORT_FULLSCREEN_MODE;
    4032 
    4033  notebook = rcw_create_notebook(cnnwin);
    4034 
    4035  cnnwin->priv->overlay = gtk_overlay_new();
    4036  gtk_container_add(GTK_CONTAINER(cnnwin), cnnwin->priv->overlay);
    4037  gtk_container_add(GTK_CONTAINER(cnnwin->priv->overlay), GTK_WIDGET(notebook));
    4038  gtk_widget_show(GTK_WIDGET(cnnwin->priv->overlay));
    4039 
    4040  cnnwin->priv->notebook = notebook;
    4041  cnnwin->priv->view_mode = view_mode;
    4042  cnnwin->priv->fss_view_mode = view_mode;
    4043 
    4044  /* Create the floating toolbar */
    4046  /* Add drag and drop capabilities to the drop/dest target for floating toolbar */
    4047  gtk_drag_dest_set(GTK_WIDGET(cnnwin->priv->overlay), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
    4048  dnd_targets_ftb, sizeof dnd_targets_ftb / sizeof *dnd_targets_ftb, GDK_ACTION_MOVE);
    4049  gtk_drag_dest_set_track_motion(GTK_WIDGET(cnnwin->priv->notebook), TRUE);
    4050  g_signal_connect(GTK_WIDGET(cnnwin->priv->overlay), "drag-drop", G_CALLBACK(rcw_ftb_drag_drop), cnnwin);
    4051 
    4052  gtk_widget_show(GTK_WIDGET(cnnwin));
    4053  GtkWindowGroup *wingrp = gtk_window_group_new();
    4054  gtk_window_group_add_window(wingrp, GTK_WINDOW(cnnwin));
    4055  gtk_window_set_transient_for(GTK_WINDOW(cnnwin), NULL);
    4056 
    4057  return cnnwin;
    4058 }
    4059 
    4060 static gboolean rcw_hostkey_func(RemminaProtocolWidget *gp, guint keyval, gboolean release)
    4061 {
    4062  TRACE_CALL(__func__);
    4063  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4064  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    4065  const RemminaProtocolFeature *feature;
    4066  gint i;
    4067 
    4068  if (release) {
    4069  if (remmina_pref.hostkey && keyval == remmina_pref.hostkey) {
    4070  priv->hostkey_activated = FALSE;
    4071  if (priv->hostkey_used)
    4072  /* hostkey pressed + something else */
    4073  return TRUE;
    4074  }
    4075  /* If hostkey is released without pressing other keys, we should execute the
    4076  * shortcut key which is the same as hostkey. Be default, this is grab/ungrab
    4077  * keyboard */
    4078  else if (priv->hostkey_activated) {
    4079  /* Trap all key releases when hostkey is pressed */
    4080  /* hostkey pressed + something else */
    4081  return TRUE;
    4082  } else {
    4083  /* Any key pressed, no hostkey */
    4084  return FALSE;
    4085  }
    4086  } else if (remmina_pref.hostkey && keyval == remmina_pref.hostkey) {
    4088  priv->hostkey_activated = TRUE;
    4089  priv->hostkey_used = FALSE;
    4090  return TRUE;
    4091  } else if (!priv->hostkey_activated) {
    4092  /* Any key pressed, no hostkey */
    4093  return FALSE;
    4094  }
    4095 
    4096  priv->hostkey_used = TRUE;
    4097  keyval = gdk_keyval_to_lower(keyval);
    4098  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down
    4099  || keyval == GDK_KEY_Left || keyval == GDK_KEY_Right) {
    4100  GtkAdjustment *adjust;
    4101  int pos;
    4102 
    4103  if (cnnobj->connected && GTK_IS_SCROLLED_WINDOW(cnnobj->scrolled_container)) {
    4104  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down)
    4105  adjust = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container));
    4106  else
    4107  adjust = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container));
    4108 
    4109  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Left)
    4110  pos = 0;
    4111  else
    4112  pos = gtk_adjustment_get_upper(adjust);
    4113 
    4114  gtk_adjustment_set_value(adjust, pos);
    4115  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down)
    4116  gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container), adjust);
    4117  else
    4118  gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(cnnobj->scrolled_container), adjust);
    4119  } else if (REMMINA_IS_SCROLLED_VIEWPORT(cnnobj->scrolled_container)) {
    4121  GtkWidget *child;
    4122  GdkWindow *gsvwin;
    4123  gint sz;
    4124  GtkAdjustment *adj;
    4125  gdouble value;
    4126 
    4127  if (!GTK_IS_BIN(cnnobj->scrolled_container))
    4128  return FALSE;
    4129 
    4130  gsv = REMMINA_SCROLLED_VIEWPORT(cnnobj->scrolled_container);
    4131  child = gtk_bin_get_child(GTK_BIN(gsv));
    4132  if (!GTK_IS_VIEWPORT(child))
    4133  return FALSE;
    4134 
    4135  gsvwin = gtk_widget_get_window(GTK_WIDGET(gsv));
    4136  if (!gsv)
    4137  return FALSE;
    4138 
    4139  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down) {
    4140  sz = gdk_window_get_height(gsvwin) + 2; // Add 2px of black scroll border
    4141  adj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(child));
    4142  } else {
    4143  sz = gdk_window_get_width(gsvwin) + 2; // Add 2px of black scroll border
    4144  adj = gtk_scrollable_get_hadjustment(GTK_SCROLLABLE(child));
    4145  }
    4146 
    4147  if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Left)
    4148  value = 0;
    4149  else
    4150  value = gtk_adjustment_get_upper(GTK_ADJUSTMENT(adj)) - (gdouble)sz + 2.0;
    4151 
    4152  gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), value);
    4153  }
    4154  }
    4155 
    4156  if (keyval == remmina_pref.shortcutkey_fullscreen && !extrahardening) {
    4157  switch (priv->view_mode) {
    4158  case SCROLLED_WINDOW_MODE:
    4159  rcw_switch_viewmode(cnnobj->cnnwin, priv->fss_view_mode);
    4160  break;
    4164  break;
    4165  default:
    4166  break;
    4167  }
    4168  } else if (keyval == remmina_pref.shortcutkey_autofit && !extrahardening) {
    4169  if (priv->toolitem_autofit && gtk_widget_is_sensitive(GTK_WIDGET(priv->toolitem_autofit)))
    4170  rcw_toolbar_autofit(GTK_TOOL_ITEM(gp), cnnobj->cnnwin);
    4171  } else if (keyval == remmina_pref.shortcutkey_nexttab && !extrahardening) {
    4172  i = gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->notebook)) + 1;
    4173  if (i >= gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook)))
    4174  i = 0;
    4175  gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->notebook), i);
    4176  } else if (keyval == remmina_pref.shortcutkey_prevtab && !extrahardening) {
    4177  i = gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->notebook)) - 1;
    4178  if (i < 0)
    4179  i = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->notebook)) - 1;
    4180  gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->notebook), i);
    4181  } else if (keyval == remmina_pref.shortcutkey_scale && !extrahardening) {
    4182  if (gtk_widget_is_sensitive(GTK_WIDGET(priv->toolitem_scale))) {
    4183  gtk_toggle_tool_button_set_active(
    4184  GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_scale),
    4185  !gtk_toggle_tool_button_get_active(
    4186  GTK_TOGGLE_TOOL_BUTTON(
    4187  priv->toolitem_scale)));
    4188  }
    4189  } else if (keyval == remmina_pref.shortcutkey_grab && !extrahardening) {
    4190  gtk_toggle_tool_button_set_active(
    4191  GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_grab),
    4192  !gtk_toggle_tool_button_get_active(
    4193  GTK_TOGGLE_TOOL_BUTTON(
    4194  priv->toolitem_grab)));
    4195  } else if (keyval == remmina_pref.shortcutkey_minimize && !extrahardening) {
    4196  rcw_toolbar_minimize(GTK_TOOL_ITEM(gp),
    4197  cnnobj->cnnwin);
    4198  } else if (keyval == remmina_pref.shortcutkey_viewonly && !extrahardening) {
    4199  remmina_file_set_int(cnnobj->remmina_file, "viewonly",
    4200  (remmina_file_get_int(cnnobj->remmina_file, "viewonly", 0)
    4201  == 0) ? 1 : 0);
    4202  } else if (keyval == remmina_pref.shortcutkey_screenshot && !extrahardening) {
    4203  rcw_toolbar_screenshot(GTK_TOOL_ITEM(gp),
    4204  cnnobj->cnnwin);
    4205  } else if (keyval == remmina_pref.shortcutkey_disconnect && !extrahardening) {
    4207  } else if (keyval == remmina_pref.shortcutkey_toolbar && !extrahardening) {
    4208  if (priv->view_mode == SCROLLED_WINDOW_MODE) {
    4209  remmina_pref.hide_connection_toolbar =
    4210  !remmina_pref.hide_connection_toolbar;
    4212  }
    4213  } else {
    4214  for (feature =
    4216  REMMINA_PROTOCOL_WIDGET(
    4217  cnnobj->proto));
    4218  feature && feature->type;
    4219  feature++) {
    4220  if (feature->type
    4222  && GPOINTER_TO_UINT(
    4223  feature->opt3)
    4224  == keyval) {
    4226  REMMINA_PROTOCOL_WIDGET(
    4227  cnnobj->proto),
    4228  feature);
    4229  break;
    4230  }
    4231  }
    4232  }
    4233  /* If a keypress makes the current cnnobj to move to another window,
    4234  * priv is now invalid. So we can no longer use priv here */
    4235  cnnobj->cnnwin->priv->hostkey_activated = FALSE;
    4236 
    4237  /* Trap all keypresses when hostkey is pressed */
    4238  return TRUE;
    4239 }
    4240 
    4242 {
    4243  TRACE_CALL(__func__);
    4244  const gchar *tag;
    4245 
    4246  switch (remmina_pref.tab_mode) {
    4247  case REMMINA_TAB_BY_GROUP:
    4248  tag = remmina_file_get_string(remminafile, "group");
    4249  break;
    4251  tag = remmina_file_get_string(remminafile, "protocol");
    4252  break;
    4253  case REMMINA_TAB_ALL:
    4254  tag = NULL;
    4255  break;
    4256  case REMMINA_TAB_NONE:
    4257  default:
    4258  return NULL;
    4259  }
    4260  return RCW(remmina_widget_pool_find(REMMINA_TYPE_CONNECTION_WINDOW, tag));
    4261 }
    4262 
    4263 gboolean rcw_delayed_window_present(gpointer user_data)
    4264 {
    4265  RemminaConnectionWindow *cnnwin = (RemminaConnectionWindow *)user_data;
    4266 
    4267  if (cnnwin) {
    4268  gtk_window_present_with_time(GTK_WINDOW(cnnwin), (guint32)(g_get_monotonic_time() / 1000));
    4269  rcw_grab_focus(cnnwin);
    4270  }
    4271  cnnwin->priv->dwp_eventsourceid = 0;
    4272  return G_SOURCE_REMOVE;
    4273 }
    4274 
    4276 {
    4277  TRACE_CALL(__func__);
    4278 
    4279  REMMINA_DEBUG("Connect signal emitted");
    4280 
    4281  /* This signal handler is called by a plugin when it’s correctly connected
    4282  * (and authenticated) */
    4283 
    4284  cnnobj->connected = TRUE;
    4285 
    4286  remmina_protocol_widget_set_hostkey_func(REMMINA_PROTOCOL_WIDGET(cnnobj->proto),
    4287  (RemminaHostkeyFunc)rcw_hostkey_func);
    4288 
    4292  if (remmina_file_get_filename(cnnobj->remmina_file) == NULL)
    4294  remmina_file_get_string(cnnobj->remmina_file, "server"));
    4295  REMMINA_DEBUG("We save the last successful connection date");
    4296  //remmina_file_set_string(cnnobj->remmina_file, "last_success", last_success);
    4298  //REMMINA_DEBUG("Last connection made on %s.", last_success);
    4299 
    4300  REMMINA_DEBUG("Saving credentials");
    4301  /* Save credentials */
    4303 
    4304  if (cnnobj->cnnwin->priv->floating_toolbar_widget)
    4305  gtk_widget_show(cnnobj->cnnwin->priv->floating_toolbar_widget);
    4306 
    4307  rco_update_toolbar(cnnobj);
    4308 
    4309  REMMINA_DEBUG("Trying to present the window");
    4310  /* Try to present window */
    4311  cnnobj->cnnwin->priv->dwp_eventsourceid = g_timeout_add(200, rcw_delayed_window_present, (gpointer)cnnobj->cnnwin);
    4312 }
    4313 
    4314 static void cb_lasterror_confirmed(void *cbdata, int btn)
    4315 {
    4316  TRACE_CALL(__func__);
    4318 }
    4319 
    4321 {
    4322  TRACE_CALL(__func__);
    4323  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4324  RemminaConnectionWindowPriv *priv = cnnobj->cnnwin->priv;
    4325  GtkWidget *pparent;
    4326 
    4327  REMMINA_DEBUG("Disconnect signal received on RemminaProtocolWidget");
    4328  /* Detach the protocol widget from the notebook now, or we risk that a
    4329  * window delete will destroy cnnobj->proto before we complete disconnection.
    4330  */
    4331  pparent = gtk_widget_get_parent(cnnobj->proto);
    4332  if (pparent != NULL) {
    4333  g_object_ref(cnnobj->proto);
    4334  gtk_container_remove(GTK_CONTAINER(pparent), cnnobj->proto);
    4335  }
    4336 
    4337  cnnobj->connected = FALSE;
    4338 
    4339  if (remmina_pref.save_view_mode) {
    4340  if (cnnobj->cnnwin)
    4341  remmina_file_set_int(cnnobj->remmina_file, "viewmode", cnnobj->cnnwin->priv->view_mode);
    4343  }
    4344 
    4345  rcw_kp_ungrab(cnnobj->cnnwin);
    4346  gtk_toggle_tool_button_set_active(
    4347  GTK_TOGGLE_TOOL_BUTTON(priv->toolitem_grab),
    4348  FALSE);
    4349 
    4351  /* We cannot close window immediately, but we must show a message panel */
    4352  RemminaMessagePanel *mp;
    4353  /* Destroy scrolled_container (and viewport) and all its children the plugin created
    4354  * on it, so they will not receive GUI signals */
    4355  if (cnnobj->scrolled_container) {
    4356  gtk_widget_destroy(cnnobj->scrolled_container);
    4357  cnnobj->scrolled_container = NULL;
    4358  }
    4359  cnnobj->viewport = NULL;
    4362  rco_show_message_panel(gp->cnnobj, mp);
    4363  REMMINA_DEBUG("Could not disconnect");
    4364  } else {
    4365  rco_closewin(gp);
    4366  REMMINA_DEBUG("Disconnected");
    4367  }
    4368 }
    4369 
    4371 {
    4372  TRACE_CALL(__func__);
    4373  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4374 
    4375  if (cnnobj && cnnobj->cnnwin && cnnobj->cnnwin->priv->view_mode != SCROLLED_WINDOW_MODE)
    4376  rco_check_resize(cnnobj);
    4377 }
    4378 
    4380 {
    4381  TRACE_CALL(__func__);
    4382  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4383 
    4385 }
    4386 
    4388 {
    4389  TRACE_CALL(__func__);
    4390  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4391 
    4392  cnnobj->dynres_unlocked = FALSE;
    4393  rco_update_toolbar(cnnobj);
    4394 }
    4395 
    4397 {
    4398  TRACE_CALL(__func__);
    4399  RemminaConnectionObject *cnnobj = gp->cnnobj;
    4400 
    4401  cnnobj->dynres_unlocked = TRUE;
    4402  rco_update_toolbar(cnnobj);
    4403 }
    4404 
    4405 gboolean rcw_open_from_filename(const gchar *filename)
    4406 {
    4407  TRACE_CALL(__func__);
    4408  RemminaFile *remminafile;
    4409  GtkWidget *dialog;
    4410 
    4411  remminafile = remmina_file_manager_load_file(filename);
    4412  if (remminafile) {
    4413  if (remmina_file_get_int (remminafile, "profile-lock", FALSE)
    4415  return FALSE;
    4416  rcw_open_from_file(remminafile);
    4417  return TRUE;
    4418  } else {
    4419  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
    4420  _("The file “%s” is corrupted, unreadable, or could not be found."), filename);
    4421  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
    4422  gtk_widget_show(dialog);
    4424  return FALSE;
    4425  }
    4426 }
    4427 
    4428 static gboolean open_connection_last_stage(gpointer user_data)
    4429 {
    4430  RemminaProtocolWidget *gp = (RemminaProtocolWidget *)user_data;
    4431 
    4432  /* Now we have an allocated size for our RemminaProtocolWidget. We can proceed with the connection */
    4435  rco_check_resize(gp->cnnobj);
    4436 
    4437  return FALSE;
    4438 }
    4439 
    4440 static void rpw_size_allocated_on_connection(GtkWidget *w, GdkRectangle *allocation, gpointer user_data)
    4441 {
    4443 
    4444  /* Disconnect signal handler to avoid to be called again after a normal resize */
    4445  g_signal_handler_disconnect(w, gp->cnnobj->deferred_open_size_allocate_handler);
    4446 
    4447  /* Allow extra 100 ms for size allocation (do we really need it?) */
    4448  g_timeout_add(100, open_connection_last_stage, gp);
    4449 
    4450  return;
    4451 }
    4452 
    4454 {
    4455  TRACE_CALL(__func__);
    4456  rcw_open_from_file_full(remminafile, NULL, NULL, NULL);
    4457 }
    4458 
    4459 static void set_label_selectable(gpointer data, gpointer user_data)
    4460 {
    4461  TRACE_CALL(__func__);
    4462  GtkWidget *widget = GTK_WIDGET(data);
    4463 
    4464  if (GTK_IS_LABEL(widget))
    4465  gtk_label_set_selectable(GTK_LABEL(widget), TRUE);
    4466 }
    4467 
    4475 };
    4476 
    4481 static void rcw_gtksocket_not_available_dialog_response(GtkDialog * self,
    4482  gint response_id,
    4483  RemminaConnectionObject * cnnobj)
    4484 {
    4485  TRACE_CALL(__func__);
    4486 
    4487  GError *error = NULL;
    4488 
    4489  if (response_id == GTKSOCKET_NOT_AVAIL_RESPONSE_OPEN_BROWSER) {
    4490  gtk_show_uri_on_window(
    4491  NULL,
    4492  // TRANSLATORS: This should be a link to the Remmina wiki page:
    4493  // TRANSLATORS: 'GtkSocket feature is not available'.
    4494  _("https://gitlab.com/Remmina/Remmina/-/wikis/GtkSocket-feature-is-not-available-in-a-Wayland-session"),
    4495  GDK_CURRENT_TIME, &error
    4496  );
    4497  }
    4498 
    4499  // Close the current page since it's useless without GtkSocket.
    4500  // The user would need to manually click the close button.
    4501  if (cnnobj) rco_disconnect_current_page(cnnobj);
    4502 
    4503  gtk_widget_destroy(GTK_WIDGET(self));
    4504 }
    4505 
    4506 GtkWidget *rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
    4507 {
    4508  TRACE_CALL(__func__);
    4509  RemminaConnectionObject *cnnobj;
    4510 
    4511  gint ret;
    4512  GtkWidget *dialog;
    4513  GtkWidget *newpage;
    4514  gint width, height;
    4515  gboolean maximize;
    4516  gint view_mode;
    4517  const gchar *msg;
    4518  RemminaScaleMode scalemode;
    4519 
    4520  if (disconnect_cb) {
    4521  g_print("disconnect_cb is deprecated inside rcw_open_from_file_full() and should be null\n");
    4522  return NULL;
    4523  }
    4524 
    4525 
    4526  /* Create the RemminaConnectionObject */
    4527  cnnobj = g_new0(RemminaConnectionObject, 1);
    4528  cnnobj->remmina_file = remminafile;
    4529 
    4530  /* Create the RemminaProtocolWidget */
    4531  cnnobj->proto = remmina_protocol_widget_new();
    4532  remmina_protocol_widget_setup((RemminaProtocolWidget *)cnnobj->proto, remminafile, cnnobj);
    4534  GtkWindow *wparent;
    4535  wparent = remmina_main_get_window();
    4537  dialog = gtk_message_dialog_new(wparent, GTK_DIALOG_DESTROY_WITH_PARENT,
    4538  GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg);
    4539  gtk_dialog_run(GTK_DIALOG(dialog));
    4540  gtk_widget_destroy(dialog);
    4541  /* We should destroy cnnobj->proto and cnnobj now… TODO: Fix this leak */
    4542  return NULL;
    4543  }
    4544 
    4545 
    4546 
    4547  /* Set a name for the widget, for CSS selector */
    4548  gtk_widget_set_name(GTK_WIDGET(cnnobj->proto), "remmina-protocol-widget");
    4549 
    4550  gtk_widget_set_halign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    4551  gtk_widget_set_valign(GTK_WIDGET(cnnobj->proto), GTK_ALIGN_FILL);
    4552 
    4553  if (data)
    4554  g_object_set_data(G_OBJECT(cnnobj->proto), "user-data", data);
    4555 
    4556  view_mode = remmina_file_get_int(cnnobj->remmina_file, "viewmode", 0);
    4557  if (kioskmode)
    4558  view_mode = VIEWPORT_FULLSCREEN_MODE;
    4559  gint ismultimon = remmina_file_get_int(cnnobj->remmina_file, "multimon", 0);
    4560 
    4561  if (ismultimon)
    4562  view_mode = VIEWPORT_FULLSCREEN_MODE;
    4563 
    4564  if (fullscreen)
    4565  view_mode = VIEWPORT_FULLSCREEN_MODE;
    4566 
    4567  /* Create the viewport to make the RemminaProtocolWidget scrollable */
    4568  cnnobj->viewport = gtk_viewport_new(NULL, NULL);
    4569  gtk_widget_set_name(cnnobj->viewport, "remmina-cw-viewport");
    4570  gtk_widget_show(cnnobj->viewport);
    4571  gtk_container_set_border_width(GTK_CONTAINER(cnnobj->viewport), 0);
    4572  gtk_viewport_set_shadow_type(GTK_VIEWPORT(cnnobj->viewport), GTK_SHADOW_NONE);
    4573 
    4574  /* Create the scrolled container */
    4575  scalemode = get_current_allowed_scale_mode(cnnobj, NULL, NULL);
    4576  cnnobj->scrolled_container = rco_create_scrolled_container(scalemode, view_mode);
    4577 
    4578  gtk_container_add(GTK_CONTAINER(cnnobj->scrolled_container), cnnobj->viewport);
    4579 
    4580  /* Determine whether the plugin can scale or not. If the plugin can scale and we do
    4581  * not want to expand, then we add a GtkAspectFrame to maintain aspect ratio during scaling */
    4583  remmina_file_get_string(remminafile, "protocol"),
    4585 
    4586  cnnobj->aspectframe = NULL;
    4587  gtk_container_add(GTK_CONTAINER(cnnobj->viewport), cnnobj->proto);
    4588 
    4589  /* Determine whether this connection will be put on a new window
    4590  * or in an existing one */
    4591  cnnobj->cnnwin = rcw_find(remminafile);
    4592  if (!cnnobj->cnnwin) {
    4593  /* Connection goes on a new toplevel window */
    4594  switch (view_mode) {
    4597  cnnobj->cnnwin = rcw_create_fullscreen(NULL, view_mode);
    4598  break;
    4599  case SCROLLED_WINDOW_MODE:
    4600  default:
    4601  width = remmina_file_get_int(cnnobj->remmina_file, "window_width", 640);
    4602  height = remmina_file_get_int(cnnobj->remmina_file, "window_height", 480);
    4603  maximize = remmina_file_get_int(cnnobj->remmina_file, "window_maximize", FALSE) ? TRUE : FALSE;
    4604  cnnobj->cnnwin = rcw_create_scrolled(width, height, maximize);
    4605  break;
    4606  }
    4607  rcw_update_tag(cnnobj->cnnwin, cnnobj);
    4608  rcw_append_new_page(cnnobj->cnnwin, cnnobj);
    4609  } else {
    4610  newpage = rcw_append_new_page(cnnobj->cnnwin, cnnobj);
    4611  gtk_window_present(GTK_WINDOW(cnnobj->cnnwin));
    4612  nb_set_current_page(cnnobj->cnnwin->priv->notebook, newpage);
    4613  }
    4614 
    4615  // Do not call remmina_protocol_widget_update_alignment(cnnobj); here or cnnobj->proto will not fill its parent size
    4616  // and remmina_protocol_widget_update_remote_resolution() cannot autodetect available space
    4617 
    4618  gtk_widget_show(cnnobj->proto);
    4619  g_signal_connect(G_OBJECT(cnnobj->proto), "connect", G_CALLBACK(rco_on_connect), cnnobj);
    4620  g_signal_connect(G_OBJECT(cnnobj->proto), "disconnect", G_CALLBACK(rco_on_disconnect), NULL);
    4621  g_signal_connect(G_OBJECT(cnnobj->proto), "desktop-resize", G_CALLBACK(rco_on_desktop_resize), NULL);
    4622  g_signal_connect(G_OBJECT(cnnobj->proto), "update-align", G_CALLBACK(rco_on_update_align), NULL);
    4623  g_signal_connect(G_OBJECT(cnnobj->proto), "lock-dynres", G_CALLBACK(rco_on_lock_dynres), NULL);
    4624  g_signal_connect(G_OBJECT(cnnobj->proto), "unlock-dynres", G_CALLBACK(rco_on_unlock_dynres), NULL);
    4625  g_signal_connect(G_OBJECT(cnnobj->proto), "enter-notify-event", G_CALLBACK(rco_enter_protocol_widget), cnnobj);
    4626  g_signal_connect(G_OBJECT(cnnobj->proto), "leave-notify-event", G_CALLBACK(rco_leave_protocol_widget), cnnobj);
    4627 
    4628  if (!remmina_pref.save_view_mode)
    4629  remmina_file_set_int(cnnobj->remmina_file, "viewmode", remmina_pref.default_mode);
    4630 
    4631 
    4632  /* If it is a GtkSocket plugin and X11 is not available, we inform the
    4633  * user and close the connection */
    4635  remmina_file_get_string(remminafile, "protocol"),
    4637  if (ret && !remmina_gtksocket_available()) {
    4638  gchar *title = _("Warning: This plugin requires GtkSocket, but this "
    4639  "feature is unavailable in a Wayland session.");
    4640 
    4641  gchar *err_msg =
    4642  // TRANSLATORS: This should be a link to the Remmina wiki page:
    4643  // 'GtkSocket feature is not available'.
    4644  _("Plugins relying on GtkSocket can't run in a "
    4645  "Wayland session.\nFor more info and a possible "
    4646  "workaround, please visit the Remmina wiki at:\n\n"
    4647  "https://gitlab.com/Remmina/Remmina/-/wikis/GtkSocket-feature-is-not-available-in-a-Wayland-session");
    4648 
    4649  dialog = gtk_message_dialog_new(
    4650  GTK_WINDOW(cnnobj->cnnwin),
    4651  GTK_DIALOG_MODAL,
    4652  GTK_MESSAGE_WARNING,
    4653  GTK_BUTTONS_OK,
    4654  "%s", title);
    4655 
    4656  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s",
    4657  err_msg);
    4658  gtk_dialog_add_button(GTK_DIALOG(dialog), _("Open in web browser"),
    4660 
    4661  REMMINA_CRITICAL(g_strdup_printf("%s\n%s", title, err_msg));
    4662 
    4663  g_signal_connect(G_OBJECT(dialog),
    4664  "response",
    4666  cnnobj);
    4667 
    4668  // Make Text selectable. Usefull because of the link in the text.
    4669  GtkWidget *area = gtk_message_dialog_get_message_area(
    4670  GTK_MESSAGE_DIALOG(dialog));
    4671  GtkContainer *box = (GtkContainer *)area;
    4672 
    4673  GList *children = gtk_container_get_children(box);
    4674  g_list_foreach(children, set_label_selectable, NULL);
    4675  g_list_free(children);
    4676 
    4677  gtk_widget_show(dialog);
    4678 
    4679  return NULL; /* Should we destroy something before returning? */
    4680  }
    4681 
    4682  if (cnnobj->cnnwin->priv->floating_toolbar_widget)
    4683  gtk_widget_show(cnnobj->cnnwin->priv->floating_toolbar_widget);
    4684 
    4686  printf("OK, an error occurred in initializing the protocol plugin before connecting. The error is %s.\n"
    4687  "TODO: Put this string as an error to show", remmina_protocol_widget_get_error_message((RemminaProtocolWidget *)cnnobj->proto));
    4688  return cnnobj->proto;
    4689  }
    4690 
    4691 
    4692  /* GTK window setup is done here, and we are almost ready to call remmina_protocol_widget_open_connection().
    4693  * But size has not yet been allocated by GTK
    4694  * to the widgets. If we are in RES_USE_INITIAL_WINDOW_SIZE resolution mode or scale is REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES,
    4695  * we should wait for a size allocation from GTK for cnnobj->proto
    4696  * before connecting */
    4697 
    4698  cnnobj->deferred_open_size_allocate_handler = g_signal_connect(G_OBJECT(cnnobj->proto), "size-allocate", G_CALLBACK(rpw_size_allocated_on_connection), NULL);
    4699 
    4700  return cnnobj->proto;
    4701 }
    4702 
    4704 {
    4705  return &cnnobj->cnnwin->window;
    4706 }
    4708 {
    4709  return cnnobj->viewport;
    4710 }
    4711 
    4713 {
    4714  TRACE_CALL(__func__);
    4715  cnnwin->priv->on_delete_confirm_mode = mode;
    4716 }
    4717 
    4722 void rco_destroy_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    4723 {
    4724  TRACE_CALL(__func__);
    4725  GList *childs, *cc;
    4726  RemminaMessagePanel *lastPanel;
    4727  gboolean was_visible;
    4728  GtkWidget *page;
    4729 
    4730  page = nb_find_page_by_cnnobj(cnnobj->cnnwin->priv->notebook, cnnobj);
    4731  childs = gtk_container_get_children(GTK_CONTAINER(page));
    4732  cc = g_list_first(childs);
    4733  while (cc != NULL) {
    4734  if ((RemminaMessagePanel *)cc->data == mp)
    4735  break;
    4736  cc = g_list_next(cc);
    4737  }
    4738  g_list_free(childs);
    4739 
    4740  if (cc == NULL) {
    4741  printf("Remmina: Warning. There was a request to destroy a RemminaMessagePanel that is not on the page\n");
    4742  return;
    4743  }
    4744  was_visible = gtk_widget_is_visible(GTK_WIDGET(mp));
    4745  gtk_widget_destroy(GTK_WIDGET(mp));
    4746 
    4747  /* And now, show the last remaining message panel, if needed */
    4748  if (was_visible) {
    4749  childs = gtk_container_get_children(GTK_CONTAINER(page));
    4750  cc = g_list_first(childs);
    4751  lastPanel = NULL;
    4752  while (cc != NULL) {
    4753  if (G_TYPE_CHECK_INSTANCE_TYPE(cc->data, REMMINA_TYPE_MESSAGE_PANEL))
    4754  lastPanel = (RemminaMessagePanel *)cc->data;
    4755  cc = g_list_next(cc);
    4756  }
    4757  g_list_free(childs);
    4758  if (lastPanel)
    4759  gtk_widget_show(GTK_WIDGET(lastPanel));
    4760  }
    4761 }
    4762 
    4769 void rco_show_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    4770 {
    4771  TRACE_CALL(__func__);
    4772  GList *childs, *cc;
    4773  GtkWidget *page;
    4774 
    4775  /* Hides all RemminaMessagePanels childs of cnnobj->page */
    4776  page = nb_find_page_by_cnnobj(cnnobj->cnnwin->priv->notebook, cnnobj);
    4777  childs = gtk_container_get_children(GTK_CONTAINER(page));
    4778  cc = g_list_first(childs);
    4779  while (cc != NULL) {
    4780  if (G_TYPE_CHECK_INSTANCE_TYPE(cc->data, REMMINA_TYPE_MESSAGE_PANEL))
    4781  gtk_widget_hide(GTK_WIDGET(cc->data));
    4782  cc = g_list_next(cc);
    4783  }
    4784  g_list_free(childs);
    4785 
    4786  /* Add the new message panel at the top of cnnobj->page */
    4787  gtk_box_pack_start(GTK_BOX(page), GTK_WIDGET(mp), FALSE, FALSE, 0);
    4788  gtk_box_reorder_child(GTK_BOX(page), GTK_WIDGET(mp), 0);
    4789 
    4790  /* Show the message panel */
    4791  gtk_widget_show_all(GTK_WIDGET(mp));
    4792 
    4793  /* Focus the correct field of the RemminaMessagePanel */
    4795 }
    static RemminaConnectionWindow * rcw_find(RemminaFile *remminafile)
    Definition: rcw.c:4241
    -
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    guint shortcutkey_fullscreen
    Definition: remmina_pref.h:175
    static void rco_update_toolbar(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:2635
    -
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    +
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    gulong deferred_open_size_allocate_handler
    Definition: rcw.c:177
    gint floating_toolbar_placement
    Definition: remmina_pref.h:224
    @@ -98,8 +98,8 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static void rcw_focus_in(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:2948
    static void rcw_init(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:3223
    static RemminaScaleMode get_current_allowed_scale_mode(RemminaConnectionObject *cnnobj, gboolean *dynres_avail, gboolean *scale_avail)
    Definition: rcw.c:391
    -
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    -
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    +
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    guint shortcutkey_minimize
    Definition: remmina_pref.h:185
    @@ -110,7 +110,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    const gchar * grab_color
    Definition: remmina_pref.h:159
    static void rcw_tb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
    Definition: rcw.c:828
    -
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    static void rcw_toolbar_multi_monitor_mode(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1722
    static void rco_call_protocol_feature_check(GtkMenuItem *menuitem, RemminaConnectionObject *cnnobj)
    Definition: rcw.c:1816
    @@ -118,11 +118,11 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    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:3660
    GtkWindow * remmina_main_get_window()
    -
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    static gboolean rcw_hostkey_func(RemminaProtocolWidget *gp, guint keyval, gboolean release)
    Definition: rcw.c:4060
    void remmina_scrolled_viewport_remove_motion(RemminaScrolledViewport *gsv)
    -
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    static void rcw_toolbar_preferences(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1895
    static void nb_set_current_page(GtkNotebook *notebook, GtkWidget *page)
    Definition: rcw.c:1221
    @@ -140,12 +140,12 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    guint shortcutkey_prevtab
    Definition: remmina_pref.h:177
    static RemminaConnectionWindow * rcw_create_scrolled(gint width, gint height, gboolean maximize)
    Definition: rcw.c:3773
    -
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    static void rcw_toolbar_dynres(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1678
    void rco_show_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    Each cnnobj->page can have more than one RemminaMessagePanel, but 0 or 1 are visible.
    Definition: rcw.c:4769
    static void rcw_toolbar_grab(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:2299
    -
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    gboolean plugin_can_scale
    Definition: rcw.c:172
    GtkWidget * rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
    Definition: rcw.c:4506
    @@ -162,7 +162,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    void rcw_toolbar_preferences_radio(RemminaConnectionObject *cnnobj, RemminaFile *remminafile, GtkWidget *menu, const RemminaProtocolFeature *feature, const gchar *domain, gboolean enabled)
    Definition: rcw.c:1837
    -
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    +
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    static void rcw_create_overlay_ftb_overlay(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:3845
    gboolean rcw_delete(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:648
    @@ -181,19 +181,19 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static void rcw_place_toolbar(GtkToolbar *toolbar, GtkGrid *grid, GtkWidget *sibling, int toolbar_placement)
    Definition: rcw.c:2601
    guint shortcutkey_autofit
    Definition: remmina_pref.h:176
    static void rcw_toolbar_preferences_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1758
    -
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    +
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    static GtkWidget * rco_create_tab_label(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:3526
    void rco_destroy_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    Deletes a RemminaMessagePanel from the current cnnobj and if it was visible, make visible the last re...
    Definition: rcw.c:4722
    -
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    +
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    static void nb_migrate_message_panels(GtkWidget *frompage, GtkWidget *topage)
    Definition: rcw.c:1234
    static void rco_viewport_fullscreen_mode(GtkWidget *widget, RemminaConnectionObject *cnnobj)
    Definition: rcw.c:1387
    -
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    -
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    +
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    static void rcw_update_pin(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:3125
    void rcw_toolbar_fullscreen_option(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1421
    -
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    +
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    void rco_on_connect(RemminaProtocolWidget *gp, RemminaConnectionObject *cnnobj)
    Definition: rcw.c:4275
    GtkWidget * proto
    Definition: rcw.c:166
    static GtkWidget * nb_find_page_by_cnnobj(GtkNotebook *notebook, RemminaConnectionObject *cnnobj)
    Definition: rcw.c:3459
    @@ -216,7 +216,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    gchar * remmina_pref_get_value(const gchar *key)
    static RemminaConnectionObject * rcw_get_visible_cnnobj(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:377
    static gboolean rcw_focus_in_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
    Definition: rcw.c:3247
    -
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    void rcw_toolbar_menu_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1773
    GtkWidget * remmina_applet_menu_new(void)
    @@ -224,11 +224,11 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static void rco_check_resize(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:1060
    struct _RemminaConnectionWindowPriv RemminaConnectionWindowPriv
    Definition: rcw.h:52
    -
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    G_DEFINE_TYPE(RemminaConnectionWindow, rcw, GTK_TYPE_WINDOW)
    Definition: rcw.c:81
    static gboolean rcw_map_event_fullscreen(GtkWidget *widget, GdkEvent *event, gpointer data)
    Definition: rcw.c:3327
    -
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    +
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    static void remmina_protocol_widget_update_alignment(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:1148
    GtkWidget * remmina_scrolled_viewport_new(void)
    static gboolean rcw_on_switch_page_finalsel(gpointer user_data)
    Definition: rcw.c:3631
    @@ -249,7 +249,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    GtkWindow * rcw_get_gtkwindow(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:4703
    -
    GtkWidget * remmina_protocol_widget_new(void)
    +
    GtkWidget * remmina_protocol_widget_new(void)
    static const GtkTargetEntry dnd_targets_ftb[]
    Definition: rcw.c:203
    gboolean confirm_close
    Definition: remmina_pref.h:147
    @@ -259,7 +259,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    gint toolbar_placement
    Definition: remmina_pref.h:225
    RemminaProtocolFeatureType type
    Definition: types.h:73
    gboolean rcw_toolbar_autofit_restore(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:950
    -
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    GtkWidget * aspectframe
    Definition: rcw.c:167
    static void rcw_toolbar_tools(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:2015
    static gboolean rcw_on_enter_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
    Definition: rcw.c:2816
    @@ -293,7 +293,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static void rcw_toolbar_switch_page(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1582
    guint shortcutkey_scale
    Definition: remmina_pref.h:180
    static void rcw_toolbar_place_signal(RemminaConnectionWindow *cnnwin, gpointer data)
    Definition: rcw.c:3207
    -
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    +
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    static GtkNotebook * rcw_on_notebook_create_window(GtkNotebook *notebook, GtkWidget *page, gint x, gint y, gpointer data)
    Definition: rcw.c:3691
    struct _RemminaConnectionObject RemminaConnectionObject
    @@ -304,17 +304,17 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static gboolean rcw_unmap_event(GtkWidget *widget, GdkEvent *event, gpointer data)
    Definition: rcw.c:3309
    static void rcw_toolbar_menu(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1978
    static guint rcw_signals[LAST_SIGNAL]
    Definition: rcw.c:185
    -
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    gboolean fullscreen
    Definition: remmina.c:89
    -
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    void remmina_public_popup_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
    -
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    +
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    void remmina_applet_menu_populate(RemminaAppletMenu *menu)
    gboolean remmina_pref_get_boolean(const gchar *key)
    GTKSOCKET_NOT_AVAIL_RESPONSE_TYPE
    These define the response id&#39;s of the gtksocket-is-not-available-warning-dialog buttons.
    Definition: rcw.c:4472
    static void rcw_kp_ungrab(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:429
    -
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    static void rcw_toolbar_scaled_mode(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:1701
    void rco_closewin(RemminaProtocolWidget *gp)
    Definition: rcw.c:3480
    static gboolean rcw_on_configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
    Definition: rcw.c:3093
    @@ -327,7 +327,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static RemminaConnectionObject * rcw_get_cnnobj_at_page(RemminaConnectionWindow *cnnwin, gint npage)
    Definition: rcw.c:367
    static gboolean rcw_tb_drag_failed(GtkWidget *widget, GdkDragContext *context, GtkDragResult result, gpointer user_data)
    Definition: rcw.c:769
    gboolean applet_hide_count
    Definition: remmina_pref.h:163
    -
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    GtkWidget * rcw_get_gtkviewport(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:4707
    static gboolean rcw_floating_toolbar_on_leave(GtkWidget *widget, GdkEventCrossing *event, RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:2806
    static gboolean rcw_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
    Definition: rcw.c:3268
    @@ -340,7 +340,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    RemminaConnectionWindowPriv * priv
    Definition: rcw.h:56
    -
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    void rcw_open_from_file(RemminaFile *remminafile)
    Definition: rcw.c:4453
    @@ -359,14 +359,14 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    static void rcw_pointer_ungrab(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:497
    guint shortcutkey_toolbar
    Definition: remmina_pref.h:187
    GtkWidget * scrolled_container
    Definition: rcw.c:170
    -
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    RemminaFile * remmina_file
    Definition: rcw.c:164
    static void rcw_gtksocket_not_available_dialog_response(GtkDialog *self, gint response_id, RemminaConnectionObject *cnnobj)
    Gets called if the user interacts with the gtksocket-is-not-available-warning-dialog.
    Definition: rcw.c:4481
    static void rco_change_scalemode(RemminaConnectionObject *cnnobj, gboolean bdyn, gboolean bscale)
    Definition: rcw.c:1651
    -
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    static void rcw_update_notebook(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:3610
    @@ -389,7 +389,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    void remmina_message_panel_setup_message(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    gboolean kioskmode
    Definition: remmina.c:87
    void remmina_application_condexit(RemminaCondExitType why)
    Definition: remmina_exec.c:123
    -
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    +
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    static gboolean focus_in_delayed_grab(RemminaConnectionWindow *cnnwin)
    Definition: rcw.c:2925
    void rco_update_toolbar_autofit_button(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:1633
    gboolean extrahardening
    Definition: remmina.c:90
    @@ -399,7 +399,7 @@ $(document).ready(function(){initNavTree('rcw_8c_source.html','');});
    void rco_get_monitor_geometry(RemminaConnectionObject *cnnobj, GdkRectangle *sz)
    Definition: rcw.c:1009
    -
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    +
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    RemminaFile * remmina_file_manager_load_file(const gchar *filename)
    diff --git a/public/remmina__masterthread__exec_8c_source.html b/public/remmina__masterthread__exec_8c_source.html index 1d41f0133..e8056c319 100644 --- a/public/remmina__masterthread__exec_8c_source.html +++ b/public/remmina__masterthread__exec_8c_source.html @@ -88,8 +88,8 @@ $(document).ready(function(){initNavTree('remmina__masterthread__exec_8c_source.
    Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2009-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 /* Support for execution on main thread of some GTK related
    38  * functions (due to threads deprecations in GTK) */
    39 
    40 #include <gtk/gtk.h>
    41 
    43 
    44 static pthread_t gMainThreadID;
    45 
    47 {
    48 
    49  /* This function is called on main GTK Thread via gdk_threads_add_idlde()
    50  * from remmina_masterthread_exec_and_wait() */
    51 
    52  if (!d->cancelled) {
    53  switch (d->func) {
    54  case FUNC_INIT_SAVE_CRED:
    56  break;
    57  case FUNC_CHAT_RECEIVE:
    59  break;
    60  case FUNC_FILE_GET_STRING:
    61  d->p.file_get_string.retval = remmina_file_get_string( d->p.file_get_string.remminafile, d->p.file_get_string.setting );
    62  break;
    63  case FUNC_FILE_SET_STRING:
    64  remmina_file_set_string( d->p.file_set_string.remminafile, d->p.file_set_string.setting, d->p.file_set_string.value );
    65  break;
    66  case FUNC_GTK_LABEL_SET_TEXT:
    67  gtk_label_set_text( d->p.gtk_label_set_text.label, d->p.gtk_label_set_text.str );
    68  break;
    69  case FUNC_FTP_CLIENT_UPDATE_TASK:
    71  break;
    72  case FUNC_FTP_CLIENT_GET_WAITING_TASK:
    74  break;
    75  case FUNC_PROTOCOLWIDGET_EMIT_SIGNAL:
    77  break;
    78  case FUNC_PROTOCOLWIDGET_MPPROGRESS:
    80  d->p.protocolwidget_mpprogress.response_callback, d->p.protocolwidget_mpprogress.response_callback_data);
    81  break;
    82  case FUNC_PROTOCOLWIDGET_MPDESTROY:
    84  break;
    85  case FUNC_PROTOCOLWIDGET_MPSHOWRETRY:
    87  break;
    88  case FUNC_PROTOCOLWIDGET_PANELSHOWLISTEN:
    90  break;
    91  case FUNC_SFTP_CLIENT_CONFIRM_RESUME:
    92 #ifdef HAVE_LIBSSH
    94  d->p.sftp_client_confirm_resume.path );
    95 #endif
    96  break;
    97  case FUNC_VTE_TERMINAL_SET_ENCODING_AND_PTY:
    98 #if defined (HAVE_LIBSSH) && defined (HAVE_LIBVTE)
    103 #endif
    104  break;
    105 
    106  }
    107  pthread_mutex_lock(&d->pt_mutex);
    108  d->complete = TRUE;
    109  pthread_cond_signal(&d->pt_cond);
    110  pthread_mutex_unlock(&d->pt_mutex);
    111  }else {
    112  /* thread has been cancelled, so we must free d memory here */
    113  g_free(d);
    114  }
    115  return G_SOURCE_REMOVE;
    116 }
    117 
    119 {
    120  RemminaMTExecData *d = data;
    121 
    122  d->cancelled = TRUE;
    123 }
    124 
    126 {
    127  d->cancelled = FALSE;
    128  d->complete = FALSE;
    129  pthread_cleanup_push(remmina_masterthread_exec_cleanup_handler, (void*)d);
    130  pthread_mutex_init(&d->pt_mutex, NULL);
    131  pthread_cond_init(&d->pt_cond, NULL);
    132  gdk_threads_add_idle((GSourceFunc)remmina_masterthread_exec_callback, (gpointer)d);
    133  pthread_mutex_lock(&d->pt_mutex);
    134  while (!d->complete)
    135  pthread_cond_wait(&d->pt_cond, &d->pt_mutex);
    136  pthread_cleanup_pop(0);
    137  pthread_mutex_destroy(&d->pt_mutex);
    138  pthread_cond_destroy(&d->pt_cond);
    139 }
    140 
    142 {
    143  /* To be called from main thread at startup */
    144  gMainThreadID = pthread_self();
    145 }
    146 
    148 {
    149  return pthread_equal(gMainThreadID, pthread_self()) != 0;
    150 }
    151 
    struct remmina_masterthread_exec_data::@12::@14 init_save_creds
    const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
    Definition: remmina_file.c:516
    -
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    -
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    +
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    gint remmina_sftp_client_confirm_resume(RemminaSFTPClient *client, const gchar *path)
    struct remmina_masterthread_exec_data::@12::@24 protocolwidget_panelshowlisten
    @@ -102,22 +102,22 @@ $(document).ready(function(){initNavTree('remmina__masterthread__exec_8c_source.
    static pthread_t gMainThreadID
    RemminaFTPTask * remmina_ftp_client_get_waiting_task(RemminaFTPClient *client)
    void remmina_ftp_client_update_task(RemminaFTPClient *client, RemminaFTPTask *task)
    -
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    +
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    struct remmina_masterthread_exec_data::@12::@21 protocolwidget_mpprogress
    gboolean remmina_masterthread_exec_is_main_thread()
    struct remmina_masterthread_exec_data::@12::@22 protocolwidget_mpdestroy
    struct remmina_masterthread_exec_data::@12::@23 protocolwidget_mpshowretry
    struct remmina_masterthread_exec_data::@12::@26 vte_terminal_set_encoding_and_pty
    -
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    +
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    struct remmina_masterthread_exec_data::@12::@25 sftp_client_confirm_resume
    -
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    -
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    +
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    +
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    struct remmina_masterthread_exec_data::@12::@17 file_set_string
    struct remmina_masterthread_exec_data::@12::@16 file_get_string
    static void remmina_masterthread_exec_cleanup_handler(gpointer data)
    void remmina_masterthread_exec_and_wait(RemminaMTExecData *d)
    -
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    +
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    static gboolean remmina_masterthread_exec_callback(RemminaMTExecData *d)
    struct remmina_masterthread_exec_data::@12::@13 gtk_label_set_text
    diff --git a/public/remmina__plugin__manager_8c_source.html b/public/remmina__plugin__manager_8c_source.html index ada58c214..f04d8bdce 100644 --- a/public/remmina__plugin__manager_8c_source.html +++ b/public/remmina__plugin__manager_8c_source.html @@ -86,47 +86,47 @@ $(document).ready(function(){initNavTree('remmina__plugin__manager_8c_source.htm
    remmina_plugin_manager.c
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2010-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #include "config.h"
    38 
    39 
    40 #include <gtk/gtk.h>
    41 #include <glib/gi18n.h>
    42 #include <gmodule.h>
    43 #include <gio/gio.h>
    44 #include <string.h>
    45 #ifdef GDK_WINDOWING_X11
    46 #include <gdk/gdkx.h>
    47 #elif defined(GDK_WINDOWING_WAYLAND)
    48 #include <gdk/gdkwayland.h>
    49 #endif
    50 #include "remmina_public.h"
    51 #include "remmina_main.h"
    52 #include "remmina_file_manager.h"
    53 #include "remmina_pref.h"
    55 #include "remmina_log.h"
    56 #include "remmina_widget_pool.h"
    57 #include "rcw.h"
    58 #include "remmina_plugin_manager.h"
    59 #include "remmina_plugin_native.h"
    60 #include "remmina_public.h"
    63 
    64 static GPtrArray* remmina_plugin_table = NULL;
    65 
    66 /* A GHashTable of GHashTables where to store the names of the encrypted settings */
    67 static GHashTable *encrypted_settings_cache = NULL;
    68 
    69 /* There can be only one secret plugin loaded */
    71 
    72 // TRANSLATORS: "Language Wrapper" is a wrapper for plugins written in other programmin languages (Python in this context)
    73 static const gchar *remmina_plugin_type_name[] =
    74 { N_("Protocol"), N_("Entry"), N_("File"), N_("Tool"), N_("Preference"), N_("Secret"), N_("Language Wrapper"), NULL };
    75 
    77 {
    78  TRACE_CALL(__func__);
    79  return g_strcmp0((*a)->name, (*b)->name);
    80 }
    81 
    82 static void htdestroy(gpointer ht)
    83 {
    84  g_hash_table_unref(ht);
    85 }
    86 
    87 static void init_settings_cache(RemminaPlugin *plugin)
    88 {
    89  TRACE_CALL(__func__);
    90  RemminaProtocolPlugin *protocol_plugin;
    91  const RemminaProtocolSetting* setting_iter;
    92  GHashTable *pht;
    93 
    94  /* This code make a encrypted setting cache only for protocol plugins */
    95 
    96  if (plugin->type != REMMINA_PLUGIN_TYPE_PROTOCOL) {
    97  return;
    98  }
    99 
    100  if (encrypted_settings_cache == NULL)
    101  encrypted_settings_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, htdestroy);
    102 
    103  if (!(pht = g_hash_table_lookup(encrypted_settings_cache, plugin->name))) {
    104  pht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
    105  g_hash_table_insert(encrypted_settings_cache, g_strdup(plugin->name), pht);
    106  }
    107 
    108  /* Some settings are encrypted "by name" */
    109  /* g_hash_table_insert(pht, g_strdup("proxy_password"), (gpointer)TRUE); */
    110 
    111  g_hash_table_insert(pht, g_strdup("ssh_tunnel_password"), (gpointer)TRUE);
    112  g_hash_table_insert(pht, g_strdup("ssh_tunnel_passphrase"), (gpointer)TRUE);
    113 
    114  /* ssh_password is no longer used starting from remmina 1.4.
    115  * But we MUST mark it as encrypted setting, or the migration procedure will fail */
    116  g_hash_table_insert(pht, g_strdup("ssh_password"), (gpointer)TRUE);
    117 
    118  /* Other settings are encrypted because of their type */
    119  protocol_plugin = (RemminaProtocolPlugin *)plugin;
    120  setting_iter = protocol_plugin->basic_settings;
    121  if (setting_iter) {
    122  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
    123  if (setting_iter->type == REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD)
    124  g_hash_table_insert(pht, g_strdup(remmina_plugin_manager_get_canonical_setting_name(setting_iter)), (gpointer)TRUE);
    125  setting_iter++;
    126  }
    127  }
    128  setting_iter = protocol_plugin->advanced_settings;
    129  if (setting_iter) {
    130  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
    131  if (setting_iter->type == REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD)
    132  g_hash_table_insert(pht, g_strdup(remmina_plugin_manager_get_canonical_setting_name(setting_iter)), (gpointer)TRUE);
    133  setting_iter++;
    134  }
    135  }
    136 
    137 }
    138 
    140 {
    141  TRACE_CALL(__func__);
    142  if (plugin->type == REMMINA_PLUGIN_TYPE_SECRET) {
    143  g_print("Remmina plugin %s (type=%s) has been registered, but is not yet initialized/activated. "
    144  "The initialization order is %d.\n", plugin->name,
    145  _(remmina_plugin_type_name[plugin->type]),
    146  ((RemminaSecretPlugin*)plugin)->init_order);
    147  }
    148  init_settings_cache(plugin);
    149 
    150  g_ptr_array_add(remmina_plugin_table, plugin);
    151  g_ptr_array_sort(remmina_plugin_table, (GCompareFunc)remmina_plugin_manager_compare_func);
    152  return TRUE;
    153 }
    154 
    156 {
    157  GdkDisplayManager* dm;
    158  GdkDisplay* d;
    159  gboolean available;
    160 
    161  dm = gdk_display_manager_get();
    162  d = gdk_display_manager_get_default_display(dm);
    163  available = FALSE;
    164 
    165 #ifdef GDK_WINDOWING_X11
    166  if (GDK_IS_X11_DISPLAY(d)) {
    167  /* GtkSocket support is available only under X.Org */
    168  available = TRUE;
    169  }
    170 #endif
    171  return available;
    172 }
    173 
    175 {
    222 
    224 
    234 
    243 
    253 
    255 
    311 };
    312 
    313 const char *get_filename_ext(const char *filename) {
    314  const char* last = strrchr(filename, '/');
    315  const char *dot = strrchr(last, '.');
    316  if(!dot || dot == filename) return "";
    317  return dot + 1;
    318 }
    319 
    320 static gint compare_secret_plugin_init_order(gconstpointer a, gconstpointer b)
    321 {
    322  RemminaSecretPlugin *sa, *sb;
    323 
    324  sa = (RemminaSecretPlugin*)a;
    325  sb = (RemminaSecretPlugin*)b;
    326 
    327  if (sa->init_order > sb->init_order)
    328  return 1;
    329  else if (sa->init_order < sb->init_order)
    330  return -1;
    331  return 0;
    332 }
    333 
    335 {
    336  TRACE_CALL(__func__);
    337  GDir *dir;
    338  const gchar *name, *ptr;
    339  gchar *fullpath;
    340  RemminaPlugin *plugin;
    342  int i, j;
    343  GSList *secret_plugins;
    344  GSList *sple;
    345  GPtrArray *alternative_language_plugins;
    346 
    347  remmina_plugin_table = g_ptr_array_new();
    348  alternative_language_plugins = g_ptr_array_new();
    349 
    350  if (!g_module_supported()) {
    351  g_print("Dynamic loading of plugins is not supported on this platform!\n");
    352  return;
    353  }
    354 
    355  g_print("Load modules from %s\n", REMMINA_RUNTIME_PLUGINDIR);
    356  dir = g_dir_open(REMMINA_RUNTIME_PLUGINDIR, 0, NULL);
    357 
    358  if (dir == NULL)
    359  return;
    360  while ((name = g_dir_read_name(dir)) != NULL) {
    361  if ((ptr = strrchr(name, '.')) == NULL)
    362  continue;
    363  ptr++;
    364  fullpath = g_strdup_printf(REMMINA_RUNTIME_PLUGINDIR "/%s", name);
    366  g_ptr_array_add(alternative_language_plugins, g_strdup_printf(REMMINA_RUNTIME_PLUGINDIR "/%s", name));
    367  g_free(fullpath);
    368  continue;
    369  }
    370  remmina_plugin_native_load(&remmina_plugin_manager_service, fullpath);
    371  g_free(fullpath);
    372  }
    373  g_dir_close(dir);
    374 
    375  while (alternative_language_plugins->len > 0) {
    376  gboolean has_loaded = FALSE;
    377  gchar* name = (gchar*)g_ptr_array_remove_index(alternative_language_plugins, 0);
    378  const gchar* ext = get_filename_ext(name);
    379 
    380  for (j = 0; j < remmina_plugin_table->len && !has_loaded; j++) {
    381  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, j);
    384  const gchar** supported_extention = wrapper_plugin->supported_extentions;
    385  while (*supported_extention) {
    386  if (g_str_equal(*supported_extention, ext)) {
    387  has_loaded = wrapper_plugin->load(wrapper_plugin, name);
    388  if (has_loaded) {
    389  break;
    390  }
    391  }
    392  supported_extention++;
    393  }
    394  if (has_loaded) break;
    395  }
    396  }
    397 
    398  if (!has_loaded) {
    399  g_print("%s: Skip unsupported file type '%s'\n", name, ext);
    400  }
    401 
    402  g_free(name);
    403  }
    404 
    405  /* Now all secret plugins needs to initialize, following their init_order.
    406  * The 1st plugin which will initialize correctly will be
    407  * the default remmina_secret_plugin */
    408 
    409  if (remmina_secret_plugin)
    410  g_print("Internal ERROR: remmina_secret_plugin must be null here\n");
    411 
    412  secret_plugins = NULL;
    413  for (i = 0; i < remmina_plugin_table->len; i++) {
    414  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    415  if (plugin->type == REMMINA_PLUGIN_TYPE_SECRET) {
    416  secret_plugins = g_slist_insert_sorted(secret_plugins, (gpointer)plugin, compare_secret_plugin_init_order);
    417  }
    418  }
    419 
    420  sple = secret_plugins;
    421  while(sple != NULL) {
    422  sp = (RemminaSecretPlugin*)sple->data;
    423  if (sp->init(sp)) {
    424  g_print("The %s secret plugin has been initialized and it will be your default secret plugin\n",
    425  sp->name);
    426  remmina_secret_plugin = sp;
    427  break;
    428  }
    429  sple = sple->next;
    430  }
    431 
    432  g_slist_free(secret_plugins);
    433  g_ptr_array_free(alternative_language_plugins, TRUE);
    434 }
    435 
    436 gboolean remmina_plugin_manager_loader_supported(const char *filetype) {
    437  TRACE_CALL(__func__);
    438  return g_str_equal(G_MODULE_SUFFIX, filetype);
    439 }
    440 
    442 {
    443  TRACE_CALL(__func__);
    444  RemminaPlugin *plugin;
    445  gint i;
    446 
    447  for (i = 0; i < remmina_plugin_table->len; i++) {
    448  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    449  if (plugin->type == type && g_strcmp0(plugin->name, name) == 0) {
    450  return plugin;
    451  }
    452  }
    453  return NULL;
    454 }
    455 
    457 {
    458  if (setting->name == NULL) {
    460  return "server";
    462  return "password";
    464  return "resolution";
    466  return "assistance_mode";
    467  return "missing_setting_name_into_plugin_RemminaProtocolSetting";
    468  }
    469  return setting->name;
    470 }
    471 
    473 {
    474  TRACE_CALL(__func__);
    475  RemminaPlugin *plugin;
    476  gint i;
    477 
    478  for (i = 0; i < remmina_plugin_table->len; i++) {
    479  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    480  if (plugin->type == type) {
    481  func((gchar*)plugin->name, plugin, data);
    482  }
    483  }
    484 }
    485 
    486 /* A copy of remmina_plugin_manager_show and remmina_plugin_manager_show_for_each
    487  * This is because we want to print the list of plugins, and their versions, to the standard output
    488  * with the remmina command line option --full-version instead of using the plugins widget
    489  ** @todo Investigate to use only GListStore and than pass the elements to be shown to 2 separate
    490  * functions
    491  * WARNING: GListStore is supported only from GLib 2.44 */
    493 {
    494  TRACE_CALL(__func__);
    495 
    496  g_print("%-20s%-16s%-64s%-10s\n", plugin->name,
    497  _(remmina_plugin_type_name[plugin->type]),
    498  g_dgettext(plugin->domain, plugin->description),
    499  plugin->version);
    500  return FALSE;
    501 }
    502 
    504 {
    505  TRACE_CALL(__func__);
    506  g_print("%-20s%-16s%-64s%-10s\n", "NAME", "TYPE", "DESCRIPTION", "PLUGIN AND LIBRARY VERSION");
    507  g_ptr_array_foreach(remmina_plugin_table, (GFunc)remmina_plugin_manager_show_for_each_stdout, NULL);
    508 }
    509 
    510 static gboolean remmina_plugin_manager_show_for_each(RemminaPlugin *plugin, GtkListStore *store)
    511 {
    512  TRACE_CALL(__func__);
    513  GtkTreeIter iter;
    514 
    515  gtk_list_store_append(store, &iter);
    516  gtk_list_store_set(store, &iter, 0, plugin->name, 1, _(remmina_plugin_type_name[plugin->type]), 2,
    517  g_dgettext(plugin->domain, plugin->description), 3, plugin->version, -1);
    518  return FALSE;
    519 }
    520 
    521 void remmina_plugin_manager_show(GtkWindow *parent)
    522 {
    523  TRACE_CALL(__func__);
    524  GtkWidget *dialog;
    525  GtkWidget *scrolledwindow;
    526  GtkWidget *tree;
    527  GtkCellRenderer *renderer;
    528  GtkTreeViewColumn *column;
    529  GtkListStore *store;
    530 
    531  dialog = gtk_dialog_new_with_buttons(_("Plugins"), parent, GTK_DIALOG_MODAL, _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
    532  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog);
    533  gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 350);
    534 
    535  scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
    536  gtk_widget_show(scrolledwindow);
    537  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    538  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), scrolledwindow, TRUE, TRUE, 0);
    539 
    540  tree = gtk_tree_view_new();
    541  gtk_container_add(GTK_CONTAINER(scrolledwindow), tree);
    542  gtk_widget_show(tree);
    543 
    544  store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
    545  g_ptr_array_foreach(remmina_plugin_table, (GFunc)remmina_plugin_manager_show_for_each, store);
    546  gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store));
    547 
    548  renderer = gtk_cell_renderer_text_new();
    549  column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 0, NULL);
    550  gtk_tree_view_column_set_resizable(column, TRUE);
    551  gtk_tree_view_column_set_sort_column_id(column, 0);
    552  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    553 
    554  renderer = gtk_cell_renderer_text_new();
    555  column = gtk_tree_view_column_new_with_attributes(_("Type"), renderer, "text", 1, NULL);
    556  gtk_tree_view_column_set_resizable(column, TRUE);
    557  gtk_tree_view_column_set_sort_column_id(column, 1);
    558  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    559 
    560  renderer = gtk_cell_renderer_text_new();
    561  column = gtk_tree_view_column_new_with_attributes(_("Description"), renderer, "text", 2, NULL);
    562  gtk_tree_view_column_set_resizable(column, TRUE);
    563  gtk_tree_view_column_set_sort_column_id(column, 2);
    564  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    565 
    566  renderer = gtk_cell_renderer_text_new();
    567  column = gtk_tree_view_column_new_with_attributes(_("Version"), renderer, "text", 3, NULL);
    568  gtk_tree_view_column_set_resizable(column, TRUE);
    569  gtk_tree_view_column_set_sort_column_id(column, 3);
    570  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    571 
    572  gtk_widget_show(dialog);
    573 }
    574 
    576 {
    577  TRACE_CALL(__func__);
    578  RemminaFilePlugin *plugin;
    579  gint i;
    580 
    581  for (i = 0; i < remmina_plugin_table->len; i++) {
    582  plugin = (RemminaFilePlugin*)g_ptr_array_index(remmina_plugin_table, i);
    583 
    584  if (plugin->type != REMMINA_PLUGIN_TYPE_FILE)
    585  continue;
    586 
    587  if (plugin->import_test_func(plugin, file)) {
    588  return plugin;
    589  }
    590  }
    591  return NULL;
    592 }
    593 
    595 {
    596  TRACE_CALL(__func__);
    597  RemminaFilePlugin *plugin;
    598  gint i;
    599 
    600  for (i = 0; i < remmina_plugin_table->len; i++) {
    601  plugin = (RemminaFilePlugin*)g_ptr_array_index(remmina_plugin_table, i);
    602  if (plugin->type != REMMINA_PLUGIN_TYPE_FILE)
    603  continue;
    604  if (plugin->export_test_func(plugin, remminafile)) {
    605  return plugin;
    606  }
    607  }
    608  return NULL;
    609 }
    610 
    612 {
    613  TRACE_CALL(__func__);
    614  return remmina_secret_plugin;
    615 }
    616 
    618 {
    619  TRACE_CALL(__func__);
    620  const RemminaProtocolFeature *feature;
    621  RemminaProtocolPlugin* plugin;
    622 
    624 
    625  if (plugin == NULL) {
    626  return FALSE;
    627  }
    628 
    629  for (feature = plugin->features; feature && feature->type; feature++) {
    630  if (feature->type == ftype)
    631  return TRUE;
    632  }
    633  return FALSE;
    634 }
    635 
    637 {
    638  TRACE_CALL(__func__);
    639  GHashTable *pht;
    640 
    641  if (encrypted_settings_cache == NULL)
    642  return FALSE;
    643 
    644  if (!(pht = g_hash_table_lookup(encrypted_settings_cache, pp->name)))
    645  return FALSE;
    646 
    647  if (!g_hash_table_lookup(pht, setting))
    648  return FALSE;
    649 
    650  return TRUE;
    651 }
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2010-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #include "config.h"
    38 
    39 
    40 #include <gtk/gtk.h>
    41 #include <glib/gi18n.h>
    42 #include <gmodule.h>
    43 #include <gio/gio.h>
    44 #include <string.h>
    45 #ifdef GDK_WINDOWING_X11
    46 #include <gdk/gdkx.h>
    47 #elif defined(GDK_WINDOWING_WAYLAND)
    48 #include <gdk/gdkwayland.h>
    49 #endif
    50 #include "remmina_public.h"
    51 #include "remmina_main.h"
    52 #include "remmina_file_manager.h"
    53 #include "remmina_pref.h"
    55 #include "remmina_log.h"
    56 #include "remmina_widget_pool.h"
    57 #include "rcw.h"
    58 #include "remmina_plugin_manager.h"
    59 #include "remmina_plugin_native.h"
    60 #include "remmina_public.h"
    63 
    64 static GPtrArray* remmina_plugin_table = NULL;
    65 
    66 /* A GHashTable of GHashTables where to store the names of the encrypted settings */
    67 static GHashTable *encrypted_settings_cache = NULL;
    68 
    69 /* There can be only one secret plugin loaded */
    71 
    72 // TRANSLATORS: "Language Wrapper" is a wrapper for plugins written in other programmin languages (Python in this context)
    73 static const gchar *remmina_plugin_type_name[] =
    74 { N_("Protocol"), N_("Entry"), N_("File"), N_("Tool"), N_("Preference"), N_("Secret"), N_("Language Wrapper"), NULL };
    75 
    77 {
    78  TRACE_CALL(__func__);
    79  return g_strcmp0((*a)->name, (*b)->name);
    80 }
    81 
    82 static void htdestroy(gpointer ht)
    83 {
    84  g_hash_table_unref(ht);
    85 }
    86 
    87 static void init_settings_cache(RemminaPlugin *plugin)
    88 {
    89  TRACE_CALL(__func__);
    90  RemminaProtocolPlugin *protocol_plugin;
    91  const RemminaProtocolSetting* setting_iter;
    92  GHashTable *pht;
    93 
    94  /* This code make a encrypted setting cache only for protocol plugins */
    95 
    96  if (plugin->type != REMMINA_PLUGIN_TYPE_PROTOCOL) {
    97  return;
    98  }
    99 
    100  if (encrypted_settings_cache == NULL)
    101  encrypted_settings_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, htdestroy);
    102 
    103  if (!(pht = g_hash_table_lookup(encrypted_settings_cache, plugin->name))) {
    104  pht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
    105  g_hash_table_insert(encrypted_settings_cache, g_strdup(plugin->name), pht);
    106  }
    107 
    108  /* Some settings are encrypted "by name" */
    109  /* g_hash_table_insert(pht, g_strdup("proxy_password"), (gpointer)TRUE); */
    110 
    111  g_hash_table_insert(pht, g_strdup("ssh_tunnel_password"), (gpointer)TRUE);
    112  g_hash_table_insert(pht, g_strdup("ssh_tunnel_passphrase"), (gpointer)TRUE);
    113 
    114  /* ssh_password is no longer used starting from remmina 1.4.
    115  * But we MUST mark it as encrypted setting, or the migration procedure will fail */
    116  g_hash_table_insert(pht, g_strdup("ssh_password"), (gpointer)TRUE);
    117 
    118  /* Other settings are encrypted because of their type */
    119  protocol_plugin = (RemminaProtocolPlugin *)plugin;
    120  setting_iter = protocol_plugin->basic_settings;
    121  if (setting_iter) {
    122  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
    123  if (setting_iter->type == REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD)
    124  g_hash_table_insert(pht, g_strdup(remmina_plugin_manager_get_canonical_setting_name(setting_iter)), (gpointer)TRUE);
    125  setting_iter++;
    126  }
    127  }
    128  setting_iter = protocol_plugin->advanced_settings;
    129  if (setting_iter) {
    130  while (setting_iter->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
    131  if (setting_iter->type == REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD)
    132  g_hash_table_insert(pht, g_strdup(remmina_plugin_manager_get_canonical_setting_name(setting_iter)), (gpointer)TRUE);
    133  setting_iter++;
    134  }
    135  }
    136 
    137 }
    138 
    140 {
    141  TRACE_CALL(__func__);
    142  if (plugin->type == REMMINA_PLUGIN_TYPE_SECRET) {
    143  g_print("Remmina plugin %s (type=%s) has been registered, but is not yet initialized/activated. "
    144  "The initialization order is %d.\n", plugin->name,
    145  _(remmina_plugin_type_name[plugin->type]),
    146  ((RemminaSecretPlugin*)plugin)->init_order);
    147  }
    148  init_settings_cache(plugin);
    149 
    150  g_ptr_array_add(remmina_plugin_table, plugin);
    151  g_ptr_array_sort(remmina_plugin_table, (GCompareFunc)remmina_plugin_manager_compare_func);
    152  return TRUE;
    153 }
    154 
    156 {
    157  GdkDisplayManager* dm;
    158  GdkDisplay* d;
    159  gboolean available;
    160 
    161  dm = gdk_display_manager_get();
    162  d = gdk_display_manager_get_default_display(dm);
    163  available = FALSE;
    164 
    165 #ifdef GDK_WINDOWING_X11
    166  if (GDK_IS_X11_DISPLAY(d)) {
    167  /* GtkSocket support is available only under X.Org */
    168  available = TRUE;
    169  }
    170 #endif
    171  return available;
    172 }
    173 
    175 {
    222 
    224 
    234 
    243 
    253 
    255 
    311 };
    312 
    313 const char *get_filename_ext(const char *filename) {
    314  const char* last = strrchr(filename, '/');
    315  const char *dot = strrchr(last, '.');
    316  if(!dot || dot == filename) return "";
    317  return dot + 1;
    318 }
    319 
    320 static gint compare_secret_plugin_init_order(gconstpointer a, gconstpointer b)
    321 {
    322  RemminaSecretPlugin *sa, *sb;
    323 
    324  sa = (RemminaSecretPlugin*)a;
    325  sb = (RemminaSecretPlugin*)b;
    326 
    327  if (sa->init_order > sb->init_order)
    328  return 1;
    329  else if (sa->init_order < sb->init_order)
    330  return -1;
    331  return 0;
    332 }
    333 
    335 {
    336  TRACE_CALL(__func__);
    337  GDir *dir;
    338  const gchar *name, *ptr;
    339  gchar *fullpath;
    340  RemminaPlugin *plugin;
    342  int i, j;
    343  GSList *secret_plugins;
    344  GSList *sple;
    345  GPtrArray *alternative_language_plugins;
    346 
    347  remmina_plugin_table = g_ptr_array_new();
    348  alternative_language_plugins = g_ptr_array_new();
    349 
    350  if (!g_module_supported()) {
    351  g_print("Dynamic loading of plugins is not supported on this platform!\n");
    352  return;
    353  }
    354 
    355  g_print("Load modules from %s\n", REMMINA_RUNTIME_PLUGINDIR);
    356  dir = g_dir_open(REMMINA_RUNTIME_PLUGINDIR, 0, NULL);
    357 
    358  if (dir == NULL)
    359  return;
    360  while ((name = g_dir_read_name(dir)) != NULL) {
    361  if ((ptr = strrchr(name, '.')) == NULL)
    362  continue;
    363  ptr++;
    364  fullpath = g_strdup_printf(REMMINA_RUNTIME_PLUGINDIR "/%s", name);
    366  g_ptr_array_add(alternative_language_plugins, g_strdup_printf(REMMINA_RUNTIME_PLUGINDIR "/%s", name));
    367  g_free(fullpath);
    368  continue;
    369  }
    370  remmina_plugin_native_load(&remmina_plugin_manager_service, fullpath);
    371  g_free(fullpath);
    372  }
    373  g_dir_close(dir);
    374 
    375  while (alternative_language_plugins->len > 0) {
    376  gboolean has_loaded = FALSE;
    377  gchar* name = (gchar*)g_ptr_array_remove_index(alternative_language_plugins, 0);
    378  const gchar* ext = get_filename_ext(name);
    379 
    380  for (j = 0; j < remmina_plugin_table->len && !has_loaded; j++) {
    381  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, j);
    384  const gchar** supported_extention = wrapper_plugin->supported_extentions;
    385  while (*supported_extention) {
    386  if (g_str_equal(*supported_extention, ext)) {
    387  has_loaded = wrapper_plugin->load(wrapper_plugin, name);
    388  if (has_loaded) {
    389  break;
    390  }
    391  }
    392  supported_extention++;
    393  }
    394  if (has_loaded) break;
    395  }
    396  }
    397 
    398  if (!has_loaded) {
    399  g_print("%s: Skip unsupported file type '%s'\n", name, ext);
    400  }
    401 
    402  g_free(name);
    403  }
    404 
    405  /* Now all secret plugins needs to initialize, following their init_order.
    406  * The 1st plugin which will initialize correctly will be
    407  * the default remmina_secret_plugin */
    408 
    409  if (remmina_secret_plugin)
    410  g_print("Internal ERROR: remmina_secret_plugin must be null here\n");
    411 
    412  secret_plugins = NULL;
    413  for (i = 0; i < remmina_plugin_table->len; i++) {
    414  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    415  if (plugin->type == REMMINA_PLUGIN_TYPE_SECRET) {
    416  secret_plugins = g_slist_insert_sorted(secret_plugins, (gpointer)plugin, compare_secret_plugin_init_order);
    417  }
    418  }
    419 
    420  sple = secret_plugins;
    421  while(sple != NULL) {
    422  sp = (RemminaSecretPlugin*)sple->data;
    423  if (sp->init(sp)) {
    424  g_print("The %s secret plugin has been initialized and it will be your default secret plugin\n",
    425  sp->name);
    426  remmina_secret_plugin = sp;
    427  break;
    428  }
    429  sple = sple->next;
    430  }
    431 
    432  g_slist_free(secret_plugins);
    433  g_ptr_array_free(alternative_language_plugins, TRUE);
    434 }
    435 
    436 gboolean remmina_plugin_manager_loader_supported(const char *filetype) {
    437  TRACE_CALL(__func__);
    438  return g_str_equal(G_MODULE_SUFFIX, filetype);
    439 }
    440 
    442 {
    443  TRACE_CALL(__func__);
    444  RemminaPlugin *plugin;
    445  gint i;
    446 
    447  for (i = 0; i < remmina_plugin_table->len; i++) {
    448  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    449  if (plugin->type == type && g_strcmp0(plugin->name, name) == 0) {
    450  return plugin;
    451  }
    452  }
    453  return NULL;
    454 }
    455 
    457 {
    458  if (setting->name == NULL) {
    460  return "server";
    462  return "password";
    464  return "resolution";
    466  return "assistance_mode";
    467  return "missing_setting_name_into_plugin_RemminaProtocolSetting";
    468  }
    469  return setting->name;
    470 }
    471 
    473 {
    474  TRACE_CALL(__func__);
    475  RemminaPlugin *plugin;
    476  gint i;
    477 
    478  for (i = 0; i < remmina_plugin_table->len; i++) {
    479  plugin = (RemminaPlugin*)g_ptr_array_index(remmina_plugin_table, i);
    480  if (plugin->type == type) {
    481  func((gchar*)plugin->name, plugin, data);
    482  }
    483  }
    484 }
    485 
    486 /* A copy of remmina_plugin_manager_show and remmina_plugin_manager_show_for_each
    487  * This is because we want to print the list of plugins, and their versions, to the standard output
    488  * with the remmina command line option --full-version instead of using the plugins widget
    489  ** @todo Investigate to use only GListStore and than pass the elements to be shown to 2 separate
    490  * functions
    491  * WARNING: GListStore is supported only from GLib 2.44 */
    493 {
    494  TRACE_CALL(__func__);
    495 
    496  g_print("%-20s%-16s%-64s%-10s\n", plugin->name,
    497  _(remmina_plugin_type_name[plugin->type]),
    498  g_dgettext(plugin->domain, plugin->description),
    499  plugin->version);
    500  return FALSE;
    501 }
    502 
    504 {
    505  TRACE_CALL(__func__);
    506  g_print("%-20s%-16s%-64s%-10s\n", "NAME", "TYPE", "DESCRIPTION", "PLUGIN AND LIBRARY VERSION");
    507  g_ptr_array_foreach(remmina_plugin_table, (GFunc)remmina_plugin_manager_show_for_each_stdout, NULL);
    508 }
    509 
    510 static gboolean remmina_plugin_manager_show_for_each(RemminaPlugin *plugin, GtkListStore *store)
    511 {
    512  TRACE_CALL(__func__);
    513  GtkTreeIter iter;
    514 
    515  gtk_list_store_append(store, &iter);
    516  gtk_list_store_set(store, &iter, 0, plugin->name, 1, _(remmina_plugin_type_name[plugin->type]), 2,
    517  g_dgettext(plugin->domain, plugin->description), 3, plugin->version, -1);
    518  return FALSE;
    519 }
    520 
    521 void remmina_plugin_manager_show(GtkWindow *parent)
    522 {
    523  TRACE_CALL(__func__);
    524  GtkWidget *dialog;
    525  GtkWidget *scrolledwindow;
    526  GtkWidget *tree;
    527  GtkCellRenderer *renderer;
    528  GtkTreeViewColumn *column;
    529  GtkListStore *store;
    530 
    531  dialog = gtk_dialog_new_with_buttons(_("Plugins"), parent, GTK_DIALOG_MODAL, _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
    532  g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog);
    533  gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 350);
    534 
    535  scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
    536  gtk_widget_show(scrolledwindow);
    537  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    538  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), scrolledwindow, TRUE, TRUE, 0);
    539 
    540  tree = gtk_tree_view_new();
    541  gtk_container_add(GTK_CONTAINER(scrolledwindow), tree);
    542  gtk_widget_show(tree);
    543 
    544  store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
    545  g_ptr_array_foreach(remmina_plugin_table, (GFunc)remmina_plugin_manager_show_for_each, store);
    546  gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store));
    547 
    548  renderer = gtk_cell_renderer_text_new();
    549  column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 0, NULL);
    550  gtk_tree_view_column_set_resizable(column, TRUE);
    551  gtk_tree_view_column_set_sort_column_id(column, 0);
    552  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    553 
    554  renderer = gtk_cell_renderer_text_new();
    555  column = gtk_tree_view_column_new_with_attributes(_("Type"), renderer, "text", 1, NULL);
    556  gtk_tree_view_column_set_resizable(column, TRUE);
    557  gtk_tree_view_column_set_sort_column_id(column, 1);
    558  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    559 
    560  renderer = gtk_cell_renderer_text_new();
    561  column = gtk_tree_view_column_new_with_attributes(_("Description"), renderer, "text", 2, NULL);
    562  gtk_tree_view_column_set_resizable(column, TRUE);
    563  gtk_tree_view_column_set_sort_column_id(column, 2);
    564  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    565 
    566  renderer = gtk_cell_renderer_text_new();
    567  column = gtk_tree_view_column_new_with_attributes(_("Version"), renderer, "text", 3, NULL);
    568  gtk_tree_view_column_set_resizable(column, TRUE);
    569  gtk_tree_view_column_set_sort_column_id(column, 3);
    570  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
    571 
    572  gtk_widget_show(dialog);
    573 }
    574 
    576 {
    577  TRACE_CALL(__func__);
    578  RemminaFilePlugin *plugin;
    579  gint i;
    580 
    581  for (i = 0; i < remmina_plugin_table->len; i++) {
    582  plugin = (RemminaFilePlugin*)g_ptr_array_index(remmina_plugin_table, i);
    583 
    584  if (plugin->type != REMMINA_PLUGIN_TYPE_FILE)
    585  continue;
    586 
    587  if (plugin->import_test_func(plugin, file)) {
    588  return plugin;
    589  }
    590  }
    591  return NULL;
    592 }
    593 
    595 {
    596  TRACE_CALL(__func__);
    597  RemminaFilePlugin *plugin;
    598  gint i;
    599 
    600  for (i = 0; i < remmina_plugin_table->len; i++) {
    601  plugin = (RemminaFilePlugin*)g_ptr_array_index(remmina_plugin_table, i);
    602  if (plugin->type != REMMINA_PLUGIN_TYPE_FILE)
    603  continue;
    604  if (plugin->export_test_func(plugin, remminafile)) {
    605  return plugin;
    606  }
    607  }
    608  return NULL;
    609 }
    610 
    612 {
    613  TRACE_CALL(__func__);
    614  return remmina_secret_plugin;
    615 }
    616 
    618 {
    619  TRACE_CALL(__func__);
    620  const RemminaProtocolFeature *feature;
    621  RemminaProtocolPlugin* plugin;
    622 
    624 
    625  if (plugin == NULL) {
    626  return FALSE;
    627  }
    628 
    629  for (feature = plugin->features; feature && feature->type; feature++) {
    630  if (feature->type == ftype)
    631  return TRUE;
    632  }
    633  return FALSE;
    634 }
    635 
    637 {
    638  TRACE_CALL(__func__);
    639  GHashTable *pht;
    640 
    641  if (encrypted_settings_cache == NULL)
    642  return FALSE;
    643 
    644  if (!(pht = g_hash_table_lookup(encrypted_settings_cache, pp->name)))
    645  return FALSE;
    646 
    647  if (!g_hash_table_lookup(pht, setting))
    648  return FALSE;
    649 
    650  return TRUE;
    651 }
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    static RemminaSecretPlugin * remmina_secret_plugin
    const gchar * remmina_plugin_manager_get_canonical_setting_name(const RemminaProtocolSetting *setting)
    -
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    +
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    gboolean remmina_plugin_manager_is_encrypted_setting(RemminaProtocolPlugin *pp, const char *setting)
    gint remmina_pref_get_scale_quality(void)
    const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
    Definition: remmina_file.c:516
    -
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    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.
    +
    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()
    -
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    -
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    +
    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)
    gboolean remmina_plugin_manager_loader_supported(const char *filetype)
    -
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    gint remmina_pref_get_sshtunnel_port(void)
    -
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    +
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    -
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    const gchar * remmina_file_get_filename(RemminaFile *remminafile)
    Definition: remmina_file.c:210
    static gint compare_secret_plugin_init_order(gconstpointer a, gconstpointer b)
    -
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    -
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    +
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    -
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    RemminaPluginType type
    Definition: plugin.h:57
    gboolean(* init)(struct _RemminaSecretPlugin *instance)
    Definition: plugin.h:143
    -
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    -
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    +
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    +
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    G_BEGIN_DECLS typedef gboolean(* RemminaPluginFunc)(gchar *name, RemminaPlugin *plugin, gpointer data)
    void remmina_plugin_manager_for_each_plugin(RemminaPluginType type, RemminaPluginFunc func, gpointer data)
    -
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    GtkWidget * rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
    Definition: rcw.c:4506
    void remmina_widget_pool_register(GtkWidget *widget)
    void _remmina_critical(const gchar *fun, const gchar *fmt,...)
    Definition: remmina_log.c:382
    @@ -144,14 +144,14 @@ $(document).ready(function(){initNavTree('remmina__plugin__manager_8c_source.htm
    void _remmina_warning(const gchar *fun, const gchar *fmt,...)
    Definition: remmina_log.c:286
    RemminaFilePlugin * remmina_plugin_manager_get_import_file_handler(const gchar *file)
    RemminaSecretPlugin * remmina_plugin_manager_get_secret_plugin(void)
    -
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    -
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    void _remmina_audit(const gchar *fun, const gchar *fmt,...)
    Definition: remmina_log.c:313
    -
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    +
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    gdouble remmina_file_get_double(RemminaFile *remminafile, const gchar *setting, gdouble default_value)
    Definition: remmina_file.c:629
    -
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    void remmina_pref_set_value(const gchar *key, const gchar *value)
    const gchar * description
    Definition: plugin.h:59
    @@ -159,95 +159,95 @@ $(document).ready(function(){initNavTree('remmina__plugin__manager_8c_source.htm
    gboolean(* load)(struct _RemminaLanguageWrapperPlugin *instance, const gchar *plugin_file)
    Definition: plugin.h:159
    void _remmina_debug(const gchar *fun, const gchar *fmt,...)
    Print a string in the Remmina Debug Windows and in the terminal.
    Definition: remmina_log.c:259
    -
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    -
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    +
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    +
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    static gboolean remmina_plugin_manager_show_for_each(RemminaPlugin *plugin, GtkListStore *store)
    gchar * remmina_pref_get_value(const gchar *key)
    gboolean remmina_pref_get_ssh_parseconfig(void)
    -
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    +
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    const char * get_filename_ext(const char *filename)
    -
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    +
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    void remmina_plugin_manager_show(GtkWindow *parent)
    gboolean remmina_masterthread_exec_is_main_thread()
    guint * remmina_pref_keymap_get_table(const gchar *keymap)
    -
    void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
    +
    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_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    RemminaProtocolFeatureType type
    Definition: types.h:73
    gboolean(* export_test_func)(struct _RemminaFilePlugin *instance, RemminaFile *file)
    Definition: plugin.h:109
    const gchar * name
    Definition: plugin.h:137
    -
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    +
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    gboolean remmina_plugin_manager_query_feature_by_type(RemminaPluginType ptype, const gchar *name, RemminaProtocolFeatureType ftype)
    -
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    void remmina_file_set_int(RemminaFile *remminafile, const gchar *setting, gint value)
    Definition: remmina_file.c:585
    -
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    gboolean remmina_gtksocket_available()
    -
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    const gchar ** supported_extentions
    Definition: plugin.h:156
    const RemminaProtocolSetting * basic_settings
    Definition: plugin.h:74
    -
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    +
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    void remmina_plugin_manager_init()
    gchar * remmina_file_get_datadir(void)
    Return datadir_path from pref or first found data dir as per XDG specs.
    -
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    -
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    +
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    void _remmina_info(const gchar *fmt,...)
    Definition: remmina_log.c:206
    RemminaProtocolFeatureType
    Definition: types.h:46
    -
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    +
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    RemminaProtocolSettingType type
    Definition: types.h:118
    -
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    +
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    RemminaFile * remmina_file_new(void)
    Definition: remmina_file.c:93
    guint remmina_pref_keymap_get_keyval(const gchar *keymap, guint keyval)
    -
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    RemminaPluginType type
    Definition: plugin.h:101
    gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
    Definition: remmina_file.c:603
    -
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    +
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    gboolean(* import_test_func)(struct _RemminaFilePlugin *instance, const gchar *from_file)
    Definition: plugin.h:107
    RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
    -
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    static GPtrArray * remmina_plugin_table
    -
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    const gchar * name
    Definition: plugin.h:67
    -
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    static gint remmina_plugin_manager_compare_func(RemminaPlugin **a, RemminaPlugin **b)
    const RemminaProtocolSetting * advanced_settings
    Definition: plugin.h:75
    RemminaPluginType
    Definition: plugin.h:46
    static GHashTable * encrypted_settings_cache
    -
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    +
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    void remmina_log_printf(const gchar *fmt,...)
    Definition: remmina_log.c:411
    static gboolean remmina_plugin_manager_show_for_each_stdout(RemminaPlugin *plugin)
    void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
    Definition: remmina_file.c:469
    -
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    +
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    void remmina_log_print(const gchar *text)
    Definition: remmina_log.c:197
    void _remmina_message(const gchar *fmt,...)
    Definition: remmina_log.c:230
    void remmina_file_unsave_passwords(RemminaFile *remminafile)
    Definition: remmina_file.c:978
    -
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    void remmina_public_get_server_port(const gchar *server, gint defaultport, gchar **host, gint *port)
    static gboolean remmina_plugin_manager_register_plugin(RemminaPlugin *plugin)
    void remmina_plugin_manager_show_stdout()
    -
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    +
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    static void init_settings_cache(RemminaPlugin *plugin)
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    gint remmina_public_open_unix_sock(const char *unixsock)
    Return a file descriptor handle for a unix socket.
    -
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    +
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    const gchar * name
    Definition: plugin.h:58
    -
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    void _remmina_error(const gchar *fun, const gchar *fmt,...)
    Definition: remmina_log.c:355
    const gchar * name
    Definition: types.h:119
    diff --git a/public/remmina__protocol__widget_8c.html b/public/remmina__protocol__widget_8c.html index d0373b12c..9cc1e599f 100644 --- a/public/remmina__protocol__widget_8c.html +++ b/public/remmina__protocol__widget_8c.html @@ -139,6 +139,8 @@ Functions   void remmina_protocol_widget_open_connection (RemminaProtocolWidget *gp)   +static gboolean conn_closed_real (gpointer data, int button) +  static gboolean conn_closed (gpointer data)   void remmina_protocol_widget_signal_connection_closed (RemminaProtocolWidget *gp) @@ -380,7 +382,7 @@ Variables RPWDT_AUTHX509  -

    Definition at line 104 of file remmina_protocol_widget.c.

    +

    Definition at line 105 of file remmina_protocol_widget.c.

    @@ -419,7 +421,7 @@ Variables
    -

    Definition at line 1500 of file remmina_protocol_widget.c.

    +

    Definition at line 1526 of file remmina_protocol_widget.c.

    @@ -457,7 +459,7 @@ Variables
    -

    Definition at line 1297 of file remmina_protocol_widget.c.

    +

    Definition at line 1323 of file remmina_protocol_widget.c.

    @@ -495,7 +497,7 @@ Variables
    -

    Definition at line 912 of file remmina_protocol_widget.c.

    +

    Definition at line 938 of file remmina_protocol_widget.c.

    @@ -533,7 +535,7 @@ Variables
    -

    Definition at line 309 of file remmina_protocol_widget.c.

    +

    Definition at line 311 of file remmina_protocol_widget.c.

    @@ -571,7 +573,7 @@ Variables
    -

    Definition at line 1021 of file remmina_protocol_widget.c.

    +

    Definition at line 1047 of file remmina_protocol_widget.c.

    @@ -609,7 +611,7 @@ Variables
    -

    Definition at line 1157 of file remmina_protocol_widget.c.

    +

    Definition at line 1183 of file remmina_protocol_widget.c.

    @@ -637,7 +639,45 @@ Variables
    -

    Definition at line 344 of file remmina_protocol_widget.c.

    +

    Definition at line 362 of file remmina_protocol_widget.c.

    + +
    + + +

    ◆ conn_closed_real()

    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    static gboolean conn_closed_real (gpointer data,
    int button 
    )
    +
    +static
    +
    + +

    Definition at line 346 of file remmina_protocol_widget.c.

    @@ -665,7 +705,7 @@ Variables
    -

    Definition at line 369 of file remmina_protocol_widget.c.

    +

    Definition at line 394 of file remmina_protocol_widget.c.

    @@ -693,7 +733,7 @@ Variables
    -

    Definition at line 452 of file remmina_protocol_widget.c.

    +

    Definition at line 477 of file remmina_protocol_widget.c.

    @@ -729,7 +769,7 @@ Variables
    -

    Definition at line 110 of file remmina_protocol_widget.c.

    +

    Definition at line 111 of file remmina_protocol_widget.c.

    @@ -757,7 +797,7 @@ Variables
    -

    Definition at line 420 of file remmina_protocol_widget.c.

    +

    Definition at line 445 of file remmina_protocol_widget.c.

    @@ -787,7 +827,7 @@ Variables
    -

    Definition at line 811 of file remmina_protocol_widget.c.

    +

    Definition at line 837 of file remmina_protocol_widget.c.

    @@ -823,7 +863,7 @@ Variables
    -

    Definition at line 798 of file remmina_protocol_widget.c.

    +

    Definition at line 824 of file remmina_protocol_widget.c.

    @@ -843,7 +883,7 @@ Variables
    -

    Definition at line 2029 of file remmina_protocol_widget.c.

    +

    Definition at line 2055 of file remmina_protocol_widget.c.

    @@ -871,7 +911,7 @@ Variables
    -

    Definition at line 2007 of file remmina_protocol_widget.c.

    +

    Definition at line 2033 of file remmina_protocol_widget.c.

    @@ -913,7 +953,7 @@ Variables
    -

    Definition at line 2013 of file remmina_protocol_widget.c.

    +

    Definition at line 2039 of file remmina_protocol_widget.c.

    @@ -943,7 +983,7 @@ Variables
    -

    Definition at line 2036 of file remmina_protocol_widget.c.

    +

    Definition at line 2062 of file remmina_protocol_widget.c.

    @@ -971,7 +1011,7 @@ Variables
    -

    Definition at line 130 of file remmina_protocol_widget.c.

    +

    Definition at line 131 of file remmina_protocol_widget.c.

    @@ -999,7 +1039,7 @@ Variables
    -

    Definition at line 154 of file remmina_protocol_widget.c.

    +

    Definition at line 155 of file remmina_protocol_widget.c.

    @@ -1019,7 +1059,7 @@ Variables
    -

    Definition at line 469 of file remmina_protocol_widget.c.

    +

    Definition at line 494 of file remmina_protocol_widget.c.

    @@ -1039,7 +1079,7 @@ Variables
    -

    Definition at line 461 of file remmina_protocol_widget.c.

    +

    Definition at line 486 of file remmina_protocol_widget.c.

    @@ -1077,7 +1117,7 @@ Variables
    -

    Definition at line 172 of file remmina_protocol_widget.c.

    +

    Definition at line 173 of file remmina_protocol_widget.c.

    @@ -1151,7 +1191,7 @@ Variables
    -

    Definition at line 1612 of file remmina_protocol_widget.c.

    +

    Definition at line 1638 of file remmina_protocol_widget.c.

    @@ -1179,7 +1219,7 @@ Variables
    -

    Definition at line 1533 of file remmina_protocol_widget.c.

    +

    Definition at line 1559 of file remmina_protocol_widget.c.

    @@ -1209,7 +1249,7 @@ Variables
    -

    Definition at line 748 of file remmina_protocol_widget.c.

    +

    Definition at line 774 of file remmina_protocol_widget.c.

    @@ -1229,7 +1269,7 @@ Variables
    -

    Definition at line 1854 of file remmina_protocol_widget.c.

    +

    Definition at line 1880 of file remmina_protocol_widget.c.

    @@ -1249,7 +1289,7 @@ Variables
    -

    Definition at line 1863 of file remmina_protocol_widget.c.

    +

    Definition at line 1889 of file remmina_protocol_widget.c.

    @@ -1269,7 +1309,7 @@ Variables
    -

    Definition at line 1872 of file remmina_protocol_widget.c.

    +

    Definition at line 1898 of file remmina_protocol_widget.c.

    @@ -1289,7 +1329,7 @@ Variables
    -

    Definition at line 1881 of file remmina_protocol_widget.c.

    +

    Definition at line 1907 of file remmina_protocol_widget.c.

    @@ -1309,7 +1349,7 @@ Variables
    -

    Definition at line 1413 of file remmina_protocol_widget.c.

    +

    Definition at line 1439 of file remmina_protocol_widget.c.

    @@ -1329,7 +1369,7 @@ Variables
    -

    Definition at line 1842 of file remmina_protocol_widget.c.

    +

    Definition at line 1868 of file remmina_protocol_widget.c.

    @@ -1349,7 +1389,7 @@ Variables
    -

    Definition at line 1444 of file remmina_protocol_widget.c.

    +

    Definition at line 1470 of file remmina_protocol_widget.c.

    @@ -1369,7 +1409,7 @@ Variables
    -

    Definition at line 1425 of file remmina_protocol_widget.c.

    +

    Definition at line 1451 of file remmina_protocol_widget.c.

    @@ -1389,7 +1429,7 @@ Variables
    -

    Definition at line 769 of file remmina_protocol_widget.c.

    +

    Definition at line 795 of file remmina_protocol_widget.c.

    @@ -1409,7 +1449,7 @@ Variables
    -

    Definition at line 1476 of file remmina_protocol_widget.c.

    +

    Definition at line 1502 of file remmina_protocol_widget.c.

    @@ -1429,7 +1469,7 @@ Variables
    -

    Definition at line 2083 of file remmina_protocol_widget.c.

    +

    Definition at line 2109 of file remmina_protocol_widget.c.

    @@ -1449,7 +1489,7 @@ Variables
    -

    Definition at line 1401 of file remmina_protocol_widget.c.

    +

    Definition at line 1427 of file remmina_protocol_widget.c.

    @@ -1469,7 +1509,7 @@ Variables
    -

    Definition at line 1367 of file remmina_protocol_widget.c.

    +

    Definition at line 1393 of file remmina_protocol_widget.c.

    @@ -1489,7 +1529,7 @@ Variables
    -

    Definition at line 1383 of file remmina_protocol_widget.c.

    +

    Definition at line 1409 of file remmina_protocol_widget.c.

    @@ -1509,7 +1549,7 @@ Variables
    -

    Definition at line 1836 of file remmina_protocol_widget.c.

    +

    Definition at line 1862 of file remmina_protocol_widget.c.

    @@ -1529,7 +1569,7 @@ Variables
    -

    Definition at line 1376 of file remmina_protocol_widget.c.

    +

    Definition at line 1402 of file remmina_protocol_widget.c.

    @@ -1549,7 +1589,7 @@ Variables
    -

    Definition at line 1360 of file remmina_protocol_widget.c.

    +

    Definition at line 1386 of file remmina_protocol_widget.c.

    @@ -1569,7 +1609,7 @@ Variables
    -

    Definition at line 1848 of file remmina_protocol_widget.c.

    +

    Definition at line 1874 of file remmina_protocol_widget.c.

    @@ -1589,7 +1629,7 @@ Variables
    -

    Definition at line 1830 of file remmina_protocol_widget.c.

    +

    Definition at line 1856 of file remmina_protocol_widget.c.

    @@ -1609,7 +1649,7 @@ Variables
    -

    Definition at line 1389 of file remmina_protocol_widget.c.

    +

    Definition at line 1415 of file remmina_protocol_widget.c.

    @@ -1629,7 +1669,7 @@ Variables
    -

    Definition at line 217 of file remmina_protocol_widget.c.

    +

    Definition at line 218 of file remmina_protocol_widget.c.

    @@ -1649,7 +1689,7 @@ Variables
    -

    Definition at line 2088 of file remmina_protocol_widget.c.

    +

    Definition at line 2114 of file remmina_protocol_widget.c.

    @@ -1669,7 +1709,7 @@ Variables
    -

    Definition at line 1438 of file remmina_protocol_widget.c.

    +

    Definition at line 1464 of file remmina_protocol_widget.c.

    @@ -1697,7 +1737,7 @@ Variables
    -

    Definition at line 230 of file remmina_protocol_widget.c.

    +

    Definition at line 231 of file remmina_protocol_widget.c.

    @@ -1725,7 +1765,7 @@ Variables
    -

    Definition at line 917 of file remmina_protocol_widget.c.

    +

    Definition at line 943 of file remmina_protocol_widget.c.

    @@ -1745,7 +1785,7 @@ Variables
    -

    Definition at line 1470 of file remmina_protocol_widget.c.

    +

    Definition at line 1496 of file remmina_protocol_widget.c.

    @@ -1765,7 +1805,7 @@ Variables
    -

    Definition at line 438 of file remmina_protocol_widget.c.

    +

    Definition at line 463 of file remmina_protocol_widget.c.

    @@ -1785,7 +1825,7 @@ Variables
    -

    Definition at line 724 of file remmina_protocol_widget.c.

    +

    Definition at line 750 of file remmina_protocol_widget.c.

    @@ -1815,7 +1855,7 @@ Variables
    -

    Definition at line 895 of file remmina_protocol_widget.c.

    +

    Definition at line 921 of file remmina_protocol_widget.c.

    @@ -1857,7 +1897,7 @@ Variables
    -

    Definition at line 870 of file remmina_protocol_widget.c.

    +

    Definition at line 896 of file remmina_protocol_widget.c.

    @@ -1877,7 +1917,7 @@ Variables
    -

    Definition at line 2093 of file remmina_protocol_widget.c.

    +

    Definition at line 2119 of file remmina_protocol_widget.c.

    @@ -1921,7 +1961,7 @@ Variables
    -

    Definition at line 840 of file remmina_protocol_widget.c.

    +

    Definition at line 866 of file remmina_protocol_widget.c.

    @@ -1965,7 +2005,7 @@ Variables
    -

    Definition at line 848 of file remmina_protocol_widget.c.

    +

    Definition at line 874 of file remmina_protocol_widget.c.

    @@ -1985,7 +2025,7 @@ Variables
    -

    Definition at line 316 of file remmina_protocol_widget.c.

    +

    Definition at line 318 of file remmina_protocol_widget.c.

    @@ -2005,7 +2045,7 @@ Variables
    -

    Definition at line 243 of file remmina_protocol_widget.c.

    +

    Definition at line 245 of file remmina_protocol_widget.c.

    @@ -2065,7 +2105,7 @@ Variables
    -

    Definition at line 1694 of file remmina_protocol_widget.c.

    +

    Definition at line 1720 of file remmina_protocol_widget.c.

    @@ -2101,7 +2141,7 @@ Variables
    -

    Definition at line 1702 of file remmina_protocol_widget.c.

    +

    Definition at line 1728 of file remmina_protocol_widget.c.

    @@ -2121,7 +2161,7 @@ Variables
    -

    Definition at line 1756 of file remmina_protocol_widget.c.

    +

    Definition at line 1782 of file remmina_protocol_widget.c.

    @@ -2169,7 +2209,7 @@ Variables
    -

    Definition at line 1796 of file remmina_protocol_widget.c.

    +

    Definition at line 1822 of file remmina_protocol_widget.c.

    @@ -2189,7 +2229,7 @@ Variables
    -

    Definition at line 2001 of file remmina_protocol_widget.c.

    +

    Definition at line 2027 of file remmina_protocol_widget.c.

    @@ -2231,7 +2271,7 @@ Variables
    -

    Definition at line 1764 of file remmina_protocol_widget.c.

    +

    Definition at line 1790 of file remmina_protocol_widget.c.

    @@ -2261,7 +2301,7 @@ Variables
    -

    Definition at line 1689 of file remmina_protocol_widget.c.

    +

    Definition at line 1715 of file remmina_protocol_widget.c.

    @@ -2281,7 +2321,7 @@ Variables
    -

    Definition at line 1995 of file remmina_protocol_widget.c.

    +

    Definition at line 2021 of file remmina_protocol_widget.c.

    @@ -2311,7 +2351,7 @@ Variables
    -

    Definition at line 1944 of file remmina_protocol_widget.c.

    +

    Definition at line 1970 of file remmina_protocol_widget.c.

    @@ -2331,7 +2371,7 @@ Variables
    -

    Definition at line 1973 of file remmina_protocol_widget.c.

    +

    Definition at line 1999 of file remmina_protocol_widget.c.

    @@ -2353,7 +2393,7 @@ Variables

    Check if the plugin accepts keystrokes.

    -

    Definition at line 504 of file remmina_protocol_widget.c.

    +

    Definition at line 530 of file remmina_protocol_widget.c.

    @@ -2383,7 +2423,7 @@ Variables
    -

    Definition at line 713 of file remmina_protocol_widget.c.

    +

    Definition at line 739 of file remmina_protocol_widget.c.

    @@ -2413,7 +2453,7 @@ Variables
    -

    Definition at line 792 of file remmina_protocol_widget.c.

    +

    Definition at line 818 of file remmina_protocol_widget.c.

    @@ -2443,7 +2483,7 @@ Variables
    -

    Definition at line 775 of file remmina_protocol_widget.c.

    +

    Definition at line 801 of file remmina_protocol_widget.c.

    @@ -2473,7 +2513,7 @@ Variables
    -

    Definition at line 857 of file remmina_protocol_widget.c.

    +

    Definition at line 883 of file remmina_protocol_widget.c.

    @@ -2493,7 +2533,7 @@ Variables
    -

    Definition at line 1890 of file remmina_protocol_widget.c.

    +

    Definition at line 1916 of file remmina_protocol_widget.c.

    @@ -2531,7 +2571,7 @@ Variables

    Send to the plugin some keystrokes from the content of the clipboard This is a copy of remmina_protocol_widget_send_keystrokes but it uses the clipboard content get from remmina_protocol_widget_send_clipboard Probably we don't need the replacement table.

    -

    Definition at line 603 of file remmina_protocol_widget.c.

    +

    Definition at line 629 of file remmina_protocol_widget.c.

    @@ -2561,7 +2601,7 @@ Variables
    -

    Definition at line 699 of file remmina_protocol_widget.c.

    +

    Definition at line 725 of file remmina_protocol_widget.c.

    @@ -2603,7 +2643,7 @@ Variables
    -

    Definition at line 2102 of file remmina_protocol_widget.c.

    +

    Definition at line 2128 of file remmina_protocol_widget.c.

    @@ -2635,7 +2675,7 @@ Variables

    Send to the plugin some keystrokes.

    -

    Definition at line 512 of file remmina_protocol_widget.c.

    +

    Definition at line 538 of file remmina_protocol_widget.c.

    @@ -2665,7 +2705,7 @@ Variables
    -

    Definition at line 1419 of file remmina_protocol_widget.c.

    +

    Definition at line 1445 of file remmina_protocol_widget.c.

    @@ -2695,7 +2735,7 @@ Variables
    -

    Definition at line 1347 of file remmina_protocol_widget.c.

    +

    Definition at line 1373 of file remmina_protocol_widget.c.

    @@ -2731,7 +2771,7 @@ Variables
    -

    Definition at line 1450 of file remmina_protocol_widget.c.

    +

    Definition at line 1476 of file remmina_protocol_widget.c.

    @@ -2761,7 +2801,7 @@ Variables
    -

    Definition at line 1431 of file remmina_protocol_widget.c.

    +

    Definition at line 1457 of file remmina_protocol_widget.c.

    @@ -2791,7 +2831,7 @@ Variables
    -

    Definition at line 1407 of file remmina_protocol_widget.c.

    +

    Definition at line 1433 of file remmina_protocol_widget.c.

    @@ -2821,7 +2861,7 @@ Variables
    -

    Definition at line 864 of file remmina_protocol_widget.c.

    +

    Definition at line 890 of file remmina_protocol_widget.c.

    @@ -2851,7 +2891,7 @@ Variables
    -

    Definition at line 1395 of file remmina_protocol_widget.c.

    +

    Definition at line 1421 of file remmina_protocol_widget.c.

    @@ -2887,7 +2927,7 @@ Variables
    -

    Definition at line 2058 of file remmina_protocol_widget.c.

    +

    Definition at line 2084 of file remmina_protocol_widget.c.

    @@ -2907,7 +2947,7 @@ Variables
    -

    Definition at line 360 of file remmina_protocol_widget.c.

    +

    Definition at line 384 of file remmina_protocol_widget.c.

    @@ -2927,7 +2967,7 @@ Variables
    -

    Definition at line 396 of file remmina_protocol_widget.c.

    +

    Definition at line 421 of file remmina_protocol_widget.c.

    @@ -2969,7 +3009,7 @@ Variables
    -

    Definition at line 1195 of file remmina_protocol_widget.c.

    +

    Definition at line 1221 of file remmina_protocol_widget.c.

    @@ -3007,7 +3047,7 @@ Variables

    Start an SSH tunnel if possible and return the host:port string.

    -

    Definition at line 1062 of file remmina_protocol_widget.c.

    +

    Definition at line 1088 of file remmina_protocol_widget.c.

    @@ -3037,7 +3077,7 @@ Variables
    -

    Definition at line 1164 of file remmina_protocol_widget.c.

    +

    Definition at line 1190 of file remmina_protocol_widget.c.

    @@ -3067,7 +3107,7 @@ Variables
    -

    Definition at line 1302 of file remmina_protocol_widget.c.

    +

    Definition at line 1328 of file remmina_protocol_widget.c.

    @@ -3105,7 +3145,7 @@ Variables
    -

    Definition at line 1026 of file remmina_protocol_widget.c.

    +

    Definition at line 1052 of file remmina_protocol_widget.c.

    @@ -3125,7 +3165,7 @@ Variables
    -

    Definition at line 445 of file remmina_protocol_widget.c.

    +

    Definition at line 470 of file remmina_protocol_widget.c.

    @@ -3145,7 +3185,7 @@ Variables
    -

    Definition at line 736 of file remmina_protocol_widget.c.

    +

    Definition at line 762 of file remmina_protocol_widget.c.

    @@ -3165,7 +3205,7 @@ Variables
    -

    Definition at line 413 of file remmina_protocol_widget.c.

    +

    Definition at line 438 of file remmina_protocol_widget.c.

    @@ -3185,7 +3225,7 @@ Variables
    -

    Definition at line 2142 of file remmina_protocol_widget.c.

    +

    Definition at line 2168 of file remmina_protocol_widget.c.

    @@ -3223,7 +3263,7 @@ Variables
    -

    Definition at line 1278 of file remmina_protocol_widget.c.

    +

    Definition at line 1304 of file remmina_protocol_widget.c.

    @@ -3261,7 +3301,7 @@ Variables
    -

    Definition at line 1284 of file remmina_protocol_widget.c.

    +

    Definition at line 1310 of file remmina_protocol_widget.c.

    @@ -3299,7 +3339,7 @@ Variables
    -

    Definition at line 1261 of file remmina_protocol_widget.c.

    +

    Definition at line 1287 of file remmina_protocol_widget.c.

    @@ -3337,7 +3377,7 @@ Variables
    -

    Definition at line 1603 of file remmina_protocol_widget.c.

    +

    Definition at line 1629 of file remmina_protocol_widget.c.

    @@ -3381,7 +3421,7 @@ Variables
    -

    Definition at line 1587 of file remmina_protocol_widget.c.

    +

    Definition at line 1613 of file remmina_protocol_widget.c.

    @@ -3419,7 +3459,7 @@ Variables
    -

    Definition at line 1595 of file remmina_protocol_widget.c.

    +

    Definition at line 1621 of file remmina_protocol_widget.c.

    @@ -3447,7 +3487,7 @@ Variables
    -

    Definition at line 1581 of file remmina_protocol_widget.c.

    +

    Definition at line 1607 of file remmina_protocol_widget.c.

    @@ -3475,7 +3515,7 @@ Variables
    -

    Definition at line 429 of file remmina_protocol_widget.c.

    +

    Definition at line 454 of file remmina_protocol_widget.c.

    @@ -3503,7 +3543,7 @@ Variables
    -

    Definition at line 404 of file remmina_protocol_widget.c.

    +

    Definition at line 429 of file remmina_protocol_widget.c.

    @@ -3528,7 +3568,7 @@ Variables
    Initial value:
    =
    { 0 }
    -

    Definition at line 127 of file remmina_protocol_widget.c.

    +

    Definition at line 128 of file remmina_protocol_widget.c.

    diff --git a/public/remmina__protocol__widget_8c.js b/public/remmina__protocol__widget_8c.js index db015c389..df7c47149 100644 --- a/public/remmina__protocol__widget_8c.js +++ b/public/remmina__protocol__widget_8c.js @@ -17,6 +17,7 @@ var remmina__protocol__widget_8c = [ "cancel_start_direct_tunnel_cb", "remmina__protocol__widget_8c.html#a0a93da80662ff18b93270ced59243ce3", null ], [ "cancel_start_reverse_tunnel_cb", "remmina__protocol__widget_8c.html#aeffe07c6412286d99ba04f05fe74aeac", null ], [ "conn_closed", "remmina__protocol__widget_8c.html#a69757e0c39fa9fcf31800f6375772016", null ], + [ "conn_closed_real", "remmina__protocol__widget_8c.html#aa905484fffd7eaa072b834db6ffb642c", null ], [ "conn_opened", "remmina__protocol__widget_8c.html#af4a20ef0ff8cc86feeba345498179e48", null ], [ "desktop_resize", "remmina__protocol__widget_8c.html#aeaf728bb767c1bbdda6a0d8dc3553565", null ], [ "G_DEFINE_TYPE", "remmina__protocol__widget_8c.html#a247c73c70d9c58427022a4dbcd638d32", null ], diff --git a/public/remmina__protocol__widget_8c_source.html b/public/remmina__protocol__widget_8c_source.html index 744305d00..3b4a1b142 100644 --- a/public/remmina__protocol__widget_8c_source.html +++ b/public/remmina__protocol__widget_8c_source.html @@ -86,140 +86,140 @@ $(document).ready(function(){initNavTree('remmina__protocol__widget_8c_source.ht
    remmina_protocol_widget.c
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2009-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #include "config.h"
    38 
    39 #include <gtk/gtk.h>
    40 #include <gtk/gtkx.h>
    41 #include <glib/gi18n.h>
    42 #include <gmodule.h>
    43 #include <stdlib.h>
    44 
    45 #include "remmina_chat_window.h"
    47 #include "remmina_ext_exec.h"
    48 #include "remmina_plugin_manager.h"
    49 #include "remmina_pref.h"
    51 #include "remmina_public.h"
    52 #include "remmina_ssh.h"
    53 #include "remmina_log.h"
    55 
    56 #ifdef GDK_WINDOWING_WAYLAND
    57 #include <gdk/gdkwayland.h>
    58 #endif
    59 
    64 
    65  gint width;
    66  gint height;
    68  gboolean scaler_expand;
    69 
    70  gboolean has_error;
    71  gchar * error_message;
    72  /* ssh_tunnels is an array of RemminaSSHTunnel*
    73  * the 1st one is the "main" tunnel, other tunnels are used for example in sftp commands */
    74  GPtrArray * ssh_tunnels;
    76 
    77  GtkWidget * chat_window;
    78 
    79  gboolean closed;
    80 
    82 
    85  gint multimon;
    86 
    87  RemminaMessagePanel * connect_message_panel;
    88  RemminaMessagePanel * listen_message_panel;
    89  RemminaMessagePanel * auth_message_panel;
    90  RemminaMessagePanel * retry_message_panel;
    91 
    92  /* Data saved from the last message_panel when the user confirm */
    93  gchar * username;
    94  gchar * password;
    95  gchar * domain;
    96  gboolean save_password;
    97 
    98  gchar * cacert;
    99  gchar * cacrl;
    100  gchar * clientcert;
    101  gchar * clientkey;
    102 };
    103 
    108 };
    109 
    110 G_DEFINE_TYPE(RemminaProtocolWidget, remmina_protocol_widget, GTK_TYPE_EVENT_BOX)
    111 
    112 enum {
    113  CONNECT_SIGNAL,
    114  DISCONNECT_SIGNAL,
    115  DESKTOP_RESIZE_SIGNAL,
    116  UPDATE_ALIGN_SIGNAL,
    117  LOCK_DYNRES_SIGNAL,
    118  UNLOCK_DYNRES_SIGNAL,
    120 };
    121 
    124  const gchar * signal_name;
    126 
    128 { 0 };
    129 
    131 {
    132  TRACE_CALL(__func__);
    133  remmina_protocol_widget_signals[CONNECT_SIGNAL] = g_signal_new("connect", G_TYPE_FROM_CLASS(klass),
    134  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, connect), NULL, NULL,
    135  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    136  remmina_protocol_widget_signals[DISCONNECT_SIGNAL] = g_signal_new("disconnect", G_TYPE_FROM_CLASS(klass),
    137  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, disconnect), NULL, NULL,
    138  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    139  remmina_protocol_widget_signals[DESKTOP_RESIZE_SIGNAL] = g_signal_new("desktop-resize", G_TYPE_FROM_CLASS(klass),
    140  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, desktop_resize), NULL, NULL,
    141  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    142  remmina_protocol_widget_signals[UPDATE_ALIGN_SIGNAL] = g_signal_new("update-align", G_TYPE_FROM_CLASS(klass),
    143  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, update_align), NULL, NULL,
    144  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    145  remmina_protocol_widget_signals[LOCK_DYNRES_SIGNAL] = g_signal_new("lock-dynres", G_TYPE_FROM_CLASS(klass),
    146  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, lock_dynres), NULL, NULL,
    147  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    148  remmina_protocol_widget_signals[UNLOCK_DYNRES_SIGNAL] = g_signal_new("unlock-dynres", G_TYPE_FROM_CLASS(klass),
    149  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, unlock_dynres), NULL, NULL,
    150  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    151 }
    152 
    153 
    155 {
    156  TRACE_CALL(__func__);
    157  int i;
    158 
    159  if (gp->priv && gp->priv->ssh_tunnels) {
    160  for (i = 0; i < gp->priv->ssh_tunnels->len; i++) {
    161 #ifdef HAVE_LIBSSH
    163 #else
    164  REMMINA_DEBUG("LibSSH support turned off, no need to free SSH tunnel data");
    165 #endif
    166  }
    167  g_ptr_array_set_size(gp->priv->ssh_tunnels, 0);
    168  }
    169 }
    170 
    171 
    173 {
    174  TRACE_CALL(__func__);
    175 
    176  g_free(gp->priv->username);
    177  gp->priv->username = NULL;
    178 
    179  g_free(gp->priv->password);
    180  gp->priv->password = NULL;
    181 
    182  g_free(gp->priv->domain);
    183  gp->priv->domain = NULL;
    184 
    185  g_free(gp->priv->cacert);
    186  gp->priv->cacert = NULL;
    187 
    188  g_free(gp->priv->cacrl);
    189  gp->priv->cacrl = NULL;
    190 
    191  g_free(gp->priv->clientcert);
    192  gp->priv->clientcert = NULL;
    193 
    194  g_free(gp->priv->clientkey);
    195  gp->priv->clientkey = NULL;
    196 
    197  g_free(gp->priv->features);
    198  gp->priv->features = NULL;
    199 
    200  g_free(gp->priv->error_message);
    201  gp->priv->error_message = NULL;
    202 
    203  g_free(gp->priv->remmina_file);
    204  gp->priv->remmina_file = NULL;
    205 
    206  g_free(gp->priv);
    207  gp->priv = NULL;
    208 
    210 
    211  if (gp->priv && gp->priv->ssh_tunnels) {
    212  g_ptr_array_free(gp->priv->ssh_tunnels, TRUE);
    213  gp->priv->ssh_tunnels = NULL;
    214  }
    215 }
    216 
    218 {
    219  TRACE_CALL(__func__);
    220  GtkWidget *child;
    221 
    222  child = gtk_bin_get_child(GTK_BIN(gp));
    223 
    224  if (child) {
    225  gtk_widget_set_can_focus(child, TRUE);
    226  gtk_widget_grab_focus(child);
    227  }
    228 }
    229 
    231 {
    232  TRACE_CALL(__func__);
    234 
    235  priv = g_new0(RemminaProtocolWidgetPriv, 1);
    236  gp->priv = priv;
    237  gp->priv->closed = TRUE;
    238  gp->priv->ssh_tunnels = g_ptr_array_new();
    239 
    240  g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL);
    241 }
    242 
    244 {
    245  TRACE_CALL(__func__);
    246  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    247 
    248  REMMINA_DEBUG("Opening connection");
    249 
    251  RemminaProtocolFeature *feature;
    252  gint num_plugin;
    253  gint num_ssh;
    254 
    255  gp->priv->closed = FALSE;
    256 
    257  plugin = gp->priv->plugin;
    258  plugin->init(gp);
    259 
    260  for (num_plugin = 0, feature = (RemminaProtocolFeature *)plugin->features; feature && feature->type; num_plugin++, feature++) {
    261  }
    262 
    263  num_ssh = 0;
    264 #ifdef HAVE_LIBSSH
    265  if (remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    266  num_ssh += 2;
    267 
    268 #endif
    269  if (num_plugin + num_ssh == 0) {
    270  gp->priv->features = NULL;
    271  } else {
    272  gp->priv->features = g_new0(RemminaProtocolFeature, num_plugin + num_ssh + 1);
    273  feature = gp->priv->features;
    274  if (plugin->features) {
    275  memcpy(feature, plugin->features, sizeof(RemminaProtocolFeature) * num_plugin);
    276  feature += num_plugin;
    277  }
    278 #ifdef HAVE_LIBSSH
    279  REMMINA_DEBUG("Have SSH");
    280  if (num_ssh) {
    282  feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SSH;
    283  feature->opt1 = _("Connect via SSH from a new terminal");
    285  feature->opt2 = "utilities-terminal";
    287  feature->opt3 = NULL;
    289  feature++;
    290 
    292  feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SFTP;
    293  feature->opt1 = _("Open SFTP transfer…");
    295  feature->opt2 = "folder-remote";
    297  feature->opt3 = NULL;
    299  feature++;
    300  }
    302 #endif
    303  }
    304 
    305  if (!plugin->open_connection(gp))
    307 }
    308 
    309 static void cancel_open_connection_cb(void *cbdata, int btn)
    310 {
    312 
    314 }
    315 
    317 {
    318  TRACE_CALL(__func__);
    319  gchar *s;
    320  const gchar *name;
    321  RemminaMessagePanel *mp;
    322 
    323  /* Exec precommand before everything else */
    325  remmina_message_panel_setup_progress(mp, _("Executing external commands…"), NULL, NULL);
    327 
    328  remmina_ext_exec_new(gp->priv->remmina_file, "precommand");
    330 
    331  name = remmina_file_get_string(gp->priv->remmina_file, "name");
    332  // TRANSLATORS: “%s” is a placeholder for the connection profile name
    333  s = g_strdup_printf(_("Connecting to “%s”…"), (name ? name : "*"));
    334 
    337  g_free(s);
    338  gp->priv->connect_message_panel = mp;
    340 
    342 }
    343 
    344 static gboolean conn_closed(gpointer data)
    345 {
    346  TRACE_CALL(__func__);
    348 
    349 #ifdef HAVE_LIBSSH
    350  /* This will close all tunnels */
    352 #endif
    353  /* Exec postcommand */
    354  remmina_ext_exec_new(gp->priv->remmina_file, "postcommand");
    355  /* Notify listeners (usually rcw) that the connection is closed */
    356  g_signal_emit_by_name(G_OBJECT(gp), "disconnect");
    357  return G_SOURCE_REMOVE;
    358 }
    359 
    361 {
    362  /* Plugin told us that it closed the connection,
    363  * add async event to main thread to complete our close tasks */
    364  TRACE_CALL(__func__);
    365  gp->priv->closed = TRUE;
    366  g_idle_add(conn_closed, (gpointer)gp);
    367 }
    368 
    369 static gboolean conn_opened(gpointer data)
    370 {
    371  TRACE_CALL(__func__);
    373 
    374 #ifdef HAVE_LIBSSH
    375  if (gp->priv->ssh_tunnels) {
    376  for (guint i = 0; i < gp->priv->ssh_tunnels->len; i++)
    378  }
    379 #endif
    380  if (gp->priv->listen_message_panel) {
    382  gp->priv->listen_message_panel = NULL;
    383  }
    384  if (gp->priv->connect_message_panel) {
    386  gp->priv->connect_message_panel = NULL;
    387  }
    388  if (gp->priv->retry_message_panel) {
    390  gp->priv->retry_message_panel = NULL;
    391  }
    392  g_signal_emit_by_name(G_OBJECT(gp), "connect");
    393  return G_SOURCE_REMOVE;
    394 }
    395 
    397 {
    398  /* Plugin told us that it opened the connection,
    399  * add async event to main thread to complete our close tasks */
    400  TRACE_CALL(__func__);
    401  g_idle_add(conn_opened, (gpointer)gp);
    402 }
    403 
    404 static gboolean update_align(gpointer data)
    405 {
    406  TRACE_CALL(__func__);
    408 
    409  g_signal_emit_by_name(G_OBJECT(gp), "update-align");
    410  return G_SOURCE_REMOVE;
    411 }
    412 
    414 {
    415  /* Called by the plugin to do updates on rcw */
    416  TRACE_CALL(__func__);
    417  g_idle_add(update_align, (gpointer)gp);
    418 }
    419 
    420 static gboolean lock_dynres(gpointer data)
    421 {
    422  TRACE_CALL(__func__);
    424 
    425  g_signal_emit_by_name(G_OBJECT(gp), "lock-dynres");
    426  return G_SOURCE_REMOVE;
    427 }
    428 
    429 static gboolean unlock_dynres(gpointer data)
    430 {
    431  TRACE_CALL(__func__);
    433 
    434  g_signal_emit_by_name(G_OBJECT(gp), "unlock-dynres");
    435  return G_SOURCE_REMOVE;
    436 }
    437 
    439 {
    440  /* Called by the plugin to do updates on rcw */
    441  TRACE_CALL(__func__);
    442  g_idle_add(lock_dynres, (gpointer)gp);
    443 }
    444 
    446 {
    447  /* Called by the plugin to do updates on rcw */
    448  TRACE_CALL(__func__);
    449  g_idle_add(unlock_dynres, (gpointer)gp);
    450 }
    451 
    452 static gboolean desktop_resize(gpointer data)
    453 {
    454  TRACE_CALL(__func__);
    456 
    457  g_signal_emit_by_name(G_OBJECT(gp), "desktop-resize");
    458  return G_SOURCE_REMOVE;
    459 }
    460 
    462 {
    463  /* Called by the plugin to do updates on rcw */
    464  TRACE_CALL(__func__);
    465  g_idle_add(desktop_resize, (gpointer)gp);
    466 }
    467 
    468 
    470 {
    471  TRACE_CALL(__func__);
    472 
    473  /* kindly ask the protocol plugin to close the connection.
    474  * Nothing else is done here. */
    475 
    476  if (!GTK_IS_WIDGET(gp))
    477  return;
    478 
    479  if (gp->priv->chat_window) {
    480  gtk_widget_destroy(gp->priv->chat_window);
    481  gp->priv->chat_window = NULL;
    482  }
    483 
    484  if (gp->priv->closed) {
    485  /* Connection is already closed by the plugin, but
    486  * rcw is asking to close again (usually after an error panel)
    487  */
    488  /* Clear the current error, or "disconnect" signal func will reshow a panel */
    490  g_signal_emit_by_name(G_OBJECT(gp), "disconnect");
    491  return;
    492  }
    493 
    494  /* Ask the plugin to close, async.
    495  * The plugin will emit a "disconnect" signal on gp to call our
    496  * remmina_protocol_widget_on_disconnected() when done */
    497  gp->priv->plugin->close_connection(gp);
    498 
    499  return;
    500 }
    501 
    505 {
    506  return gp->priv->plugin->send_keystrokes ? TRUE : FALSE;
    507 }
    508 
    513 {
    514  TRACE_CALL(__func__);
    515  gchar *keystrokes = g_object_get_data(G_OBJECT(widget), "keystrokes");
    516  guint *keyvals;
    517  gint i;
    518  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    519  gunichar character;
    520  guint keyval;
    521  GdkKeymapKey *keys;
    522  gint n_keys;
    523 
    524  /* Single keystroke replace */
    525  typedef struct _KeystrokeReplace {
    526  gchar * search;
    527  gchar * replace;
    528  guint keyval;
    529  } KeystrokeReplace;
    530  /* Special characters to replace */
    531  KeystrokeReplace keystrokes_replaces[] =
    532  {
    533  { "\\n", "\n", GDK_KEY_Return },
    534  { "\\t", "\t", GDK_KEY_Tab },
    535  { "\\b", "\b", GDK_KEY_BackSpace },
    536  { "\\e", "\e", GDK_KEY_Escape },
    537  { "\\\\", "\\", GDK_KEY_backslash },
    538  { NULL, NULL, 0 }
    539  };
    540 
    541  /* Keystrokes can only be sent to plugins that accepts them */
    543  /* Replace special characters */
    544  for (i = 0; keystrokes_replaces[i].replace; i++) {
    545  REMMINA_DEBUG("Keystrokes before replacement is \'%s\'", keystrokes);
    546  keystrokes = g_strdup(remmina_public_str_replace_in_place(keystrokes,
    547  keystrokes_replaces[i].search,
    548  keystrokes_replaces[i].replace));
    549  REMMINA_DEBUG("Keystrokes after replacement is \'%s\'", keystrokes);
    550  }
    551  gchar *iter = g_strdup(keystrokes);
    552  keyvals = (guint *)g_malloc(strlen(keystrokes));
    553  while (TRUE) {
    554  /* Process each character in the keystrokes */
    555  character = g_utf8_get_char_validated(iter, -1);
    556  if (character == 0)
    557  break;
    558  keyval = gdk_unicode_to_keyval(character);
    559  /* Replace all the special character with its keyval */
    560  for (i = 0; keystrokes_replaces[i].replace; i++) {
    561  if (character == keystrokes_replaces[i].replace[0]) {
    562  keys = g_new0(GdkKeymapKey, 1);
    563  keyval = keystrokes_replaces[i].keyval;
    564  /* A special character was generated, no keyval lookup needed */
    565  character = 0;
    566  break;
    567  }
    568  }
    569  /* Decode character if it’s not a special character */
    570  if (character) {
    571  /* get keyval without modifications */
    572  if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
    573  g_warning("keyval 0x%04x has no keycode!", keyval);
    574  iter = g_utf8_find_next_char(iter, NULL);
    575  continue;
    576  }
    577  }
    578  /* Add modifier keys */
    579  n_keys = 0;
    580  if (keys->level & 1)
    581  keyvals[n_keys++] = GDK_KEY_Shift_L;
    582  if (keys->level & 2)
    583  keyvals[n_keys++] = GDK_KEY_Alt_R;
    584  keyvals[n_keys++] = keyval;
    585  /* Send keystroke to the plugin */
    586  gp->priv->plugin->send_keystrokes(gp, keyvals, n_keys);
    587  g_free(keys);
    588  /* Process next character in the keystrokes */
    589  iter = g_utf8_find_next_char(iter, NULL);
    590  }
    591  g_free(keyvals);
    592  }
    593  g_free(keystrokes);
    594  return;
    595 }
    596 
    603 void remmina_protocol_widget_send_clip_strokes(GtkClipboard *clipboard, const gchar *clip_text, gpointer data)
    604 {
    605  TRACE_CALL(__func__);
    606  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    607  gchar *text = g_utf8_normalize(clip_text, -1, G_NORMALIZE_DEFAULT_COMPOSE);
    608  guint *keyvals;
    609  gint i;
    610  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    611  gunichar character;
    612  guint keyval;
    613  GdkKeymapKey *keys;
    614  gint n_keys;
    615 
    616  /* Single keystroke replace */
    617  typedef struct _KeystrokeReplace {
    618  gchar * search;
    619  gchar * replace;
    620  guint keyval;
    621  } KeystrokeReplace;
    622  /* Special characters to replace */
    623  KeystrokeReplace text_replaces[] =
    624  {
    625  { "\\n", "\n", GDK_KEY_Return },
    626  { "\\t", "\t", GDK_KEY_Tab },
    627  { "\\b", "\b", GDK_KEY_BackSpace },
    628  { "\\e", "\e", GDK_KEY_Escape },
    629  { "\\\\", "\\", GDK_KEY_backslash },
    630  { NULL, NULL, 0 }
    631  };
    632 
    634  if (text) {
    635  /* Replace special characters */
    636  for (i = 0; text_replaces[i].replace; i++) {
    637  REMMINA_DEBUG("Text clipboard before replacement is \'%s\'", text);
    638  text = g_strdup(remmina_public_str_replace_in_place(text,
    639  text_replaces[i].search,
    640  text_replaces[i].replace));
    641  REMMINA_DEBUG("Text clipboard after replacement is \'%s\'", text);
    642  }
    643  gchar *iter = g_strdup(text);
    644  REMMINA_DEBUG("Iter: %s", iter),
    645  keyvals = (guint *)g_malloc(strlen(text));
    646  while (TRUE) {
    647  /* Process each character in the keystrokes */
    648  character = g_utf8_get_char_validated(iter, -1);
    649  REMMINA_DEBUG("Char: U+%04" G_GINT32_FORMAT"X", character);
    650  if (character == 0)
    651  break;
    652  keyval = gdk_unicode_to_keyval(character);
    653  REMMINA_DEBUG("Keyval: %u", keyval);
    654  /* Replace all the special character with its keyval */
    655  for (i = 0; text_replaces[i].replace; i++) {
    656  if (character == text_replaces[i].replace[0]) {
    657  keys = g_new0(GdkKeymapKey, 1);
    658  keyval = text_replaces[i].keyval;
    659  REMMINA_DEBUG("Special Keyval: %u", keyval);
    660  /* A special character was generated, no keyval lookup needed */
    661  character = 0;
    662  break;
    663  }
    664  }
    665  /* Decode character if it’s not a special character */
    666  if (character) {
    667  /* get keyval without modifications */
    668  if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
    669  REMMINA_WARNING("keyval 0x%04x has no keycode!", keyval);
    670  iter = g_utf8_find_next_char(iter, NULL);
    671  continue;
    672  }
    673  }
    674  /* Add modifier keys */
    675  n_keys = 0;
    676  if (keys->level & 1)
    677  keyvals[n_keys++] = GDK_KEY_Shift_L;
    678  if (keys->level & 2)
    679  keyvals[n_keys++] = GDK_KEY_Alt_R;
    680  /*
    681  * @fixme heap buffer overflow
    682  * In some cases, for example sending \t as the only sequence
    683  * may lead to a buffer overflow
    684  */
    685  keyvals[n_keys++] = keyval;
    686  /* Send keystroke to the plugin */
    687  gp->priv->plugin->send_keystrokes(gp, keyvals, n_keys);
    688  g_free(keys);
    689  /* Process next character in the keystrokes */
    690  iter = g_utf8_find_next_char(iter, NULL);
    691  }
    692  g_free(keyvals);
    693  }
    694  g_free(text);
    695  }
    696  return;
    697 }
    698 
    700 {
    701  TRACE_CALL(__func__);
    702  GtkClipboard *clipboard;
    703 
    704  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
    705 
    706  /* Request the contents of the clipboard, contents_received will be
    707  * called when we do get the contents.
    708  */
    709  gtk_clipboard_request_text(clipboard,
    711 }
    712 
    714 {
    715  TRACE_CALL(__func__);
    716  if (!gp->priv->plugin->get_plugin_screenshot) {
    717  REMMINA_DEBUG("plugin screenshot function is not implemented, using core Remmina functionality");
    718  return FALSE;
    719  }
    720 
    721  return gp->priv->plugin->get_plugin_screenshot(gp, rpsd);
    722 }
    723 
    725 {
    726  TRACE_CALL(__func__);
    727  if (!gp->priv->plugin->map_event) {
    728  REMMINA_DEBUG("Map plugin function not implemented");
    729  return FALSE;
    730  }
    731 
    732  REMMINA_DEBUG("Calling plugin mapping function");
    733  return gp->priv->plugin->map_event(gp);
    734 }
    735 
    737 {
    738  TRACE_CALL(__func__);
    739  if (!gp->priv->plugin->unmap_event) {
    740  REMMINA_DEBUG("Unmap plugin function not implemented");
    741  return FALSE;
    742  }
    743 
    744  REMMINA_DEBUG("Calling plugin unmapping function");
    745  return gp->priv->plugin->unmap_event(gp);
    746 }
    747 
    749 {
    750  TRACE_CALL(__func__);
    751 
    752  REMMINA_DEBUG("Emitting signals should be used from the object itself, not from another object");
    753  raise(SIGINT);
    754 
    756  /* Allow the execution of this function from a non main thread */
    758  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    759  d->func = FUNC_PROTOCOLWIDGET_EMIT_SIGNAL;
    760  d->p.protocolwidget_emit_signal.signal_name = signal_name;
    761  d->p.protocolwidget_emit_signal.gp = gp;
    763  g_free(d);
    764  return;
    765  }
    766  g_signal_emit_by_name(G_OBJECT(gp), signal_name);
    767 }
    768 
    770 {
    771  TRACE_CALL(__func__);
    772  return gp->priv->features;
    773 }
    774 
    776 {
    777  TRACE_CALL(__func__);
    778  const RemminaProtocolFeature *feature;
    779 
    780 #ifdef HAVE_LIBSSH
    782  remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    783  return TRUE;
    784 
    785 #endif
    786  for (feature = gp->priv->plugin->features; feature && feature->type; feature++)
    787  if (feature->type == type)
    788  return TRUE;
    789  return FALSE;
    790 }
    791 
    793 {
    794  TRACE_CALL(__func__);
    795  return gp->priv->plugin->query_feature(gp, feature);
    796 }
    797 
    799 {
    800  TRACE_CALL(__func__);
    801  const RemminaProtocolFeature *feature;
    802 
    803  for (feature = gp->priv->plugin->features; feature && feature->type; feature++) {
    804  if (feature->type == type && (id == 0 || feature->id == id)) {
    806  break;
    807  }
    808  }
    809 }
    810 
    812 {
    813  TRACE_CALL(__func__);
    814  switch (feature->id) {
    815 #ifdef HAVE_LIBSSH
    816  case REMMINA_PROTOCOL_FEATURE_TOOL_SSH:
    817  if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) {
    820  (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0], NULL);
    821  return;
    822  }
    823  break;
    824 
    825  case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP:
    826  if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) {
    829  gp->priv->ssh_tunnels->pdata[0], NULL);
    830  return;
    831  }
    832  break;
    833 #endif
    834  default:
    835  break;
    836  }
    837  gp->priv->plugin->call_feature(gp, feature);
    838 }
    839 
    840 static gboolean remmina_protocol_widget_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    841 {
    842  TRACE_CALL(__func__);
    843  if (gp->priv->hostkey_func)
    844  return gp->priv->hostkey_func(gp, event->keyval, FALSE);
    845  return FALSE;
    846 }
    847 
    848 static gboolean remmina_protocol_widget_on_key_release(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    849 {
    850  TRACE_CALL(__func__);
    851  if (gp->priv->hostkey_func)
    852  return gp->priv->hostkey_func(gp, event->keyval, TRUE);
    853 
    854  return FALSE;
    855 }
    856 
    858 {
    859  TRACE_CALL(__func__);
    860  g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(remmina_protocol_widget_on_key_press), gp);
    861  g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(remmina_protocol_widget_on_key_release), gp);
    862 }
    863 
    865 {
    866  TRACE_CALL(__func__);
    867  gp->priv->hostkey_func = func;
    868 }
    869 
    870 RemminaMessagePanel *remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    871 {
    872  RemminaMessagePanel *mp;
    873 
    875  /* Allow the execution of this function from a non main thread */
    877  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    878  d->func = FUNC_PROTOCOLWIDGET_MPPROGRESS;
    879  d->p.protocolwidget_mpprogress.cnnobj = cnnobj;
    880  d->p.protocolwidget_mpprogress.message = msg;
    881  d->p.protocolwidget_mpprogress.response_callback = response_callback;
    882  d->p.protocolwidget_mpprogress.response_callback_data = response_callback_data;
    884  mp = d->p.protocolwidget_mpprogress.ret_mp;
    885  g_free(d);
    886  return mp;
    887  }
    888 
    890  remmina_message_panel_setup_progress(mp, msg, response_callback, response_callback_data);
    891  rco_show_message_panel(cnnobj, mp);
    892  return mp;
    893 }
    894 
    895 void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    896 {
    898  /* Allow the execution of this function from a non main thread */
    900  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    901  d->func = FUNC_PROTOCOLWIDGET_MPDESTROY;
    902  d->p.protocolwidget_mpdestroy.cnnobj = cnnobj;
    903  d->p.protocolwidget_mpdestroy.mp = mp;
    905  g_free(d);
    906  return;
    907  }
    908  rco_destroy_message_panel(cnnobj, mp);
    909 }
    910 
    911 #ifdef HAVE_LIBSSH
    912 static void cancel_init_tunnel_cb(void *cbdata, int btn)
    913 {
    914  printf("Remmina: Cancelling an opening tunnel is not implemented\n");
    915 }
    916 
    918 {
    919  TRACE_CALL(__func__);
    920  RemminaSSHTunnel *tunnel;
    921  gint ret;
    922  gchar *msg;
    923  RemminaMessagePanel *mp;
    924  gboolean partial = FALSE;
    925  gboolean cont = FALSE;
    926 
    928 
    929  REMMINA_DEBUG("Creating SSH tunnel to “%s” via SSH…", REMMINA_SSH(tunnel)->server);
    930  // TRANSLATORS: “%s” is a placeholder for an hostname or an IP address.
    931  msg = g_strdup_printf(_("Connecting to “%s” via SSH…"), REMMINA_SSH(tunnel)->server);
    932 
    934  g_free(msg);
    935 
    936 
    937 
    938  while (1) {
    939  if (!partial) {
    940  if (!remmina_ssh_init_session(REMMINA_SSH(tunnel))) {
    941  REMMINA_DEBUG("SSH Tunnel init session error: %s", REMMINA_SSH(tunnel)->error);
    942  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    943  // exit the loop here: OK
    944  break;
    945  }
    946  }
    947 
    948  ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file);
    949  REMMINA_DEBUG("Tunnel auth returned %d", ret);
    950  switch (ret) {
    952  REMMINA_DEBUG("Authentication success");
    953  break;
    955  REMMINA_DEBUG("Continue with the next auth method");
    956  partial = TRUE;
    957  // Continue the loop: OK
    958  continue;
    959  break;
    961  REMMINA_DEBUG("Reconnecting…");
    962  if (REMMINA_SSH(tunnel)->session) {
    963  ssh_disconnect(REMMINA_SSH(tunnel)->session);
    964  ssh_free(REMMINA_SSH(tunnel)->session);
    965  REMMINA_SSH(tunnel)->session = NULL;
    966  }
    967  g_free(REMMINA_SSH(tunnel)->callback);
    968  // Continue the loop: OK
    969  continue;
    970  break;
    972  REMMINA_DEBUG("Interrupted by the user");
    973  // exit the loop here: OK
    974  goto BREAK;
    975  break;
    976  default:
    977  REMMINA_DEBUG("Error during the authentication: %s", REMMINA_SSH(tunnel)->error);
    978  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    979  // exit the loop here: OK
    980  goto BREAK;
    981  }
    982 
    983 
    984  cont = TRUE;
    985  break;
    986  }
    987 
    988 #if 0
    989 
    990  if (!remmina_ssh_init_session(REMMINA_SSH(tunnel))) {
    991  REMMINA_DEBUG("Cannot init SSH session with tunnel struct");
    992  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    993  remmina_ssh_tunnel_free(tunnel);
    994  return NULL;
    995  }
    996 
    997  ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file);
    998  REMMINA_DEBUG("Tunnel auth returned %d", ret);
    999  if (ret != REMMINA_SSH_AUTH_SUCCESS) {
    1000  if (ret != REMMINA_SSH_AUTH_USERCANCEL)
    1001  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1002  remmina_ssh_tunnel_free(tunnel);
    1003  return NULL;
    1004  }
    1005 
    1006 #endif
    1007 
    1008 BREAK:
    1009  if (!cont) {
    1010  remmina_ssh_tunnel_free(tunnel);
    1011  return NULL;
    1012  }
    1014 
    1015  return tunnel;
    1016 }
    1017 #endif
    1018 
    1019 
    1020 #ifdef HAVE_LIBSSH
    1021 static void cancel_start_direct_tunnel_cb(void *cbdata, int btn)
    1022 {
    1023  printf("Remmina: Cancelling start_direct_tunnel is not implemented\n");
    1024 }
    1025 
    1026 static gboolean remmina_protocol_widget_tunnel_destroy(RemminaSSHTunnel *tunnel, gpointer data)
    1027 {
    1028  TRACE_CALL(__func__);
    1029  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1030  guint idx = 0;
    1031 
    1032 #if GLIB_CHECK_VERSION(2, 54, 0)
    1033  gboolean found = g_ptr_array_find(gp->priv->ssh_tunnels, tunnel, &idx);
    1034 #else
    1035  int i;
    1036  gboolean found = FALSE;
    1037  for (i = 0; i < gp->priv->ssh_tunnels->len; i++) {
    1038  if ((RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[i] == tunnel) {
    1039  found = TRUE;
    1040  idx = i;
    1041  }
    1042  }
    1043 #endif
    1044 
    1045  printf("Tunnel %s found at idx = %d\n", found ? "yes": "not", idx);
    1046 
    1047  if (found) {
    1048 #ifdef HAVE_LIBSSH
    1049  REMMINA_DEBUG("[Tunnel with idx %u has been disconnected", idx);
    1050  remmina_ssh_tunnel_free(tunnel);
    1051 #endif
    1052  g_ptr_array_remove(gp->priv->ssh_tunnels, tunnel);
    1053  }
    1054  return TRUE;
    1055 }
    1056 #endif
    1057 
    1062 gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
    1063 {
    1064  TRACE_CALL(__func__);
    1065  const gchar *server;
    1066  const gchar *ssh_tunnel_server;
    1067  gchar *ssh_tunnel_host, *srv_host, *dest;
    1068  gint srv_port, ssh_tunnel_port = 0;
    1069 
    1070  REMMINA_DEBUG("SSH tunnel initialization…");
    1071 
    1072  server = remmina_file_get_string(gp->priv->remmina_file, "server");
    1073  ssh_tunnel_server = remmina_file_get_string(gp->priv->remmina_file, "ssh_tunnel_server");
    1074 
    1075  if (!server)
    1076  return g_strdup("");
    1077 
    1078  if (strstr(g_strdup(server), "unix:///") != NULL) {
    1079  REMMINA_DEBUG("%s is a UNIX socket", server);
    1080  return g_strdup(server);
    1081  }
    1082 
    1083  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1084  remmina_public_get_server_port(server, default_port, &srv_host, &srv_port);
    1085  REMMINA_DEBUG("Calling remmina_public_get_server_port (tunnel)");
    1086  remmina_public_get_server_port(ssh_tunnel_server, 22, &ssh_tunnel_host, &ssh_tunnel_port);
    1087  REMMINA_DEBUG("server: %s, port: %d", srv_host, srv_port);
    1088 
    1089  if (port_plus && srv_port < 100)
    1090  /* Protocols like VNC supports using instance number :0, :1, etc. as port number. */
    1091  srv_port += default_port;
    1092 
    1093 #ifdef HAVE_LIBSSH
    1094  gchar *msg;
    1095  RemminaMessagePanel *mp;
    1096  RemminaSSHTunnel *tunnel;
    1097 
    1098  if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE)) {
    1099  dest = g_strdup_printf("[%s]:%i", srv_host, srv_port);
    1100  g_free(srv_host);
    1101  g_free(ssh_tunnel_host);
    1102  return dest;
    1103  }
    1104 
    1106  if (!tunnel) {
    1107  g_free(srv_host);
    1108  g_free(ssh_tunnel_host);
    1109  REMMINA_DEBUG("remmina_protocol_widget_init_tunnel failed with error is %s",
    1111  return NULL;
    1112  }
    1113 
    1114  // TRANSLATORS: “%s” is a placeholder for an hostname or an IP address.
    1115  msg = g_strdup_printf(_("Connecting to “%s” via SSH…"), server);
    1117  g_free(msg);
    1118 
    1119  if (remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_loopback", FALSE)) {
    1120  g_free(srv_host);
    1121  g_free(ssh_tunnel_host);
    1122  ssh_tunnel_host = NULL;
    1123  srv_host = g_strdup("127.0.0.1");
    1124  }
    1125 
    1126  REMMINA_DEBUG("Starting tunnel to: %s, port: %d", ssh_tunnel_host, ssh_tunnel_port);
    1127  if (!remmina_ssh_tunnel_open(tunnel, srv_host, srv_port, remmina_pref.sshtunnel_port)) {
    1128  g_free(srv_host);
    1129  g_free(ssh_tunnel_host);
    1130  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1131  remmina_ssh_tunnel_free(tunnel);
    1132  return NULL;
    1133  }
    1134  g_free(srv_host);
    1135  g_free(ssh_tunnel_host);
    1136 
    1138 
    1140  tunnel->destroy_func_callback_data = (gpointer)gp;
    1141 
    1142  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1143 
    1144  return g_strdup_printf("127.0.0.1:%i", remmina_pref.sshtunnel_port);
    1145 
    1146 #else
    1147 
    1148  dest = g_strdup_printf("[%s]:%i", srv_host, srv_port);
    1149  g_free(srv_host);
    1150  g_free(ssh_tunnel_host);
    1151  return dest;
    1152 
    1153 #endif
    1154 }
    1155 
    1156 #ifdef HAVE_LIBSSH
    1157 static void cancel_start_reverse_tunnel_cb(void *cbdata, int btn)
    1158 {
    1159  printf("Remmina: Cancelling start_reverse_tunnel is not implemented\n");
    1160 }
    1161 #endif
    1162 
    1163 
    1165 {
    1166  TRACE_CALL(__func__);
    1167 #ifdef HAVE_LIBSSH
    1168  gchar *msg;
    1169  RemminaMessagePanel *mp;
    1170  RemminaSSHTunnel *tunnel;
    1171 
    1172  if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    1173  return TRUE;
    1174 
    1175  if (!(tunnel = remmina_protocol_widget_init_tunnel(gp)))
    1176  return FALSE;
    1177 
    1178  // TRANSLATORS: “%i” is a placeholder for a TCP port number.
    1179  msg = g_strdup_printf(_("Awaiting incoming SSH connection on port %i…"), remmina_file_get_int(gp->priv->remmina_file, "listenport", 0));
    1181  g_free(msg);
    1182 
    1183  if (!remmina_ssh_tunnel_reverse(tunnel, remmina_file_get_int(gp->priv->remmina_file, "listenport", 0), local_port)) {
    1184  remmina_ssh_tunnel_free(tunnel);
    1185  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1186  return FALSE;
    1187  }
    1189  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1190 #endif
    1191 
    1192  return TRUE;
    1193 }
    1194 
    1195 gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...)
    1196 {
    1197  TRACE_CALL(__func__);
    1198 #ifdef HAVE_LIBSSH
    1199  RemminaSSHTunnel *tunnel;
    1200  ssh_channel channel;
    1201  gint status;
    1202  gboolean ret = FALSE;
    1203  gchar *cmd, *ptr;
    1204  va_list args;
    1205 
    1206  if (gp->priv->ssh_tunnels->len < 1)
    1207  return FALSE;
    1208 
    1209  tunnel = (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0];
    1210 
    1211  if ((channel = ssh_channel_new(REMMINA_SSH(tunnel)->session)) == NULL)
    1212  return FALSE;
    1213 
    1214  va_start(args, fmt);
    1215  cmd = g_strdup_vprintf(fmt, args);
    1216  va_end(args);
    1217 
    1218  if (ssh_channel_open_session(channel) == SSH_OK &&
    1219  ssh_channel_request_exec(channel, cmd) == SSH_OK) {
    1220  if (wait) {
    1221  ssh_channel_send_eof(channel);
    1222  status = ssh_channel_get_exit_status(channel);
    1223  ptr = strchr(cmd, ' ');
    1224  if (ptr) *ptr = '\0';
    1225  switch (status) {
    1226  case 0:
    1227  ret = TRUE;
    1228  break;
    1229  case 127:
    1230  // TRANSLATORS: “%s” is a place holder for a unix command path.
    1231  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
    1232  _("The “%s” command is not available on the SSH server."), cmd);
    1233  break;
    1234  default:
    1235  // TRANSLATORS: “%s” is a place holder for a unix command path. “%i” is a placeholder for an error code number.
    1236  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
    1237  _("Could not run the “%s” command on the SSH server (status = %i)."), cmd, status);
    1238  break;
    1239  }
    1240  } else {
    1241  ret = TRUE;
    1242  }
    1243  } else {
    1244  // TRANSLATORS: %s is a placeholder for an error message
    1245  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not run command. %s"));
    1246  }
    1247  g_free(cmd);
    1248  if (wait)
    1249  ssh_channel_close(channel);
    1250  ssh_channel_free(channel);
    1251  return ret;
    1252 
    1253 #else
    1254 
    1255  return FALSE;
    1256 
    1257 #endif
    1258 }
    1259 
    1260 #ifdef HAVE_LIBSSH
    1262 {
    1263  TRACE_CALL(__func__);
    1264  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1265  gchar *server;
    1266  gint port;
    1267  gboolean ret;
    1268 
    1269  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1270  remmina_public_get_server_port(remmina_file_get_string(gp->priv->remmina_file, "server"), 177, &server, &port);
    1271  ret = ((RemminaXPortTunnelInitFunc)gp->priv->init_func)(gp,
    1272  tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
    1273  g_free(server);
    1274 
    1275  return ret;
    1276 }
    1277 
    1279 {
    1280  TRACE_CALL(__func__);
    1281  return TRUE;
    1282 }
    1283 
    1285 {
    1286  TRACE_CALL(__func__);
    1287  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1288 
    1289  if (REMMINA_SSH(tunnel)->error)
    1290  remmina_protocol_widget_set_error(gp, "%s", REMMINA_SSH(tunnel)->error);
    1291 
    1292  IDLE_ADD((GSourceFunc)remmina_protocol_widget_close_connection, gp);
    1293  return TRUE;
    1294 }
    1295 #endif
    1296 #ifdef HAVE_LIBSSH
    1297 static void cancel_connect_xport_cb(void *cbdata, int btn)
    1298 {
    1299  printf("Remmina: Cancelling an XPort connection is not implemented\n");
    1300 }
    1301 #endif
    1303 {
    1304  TRACE_CALL(__func__);
    1305 #ifdef HAVE_LIBSSH
    1306  gboolean bindlocalhost;
    1307  gchar *server;
    1308  gchar *msg;
    1309  RemminaMessagePanel *mp;
    1310  RemminaSSHTunnel *tunnel;
    1311 
    1312  if (!(tunnel = remmina_protocol_widget_init_tunnel(gp))) return FALSE;
    1313 
    1314  // TRANSLATORS: “%s” is a placeholder for a hostname or IP address.
    1315  msg = g_strdup_printf(_("Connecting to %s via SSH…"), remmina_file_get_string(gp->priv->remmina_file, "server"));
    1317  g_free(msg);
    1318 
    1319  gp->priv->init_func = init_func;
    1323  tunnel->callback_data = gp;
    1324 
    1325  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1326  remmina_public_get_server_port(remmina_file_get_string(gp->priv->remmina_file, "server"), 0, &server, NULL);
    1327  bindlocalhost = (g_strcmp0(REMMINA_SSH(tunnel)->server, server) == 0);
    1328  g_free(server);
    1329 
    1330  if (!remmina_ssh_tunnel_xport(tunnel, bindlocalhost)) {
    1331  remmina_protocol_widget_set_error(gp, "Could not open channel, %s",
    1332  ssh_get_error(REMMINA_SSH(tunnel)->session));
    1333  remmina_ssh_tunnel_free(tunnel);
    1334  return FALSE;
    1335  }
    1336 
    1338  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1339 
    1340  return TRUE;
    1341 
    1342 #else
    1343  return FALSE;
    1344 #endif
    1345 }
    1346 
    1348 {
    1349  TRACE_CALL(__func__);
    1350 #ifdef HAVE_LIBSSH
    1351  RemminaSSHTunnel *tunnel;
    1352  if (gp->priv->ssh_tunnels->len < 1)
    1353  return;
    1354  tunnel = (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0];
    1355  if (tunnel->localdisplay) g_free(tunnel->localdisplay);
    1356  tunnel->localdisplay = g_strdup_printf("unix:%i", display);
    1357 #endif
    1358 }
    1359 
    1361 {
    1362  TRACE_CALL(__func__);
    1363  /* Returns the width of remote desktop as chosen by the user profile */
    1364  return gp->priv->profile_remote_width;
    1365 }
    1366 
    1368 {
    1369  TRACE_CALL(__func__);
    1370  /* Returns ehenever multi monitor is enabled (1) */
    1371  gp->priv->multimon = remmina_file_get_int(gp->priv->remmina_file, "multimon", -1);
    1372  REMMINA_DEBUG("Multi monitor is set to %d", gp->priv->multimon);
    1373  return gp->priv->multimon;
    1374 }
    1375 
    1377 {
    1378  TRACE_CALL(__func__);
    1379  /* Returns the height of remote desktop as chosen by the user profile */
    1380  return gp->priv->profile_remote_height;
    1381 }
    1382 
    1384 {
    1385  TRACE_CALL(__func__);
    1386  return gp ? gp->plugin ? gp->plugin->name : NULL : NULL;
    1387 }
    1388 
    1390 {
    1391  TRACE_CALL(__func__);
    1392  return gp->priv->width;
    1393 }
    1394 
    1396 {
    1397  TRACE_CALL(__func__);
    1398  gp->priv->width = width;
    1399 }
    1400 
    1402 {
    1403  TRACE_CALL(__func__);
    1404  return gp->priv->height;
    1405 }
    1406 
    1408 {
    1409  TRACE_CALL(__func__);
    1410  gp->priv->height = height;
    1411 }
    1412 
    1414 {
    1415  TRACE_CALL(__func__);
    1416  return gp->priv->scalemode;
    1417 }
    1418 
    1420 {
    1421  TRACE_CALL(__func__);
    1422  gp->priv->scalemode = scalemode;
    1423 }
    1424 
    1426 {
    1427  TRACE_CALL(__func__);
    1428  return gp->priv->scaler_expand;
    1429 }
    1430 
    1432 {
    1433  TRACE_CALL(__func__);
    1434  gp->priv->scaler_expand = expand;
    1435  return;
    1436 }
    1437 
    1439 {
    1440  TRACE_CALL(__func__);
    1441  return gp->priv->has_error;
    1442 }
    1443 
    1445 {
    1446  TRACE_CALL(__func__);
    1447  return gp->priv->error_message;
    1448 }
    1449 
    1451 {
    1452  TRACE_CALL(__func__);
    1453  va_list args;
    1454 
    1455  if (gp->priv->error_message) g_free(gp->priv->error_message);
    1456 
    1457  if (fmt == NULL) {
    1458  gp->priv->has_error = FALSE;
    1459  gp->priv->error_message = NULL;
    1460  return;
    1461  }
    1462 
    1463  va_start(args, fmt);
    1464  gp->priv->error_message = g_strdup_vprintf(fmt, args);
    1465  va_end(args);
    1466 
    1467  gp->priv->has_error = TRUE;
    1468 }
    1469 
    1471 {
    1472  TRACE_CALL(__func__);
    1473  return gp->priv->closed;
    1474 }
    1475 
    1477 {
    1478  TRACE_CALL(__func__);
    1479  return gp->priv->remmina_file;
    1480 }
    1481 
    1483  /* Input data */
    1485  gchar * title;
    1490  enum panel_type dtype;
    1493  /* Running status */
    1494  pthread_mutex_t pt_mutex;
    1495  pthread_cond_t pt_cond;
    1496  /* Output/retval */
    1498 };
    1499 
    1500 static void authpanel_mt_cb(void *user_data, int button)
    1501 {
    1503 
    1504  d->rcbutton = button;
    1505  if (button == GTK_RESPONSE_OK) {
    1506  if (d->dtype == RPWDT_AUTH) {
    1511  } else if (d->dtype == RPWDT_AUTHX509) {
    1516  }
    1517  }
    1518 
    1519  if (d->called_from_subthread) {
    1520  /* Hide and destroy message panel, we can do it now because we are on the main thread */
    1522 
    1523  /* Awake the locked subthread, when called from subthread */
    1524  pthread_mutex_lock(&d->pt_mutex);
    1525  pthread_cond_signal(&d->pt_cond);
    1526  pthread_mutex_unlock(&d->pt_mutex);
    1527  } else {
    1528  /* Signal completion, when called from main thread. Message panel will be destroyed by the caller */
    1530  }
    1531 }
    1532 
    1533 static gboolean remmina_protocol_widget_dialog_mt_setup(gpointer user_data)
    1534 {
    1536 
    1537  RemminaFile *remminafile = d->gp->priv->remmina_file;
    1538  RemminaMessagePanel *mp;
    1539  const gchar *s;
    1540 
    1541  if (d->gp->cnnobj == NULL)
    1542  return FALSE;
    1543 
    1545 
    1546  if (d->dtype == RPWDT_AUTH) {
    1554  } else if (d->dtype == RPWDT_QUESTIONYESNO) {
    1556  } else if (d->dtype == RPWDT_AUTHX509) {
    1558  if ((s = remmina_file_get_string(remminafile, "cacert")) != NULL)
    1560  if ((s = remmina_file_get_string(remminafile, "cacrl")) != NULL)
    1562  if ((s = remmina_file_get_string(remminafile, "clientcert")) != NULL)
    1564  if ((s = remmina_file_get_string(remminafile, "clientkey")) != NULL)
    1566  }
    1567 
    1568  d->gp->priv->auth_message_panel = mp;
    1569  rco_show_message_panel(d->gp->cnnobj, mp);
    1570 
    1571  return FALSE;
    1572 }
    1573 
    1574 typedef struct {
    1575  RemminaMessagePanel * mp;
    1576  GMainLoop * loop;
    1577  gint response;
    1578  gboolean destroyed;
    1579 } MpRunInfo;
    1580 
    1581 static void shutdown_loop(MpRunInfo *mpri)
    1582 {
    1583  if (g_main_loop_is_running(mpri->loop))
    1584  g_main_loop_quit(mpri->loop);
    1585 }
    1586 
    1587 static void run_response_handler(RemminaMessagePanel *mp, gint response_id, gpointer data)
    1588 {
    1589  MpRunInfo *mpri = (MpRunInfo *)data;
    1590 
    1591  mpri->response = response_id;
    1592  shutdown_loop(mpri);
    1593 }
    1594 
    1595 static void run_unmap_handler(RemminaMessagePanel *mp, gpointer data)
    1596 {
    1597  MpRunInfo *mpri = (MpRunInfo *)data;
    1598 
    1599  mpri->response = GTK_RESPONSE_CANCEL;
    1600  shutdown_loop(mpri);
    1601 }
    1602 
    1603 static void run_destroy_handler(RemminaMessagePanel *mp, gpointer data)
    1604 {
    1605  MpRunInfo *mpri = (MpRunInfo *)data;
    1606 
    1607  mpri->destroyed = TRUE;
    1608  mpri->response = GTK_RESPONSE_CANCEL;
    1609  shutdown_loop(mpri);
    1610 }
    1611 
    1613  const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain,
    1614  const gchar *strpasswordlabel)
    1615 {
    1616  TRACE_CALL(__func__);
    1617 
    1619  int rcbutton;
    1620 
    1621  d->gp = gp;
    1622  d->pflags = pflags;
    1623  d->dtype = dtype;
    1624  d->title = g_strdup(title);
    1625  d->strpasswordlabel = g_strdup(strpasswordlabel);
    1626  d->default_username = g_strdup(default_username);
    1627  d->default_password = g_strdup(default_password);
    1628  d->default_domain = g_strdup(default_domain);
    1629  d->called_from_subthread = FALSE;
    1630 
    1632  /* Run the MessagePanel in main thread, in a very similar way of gtk_dialog_run() */
    1633  MpRunInfo mpri = { NULL, NULL, GTK_RESPONSE_CANCEL, FALSE };
    1634 
    1635  gulong unmap_handler;
    1636  gulong destroy_handler;
    1637  gulong response_handler;
    1638 
    1640 
    1641  mpri.mp = d->gp->priv->auth_message_panel;
    1642 
    1643  if (!gtk_widget_get_visible(GTK_WIDGET(mpri.mp)))
    1644  gtk_widget_show(GTK_WIDGET(mpri.mp));
    1645  response_handler = g_signal_connect(mpri.mp, "response", G_CALLBACK(run_response_handler), &mpri);
    1646  unmap_handler = g_signal_connect(mpri.mp, "unmap", G_CALLBACK(run_unmap_handler), &mpri);
    1647  destroy_handler = g_signal_connect(mpri.mp, "destroy", G_CALLBACK(run_destroy_handler), &mpri);
    1648 
    1649  g_object_ref(mpri.mp);
    1650 
    1651  mpri.loop = g_main_loop_new(NULL, FALSE);
    1652  g_main_loop_run(mpri.loop);
    1653  g_main_loop_unref(mpri.loop);
    1654 
    1655  if (!mpri.destroyed) {
    1656  g_signal_handler_disconnect(mpri.mp, response_handler);
    1657  g_signal_handler_disconnect(mpri.mp, destroy_handler);
    1658  g_signal_handler_disconnect(mpri.mp, unmap_handler);
    1659  }
    1660  g_object_unref(mpri.mp);
    1661 
    1663 
    1664  rcbutton = mpri.response;
    1665  } else {
    1666  d->called_from_subthread = TRUE;
    1667  // pthread_cleanup_push(ptcleanup, (void*)d);
    1668  pthread_cond_init(&d->pt_cond, NULL);
    1669  pthread_mutex_init(&d->pt_mutex, NULL);
    1671  pthread_mutex_lock(&d->pt_mutex);
    1672  pthread_cond_wait(&d->pt_cond, &d->pt_mutex);
    1673  // pthread_cleanup_pop(0);
    1674  pthread_mutex_destroy(&d->pt_mutex);
    1675  pthread_cond_destroy(&d->pt_cond);
    1676 
    1677  rcbutton = d->rcbutton;
    1678  }
    1679 
    1680  g_free(d->title);
    1681  g_free(d->strpasswordlabel);
    1682  g_free(d->default_username);
    1683  g_free(d->default_password);
    1684  g_free(d->default_domain);
    1685  g_free(d);
    1686  return rcbutton;
    1687 }
    1688 
    1690 {
    1691  return remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, msg, NULL, NULL, NULL, NULL);
    1692 }
    1693 
    1695  const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    1696 {
    1697  TRACE_CALL(__func__);
    1698  return remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, title, default_username,
    1699  default_password, default_domain, password_prompt == NULL ? _("Password") : password_prompt);
    1700 }
    1701 
    1702 gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    1703 {
    1704  TRACE_CALL(__func__);
    1705  unsigned pflags;
    1706  RemminaFile *remminafile = gp->priv->remmina_file;
    1707  const gchar *username, *password;
    1708 
    1710  if (remmina_file_get_filename(remminafile) != NULL &&
    1711  !remminafile->prevent_saving && allow_password_saving)
    1713 
    1714  username = remmina_file_get_string(remminafile, "ssh_tunnel_username");
    1715  password = remmina_file_get_string(remminafile, "ssh_tunnel_password");
    1716 
    1717  return remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, _("Type in SSH username and password."), username,
    1718  password, NULL, _("Password"));
    1719 }
    1720 
    1721 /*
    1722  * gint remmina_protocol_widget_panel_authpwd(RemminaProtocolWidget* gp, RemminaAuthpwdType authpwd_type, gboolean allow_password_saving)
    1723  * {
    1724  * TRACE_CALL(__func__);
    1725  * unsigned pflags;
    1726  * RemminaFile* remminafile = gp->priv->remmina_file;
    1727  * char *password_prompt;
    1728  * int rc;
    1729  *
    1730  * pflags = 0;
    1731  * if (remmina_file_get_filename(remminafile) != NULL &&
    1732  * !remminafile->prevent_saving && allow_password_saving)
    1733  * pflags |= REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD;
    1734  *
    1735  * switch (authpwd_type) {
    1736  * case REMMINA_AUTHPWD_TYPE_PROTOCOL:
    1737  * password_prompt = g_strdup_printf(_("%s password"), remmina_file_get_string(remminafile, "protocol"));
    1738  * break;
    1739  * case REMMINA_AUTHPWD_TYPE_SSH_PWD:
    1740  * password_prompt = g_strdup(_("SSH password"));
    1741  * break;
    1742  * case REMMINA_AUTHPWD_TYPE_SSH_PRIVKEY:
    1743  * password_prompt = g_strdup(_("SSH private key passphrase"));
    1744  * break;
    1745  * default:
    1746  * password_prompt = g_strdup(_("Password"));
    1747  * break;
    1748  * }
    1749  *
    1750  * rc = remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, password_prompt);
    1751  * g_free(password_prompt);
    1752  * return rc;
    1753  *
    1754  * }
    1755  */
    1757 {
    1758  TRACE_CALL(__func__);
    1759 
    1760  return remmina_protocol_widget_dialog(RPWDT_AUTHX509, gp, 0, NULL, NULL, NULL, NULL, NULL);
    1761 }
    1762 
    1763 
    1764 gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    1765 {
    1766  TRACE_CALL(__func__);
    1767  gchar *s;
    1768  int rc;
    1769 
    1770  if (remmina_pref_get_boolean("trust_all")) {
    1771  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1772  remmina_public_send_notification("remmina-security-trust-all-id", _("Fingerprint automatically accepted"), fingerprint);
    1773  rc = GTK_RESPONSE_OK;
    1774  return rc;
    1775  }
    1776  // For markup see https://developer.gnome.org/pygtk/stable/pango-markup-language.html
    1777  s = g_strdup_printf(
    1778  "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
    1779  // TRANSLATORS: The user is asked to verify a new SSL certificate.
    1780  _("Certificate details:"),
    1781  // TRANSLATORS: An SSL certificate subject is usually the remote server the user connect to.
    1782  _("Subject:"), subject,
    1783  // TRANSLATORS: The name or email of the entity that have issued the SSL certificate
    1784  _("Issuer:"), issuer,
    1785  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1786  _("Fingerprint:"), fingerprint,
    1787  // TRANSLATORS: The user is asked to accept or refuse a new SSL certificate.
    1788  _("Accept certificate?"));
    1789  rc = remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, s, NULL, NULL, NULL, NULL);
    1790  g_free(s);
    1791 
    1792  /* For compatibility with plugin API: the plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1793  return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
    1794 }
    1795 
    1796 gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    1797 {
    1798  TRACE_CALL(__func__);
    1799  gchar *s;
    1800  int rc;
    1801 
    1802  if (remmina_pref_get_boolean("trust_all")) {
    1803  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1804  remmina_public_send_notification("remmina-security-trust-all-id", _("Fingerprint automatically accepted"), new_fingerprint);
    1805  rc = GTK_RESPONSE_OK;
    1806  return rc;
    1807  }
    1808  // For markup see https://developer.gnome.org/pygtk/stable/pango-markup-language.html
    1809  s = g_strdup_printf(
    1810  "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
    1811  // TRANSLATORS: The user is asked to verify a new SSL certificate.
    1812  _("The certificate changed! Details:"),
    1813  // TRANSLATORS: An SSL certificate subject is usually the remote server the user connect to.
    1814  _("Subject:"), subject,
    1815  // TRANSLATORS: The name or email of the entity that have issued the SSL certificate
    1816  _("Issuer:"), issuer,
    1817  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1818  _("Old fingerprint:"), old_fingerprint,
    1819  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1820  _("New fingerprint:"), new_fingerprint,
    1821  // TRANSLATORS: The user is asked to accept or refuse a new SSL certificate.
    1822  _("Accept changed certificate?"));
    1823  rc = remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, s, NULL, NULL, NULL, NULL);
    1824  g_free(s);
    1825 
    1826  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1827  return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
    1828 }
    1829 
    1831 {
    1832  TRACE_CALL(__func__);
    1833  return g_strdup(gp->priv->username);
    1834 }
    1835 
    1837 {
    1838  TRACE_CALL(__func__);
    1839  return g_strdup(gp->priv->password);
    1840 }
    1841 
    1843 {
    1844  TRACE_CALL(__func__);
    1845  return g_strdup(gp->priv->domain);
    1846 }
    1847 
    1849 {
    1850  TRACE_CALL(__func__);
    1851  return gp->priv->save_password;
    1852 }
    1853 
    1855 {
    1856  TRACE_CALL(__func__);
    1857  gchar *s;
    1858 
    1859  s = gp->priv->cacert;
    1860  return s && s[0] ? g_strdup(s) : NULL;
    1861 }
    1862 
    1864 {
    1865  TRACE_CALL(__func__);
    1866  gchar *s;
    1867 
    1868  s = gp->priv->cacrl;
    1869  return s && s[0] ? g_strdup(s) : NULL;
    1870 }
    1871 
    1873 {
    1874  TRACE_CALL(__func__);
    1875  gchar *s;
    1876 
    1877  s = gp->priv->clientcert;
    1878  return s && s[0] ? g_strdup(s) : NULL;
    1879 }
    1880 
    1882 {
    1883  TRACE_CALL(__func__);
    1884  gchar *s;
    1885 
    1886  s = gp->priv->clientkey;
    1887  return s && s[0] ? g_strdup(s) : NULL;
    1888 }
    1889 
    1891 {
    1892  TRACE_CALL(__func__);
    1893 
    1894  RemminaFile *remminafile = gp->priv->remmina_file;
    1895  gchar *s;
    1896  gboolean save = FALSE;
    1897 
    1899  /* Allow the execution of this function from a non main thread */
    1900  RemminaMTExecData *d;
    1901  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    1902  d->func = FUNC_INIT_SAVE_CRED;
    1903  d->p.init_save_creds.gp = gp;
    1905  g_free(d);
    1906  return;
    1907  }
    1908 
    1909  /* Save username and certificates if any; save the password if it’s requested to do so */
    1910  s = gp->priv->username;
    1911  if (s && s[0]) {
    1912  remmina_file_set_string(remminafile, "username", s);
    1913  save = TRUE;
    1914  }
    1915  s = gp->priv->cacert;
    1916  if (s && s[0]) {
    1917  remmina_file_set_string(remminafile, "cacert", s);
    1918  save = TRUE;
    1919  }
    1920  s = gp->priv->cacrl;
    1921  if (s && s[0]) {
    1922  remmina_file_set_string(remminafile, "cacrl", s);
    1923  save = TRUE;
    1924  }
    1925  s = gp->priv->clientcert;
    1926  if (s && s[0]) {
    1927  remmina_file_set_string(remminafile, "clientcert", s);
    1928  save = TRUE;
    1929  }
    1930  s = gp->priv->clientkey;
    1931  if (s && s[0]) {
    1932  remmina_file_set_string(remminafile, "clientkey", s);
    1933  save = TRUE;
    1934  }
    1935  if (gp->priv->save_password) {
    1936  remmina_file_set_string(remminafile, "password", gp->priv->password);
    1937  save = TRUE;
    1938  }
    1939  if (save)
    1940  remmina_file_save(remminafile);
    1941 }
    1942 
    1943 
    1945 {
    1946  TRACE_CALL(__func__);
    1947  RemminaMessagePanel *mp;
    1948  gchar *s;
    1949 
    1951  /* Allow the execution of this function from a non main thread */
    1952  RemminaMTExecData *d;
    1953  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    1954  d->func = FUNC_PROTOCOLWIDGET_PANELSHOWLISTEN;
    1956  d->p.protocolwidget_panelshowlisten.port = port;
    1958  g_free(d);
    1959  return;
    1960  }
    1961 
    1963  s = g_strdup_printf(
    1964  // TRANSLATORS: “%i” is a placeholder for a port number. “%s” is a placeholder for a protocol name (VNC).
    1965  _("Listening on port %i for an incoming %s connection…"), port,
    1966  remmina_file_get_string(gp->priv->remmina_file, "protocol"));
    1967  remmina_message_panel_setup_progress(mp, s, NULL, NULL);
    1968  g_free(s);
    1969  gp->priv->listen_message_panel = mp;
    1970  rco_show_message_panel(gp->cnnobj, mp);
    1971 }
    1972 
    1974 {
    1975  TRACE_CALL(__func__);
    1976  RemminaMessagePanel *mp;
    1977 
    1979  /* Allow the execution of this function from a non main thread */
    1980  RemminaMTExecData *d;
    1981  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    1982  d->func = FUNC_PROTOCOLWIDGET_MPSHOWRETRY;
    1985  g_free(d);
    1986  return;
    1987  }
    1988 
    1990  remmina_message_panel_setup_progress(mp, _("Could not authenticate, attempting reconnection…"), NULL, NULL);
    1991  gp->priv->retry_message_panel = mp;
    1992  rco_show_message_panel(gp->cnnobj, mp);
    1993 }
    1994 
    1996 {
    1997  TRACE_CALL(__func__);
    1998  printf("Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
    1999 }
    2000 
    2002 {
    2003  TRACE_CALL(__func__);
    2004  printf("Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
    2005 }
    2006 
    2008 {
    2009  TRACE_CALL(__func__);
    2010  gp->priv->chat_window = NULL;
    2011 }
    2012 
    2014  void (*on_send)(RemminaProtocolWidget *gp, const gchar *text), void (*on_destroy)(RemminaProtocolWidget *gp))
    2015 {
    2016  TRACE_CALL(__func__);
    2017  if (gp->priv->chat_window) {
    2018  gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
    2019  } else {
    2020  gp->priv->chat_window = remmina_chat_window_new(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp))), name);
    2021  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "send", G_CALLBACK(on_send), gp);
    2022  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy",
    2023  G_CALLBACK(remmina_protocol_widget_chat_on_destroy), gp);
    2024  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy", G_CALLBACK(on_destroy), gp);
    2025  gtk_widget_show(gp->priv->chat_window);
    2026  }
    2027 }
    2028 
    2030 {
    2031  TRACE_CALL(__func__);
    2032  if (gp->priv->chat_window)
    2033  gtk_widget_destroy(gp->priv->chat_window);
    2034 }
    2035 
    2037 {
    2038  TRACE_CALL(__func__);
    2039  /* This function can be called from a non main thread */
    2040 
    2041  if (gp->priv->chat_window) {
    2043  /* Allow the execution of this function from a non main thread */
    2044  RemminaMTExecData *d;
    2045  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    2046  d->func = FUNC_CHAT_RECEIVE;
    2047  d->p.chat_receive.gp = gp;
    2048  d->p.chat_receive.text = text;
    2050  g_free(d);
    2051  return;
    2052  }
    2053  remmina_chat_window_receive(REMMINA_CHAT_WINDOW(gp->priv->chat_window), _("Server"), text);
    2054  gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
    2055  }
    2056 }
    2057 
    2059 {
    2061 
    2062  gp->priv->remmina_file = remminafile;
    2063  gp->cnnobj = cnnobj;
    2064 
    2065  /* Locate the protocol plugin */
    2067  remmina_file_get_string(remminafile, "protocol"));
    2068 
    2069  if (!plugin || !plugin->init || !plugin->open_connection) {
    2070  // TRANSLATORS: “%s” is a placeholder for a protocol name, like “RDP”.
    2071  remmina_protocol_widget_set_error(gp, _("Install the %s protocol plugin first."),
    2072  remmina_file_get_string(remminafile, "protocol"));
    2073  gp->priv->plugin = NULL;
    2074  return;
    2075  }
    2076  gp->priv->plugin = plugin;
    2077  gp->plugin = plugin;
    2078 
    2079  gp->priv->scalemode = remmina_file_get_int(gp->priv->remmina_file, "scale", FALSE);
    2080  gp->priv->scaler_expand = remmina_file_get_int(gp->priv->remmina_file, "scaler_expand", FALSE);
    2081 }
    2082 
    2084 {
    2085  return rcw_get_gtkwindow(gp->cnnobj);
    2086 }
    2087 
    2089 {
    2090  return rcw_get_gtkviewport(gp->cnnobj);
    2091 }
    2092 
    2094 {
    2095  return GTK_WIDGET(g_object_new(REMMINA_TYPE_PROTOCOL_WIDGET, NULL));
    2096 }
    2097 
    2098 /* Send one or more keystrokes to a specific widget by firing key-press and
    2099  * key-release events.
    2100  * GdkEventType action can be GDK_KEY_PRESS or GDK_KEY_RELEASE or both to
    2101  * press the keys and release them in reversed order. */
    2102 void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    2103 {
    2104  TRACE_CALL(__func__);
    2105  int i;
    2106  GdkEventKey event;
    2107  gboolean result;
    2108  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    2109 
    2110  event.window = gtk_widget_get_window(widget);
    2111  event.send_event = TRUE;
    2112  event.time = GDK_CURRENT_TIME;
    2113  event.state = 0;
    2114  event.length = 0;
    2115  event.string = "";
    2116  event.group = 0;
    2117 
    2118  if (action & GDK_KEY_PRESS) {
    2119  /* Press the requested buttons */
    2120  event.type = GDK_KEY_PRESS;
    2121  for (i = 0; i < keyvals_length; i++) {
    2122  event.keyval = keyvals[i];
    2123  event.hardware_keycode = remmina_public_get_keycode_for_keyval(keymap, event.keyval);
    2124  event.is_modifier = (int)remmina_public_get_modifier_for_keycode(keymap, event.hardware_keycode);
    2125  REMMINA_DEBUG("Sending keyval: %u, hardware_keycode: %u", event.keyval, event.hardware_keycode);
    2126  g_signal_emit_by_name(G_OBJECT(widget), "key-press-event", &event, &result);
    2127  }
    2128  }
    2129 
    2130  if (action & GDK_KEY_RELEASE) {
    2131  /* Release the requested buttons in reverse order */
    2132  event.type = GDK_KEY_RELEASE;
    2133  for (i = (keyvals_length - 1); i >= 0; i--) {
    2134  event.keyval = keyvals[i];
    2135  event.hardware_keycode = remmina_public_get_keycode_for_keyval(keymap, event.keyval);
    2136  event.is_modifier = (int)remmina_public_get_modifier_for_keycode(keymap, event.hardware_keycode);
    2137  g_signal_emit_by_name(G_OBJECT(widget), "key-release-event", &event, &result);
    2138  }
    2139  }
    2140 }
    2141 
    2143 {
    2144  TRACE_CALL(__func__);
    2145  GdkRectangle rect;
    2146  gint w, h;
    2147  gint wfile, hfile;
    2150 
    2151  rco_get_monitor_geometry(gp->cnnobj, &rect);
    2152 
    2153  /* Integrity check: check that we have a cnnwin visible and get t */
    2154 
    2155  res_mode = remmina_file_get_int(gp->priv->remmina_file, "resolution_mode", RES_INVALID);
    2157  wfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_width", -1);
    2158  hfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_height", -1);
    2159 
    2160  /* If resolution_mode is non-existent (-1), then we try to calculate it
    2161  * as we did before having resolution_mode */
    2162  if (res_mode == RES_INVALID) {
    2163  if (wfile <= 0 || hfile <= 0)
    2164  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
    2165  else
    2166  res_mode = RES_USE_CUSTOM;
    2167  }
    2168 
    2170  /* Use internal window size as remote desktop size */
    2171  GtkAllocation al;
    2172  gtk_widget_get_allocation(GTK_WIDGET(gp), &al);
    2173  /* use a multiple of four to mitigate scaling when remote host rounds up */
    2174  w = al.width - al.width % 4;
    2175  h = al.height - al.height % 4;
    2176  if (w < 10) {
    2177  printf("Remmina warning: %s RemminaProtocolWidget w=%d h=%d are too small, adjusting to 640x480\n", __func__, w, h);
    2178  w = 640;
    2179  h = 480;
    2180  }
    2181  /* Due to approximations while GTK calculates scaling, (w x h) may exceed our monitor geometry
    2182  * Adjust to fit. */
    2183  if (w > rect.width)
    2184  w = rect.width;
    2185  if (h > rect.height)
    2186  h = rect.height;
    2187  } else if (res_mode == RES_USE_CLIENT) {
    2188  w = rect.width;
    2189  h = rect.height;
    2190  } else {
    2191  w = wfile;
    2192  h = hfile;
    2193  }
    2194  gp->priv->profile_remote_width = w;
    2195  gp->priv->profile_remote_height = h;
    2196 }
    -
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2009-2011 Vic Lee
    4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #include "config.h"
    38 
    39 #include <gtk/gtk.h>
    40 #include <gtk/gtkx.h>
    41 #include <glib/gi18n.h>
    42 #include <gmodule.h>
    43 #include <stdlib.h>
    44 
    45 #include "remmina_chat_window.h"
    47 #include "remmina_ext_exec.h"
    48 #include "remmina_plugin_manager.h"
    49 #include "remmina_pref.h"
    51 #include "remmina_public.h"
    52 #include "remmina_ssh.h"
    53 #include "remmina_log.h"
    55 
    56 #ifdef GDK_WINDOWING_WAYLAND
    57 #include <gdk/gdkwayland.h>
    58 #endif
    59 
    64 
    65  gint width;
    66  gint height;
    68  gboolean scaler_expand;
    69 
    70  gboolean has_error;
    71  gchar * error_message;
    72  gboolean user_disconnect;
    73  /* ssh_tunnels is an array of RemminaSSHTunnel*
    74  * the 1st one is the "main" tunnel, other tunnels are used for example in sftp commands */
    75  GPtrArray * ssh_tunnels;
    77 
    78  GtkWidget * chat_window;
    79 
    80  gboolean closed;
    81 
    83 
    86  gint multimon;
    87 
    88  RemminaMessagePanel * connect_message_panel;
    89  RemminaMessagePanel * listen_message_panel;
    90  RemminaMessagePanel * auth_message_panel;
    91  RemminaMessagePanel * retry_message_panel;
    92 
    93  /* Data saved from the last message_panel when the user confirm */
    94  gchar * username;
    95  gchar * password;
    96  gchar * domain;
    97  gboolean save_password;
    98 
    99  gchar * cacert;
    100  gchar * cacrl;
    101  gchar * clientcert;
    102  gchar * clientkey;
    103 };
    104 
    109 };
    110 
    111 G_DEFINE_TYPE(RemminaProtocolWidget, remmina_protocol_widget, GTK_TYPE_EVENT_BOX)
    112 
    113 enum {
    114  CONNECT_SIGNAL,
    115  DISCONNECT_SIGNAL,
    116  DESKTOP_RESIZE_SIGNAL,
    117  UPDATE_ALIGN_SIGNAL,
    118  LOCK_DYNRES_SIGNAL,
    119  UNLOCK_DYNRES_SIGNAL,
    121 };
    122 
    125  const gchar * signal_name;
    127 
    129 { 0 };
    130 
    132 {
    133  TRACE_CALL(__func__);
    134  remmina_protocol_widget_signals[CONNECT_SIGNAL] = g_signal_new("connect", G_TYPE_FROM_CLASS(klass),
    135  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, connect), NULL, NULL,
    136  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    137  remmina_protocol_widget_signals[DISCONNECT_SIGNAL] = g_signal_new("disconnect", G_TYPE_FROM_CLASS(klass),
    138  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, disconnect), NULL, NULL,
    139  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    140  remmina_protocol_widget_signals[DESKTOP_RESIZE_SIGNAL] = g_signal_new("desktop-resize", G_TYPE_FROM_CLASS(klass),
    141  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, desktop_resize), NULL, NULL,
    142  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    143  remmina_protocol_widget_signals[UPDATE_ALIGN_SIGNAL] = g_signal_new("update-align", G_TYPE_FROM_CLASS(klass),
    144  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, update_align), NULL, NULL,
    145  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    146  remmina_protocol_widget_signals[LOCK_DYNRES_SIGNAL] = g_signal_new("lock-dynres", G_TYPE_FROM_CLASS(klass),
    147  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, lock_dynres), NULL, NULL,
    148  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    149  remmina_protocol_widget_signals[UNLOCK_DYNRES_SIGNAL] = g_signal_new("unlock-dynres", G_TYPE_FROM_CLASS(klass),
    150  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, unlock_dynres), NULL, NULL,
    151  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    152 }
    153 
    154 
    156 {
    157  TRACE_CALL(__func__);
    158  int i;
    159 
    160  if (gp->priv && gp->priv->ssh_tunnels) {
    161  for (i = 0; i < gp->priv->ssh_tunnels->len; i++) {
    162 #ifdef HAVE_LIBSSH
    164 #else
    165  REMMINA_DEBUG("LibSSH support turned off, no need to free SSH tunnel data");
    166 #endif
    167  }
    168  g_ptr_array_set_size(gp->priv->ssh_tunnels, 0);
    169  }
    170 }
    171 
    172 
    174 {
    175  TRACE_CALL(__func__);
    176 
    177  g_free(gp->priv->username);
    178  gp->priv->username = NULL;
    179 
    180  g_free(gp->priv->password);
    181  gp->priv->password = NULL;
    182 
    183  g_free(gp->priv->domain);
    184  gp->priv->domain = NULL;
    185 
    186  g_free(gp->priv->cacert);
    187  gp->priv->cacert = NULL;
    188 
    189  g_free(gp->priv->cacrl);
    190  gp->priv->cacrl = NULL;
    191 
    192  g_free(gp->priv->clientcert);
    193  gp->priv->clientcert = NULL;
    194 
    195  g_free(gp->priv->clientkey);
    196  gp->priv->clientkey = NULL;
    197 
    198  g_free(gp->priv->features);
    199  gp->priv->features = NULL;
    200 
    201  g_free(gp->priv->error_message);
    202  gp->priv->error_message = NULL;
    203 
    204  g_free(gp->priv->remmina_file);
    205  gp->priv->remmina_file = NULL;
    206 
    207  g_free(gp->priv);
    208  gp->priv = NULL;
    209 
    211 
    212  if (gp->priv && gp->priv->ssh_tunnels) {
    213  g_ptr_array_free(gp->priv->ssh_tunnels, TRUE);
    214  gp->priv->ssh_tunnels = NULL;
    215  }
    216 }
    217 
    219 {
    220  TRACE_CALL(__func__);
    221  GtkWidget *child;
    222 
    223  child = gtk_bin_get_child(GTK_BIN(gp));
    224 
    225  if (child) {
    226  gtk_widget_set_can_focus(child, TRUE);
    227  gtk_widget_grab_focus(child);
    228  }
    229 }
    230 
    232 {
    233  TRACE_CALL(__func__);
    235 
    236  priv = g_new0(RemminaProtocolWidgetPriv, 1);
    237  gp->priv = priv;
    238  gp->priv->user_disconnect = FALSE;
    239  gp->priv->closed = TRUE;
    240  gp->priv->ssh_tunnels = g_ptr_array_new();
    241 
    242  g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL);
    243 }
    244 
    246 {
    247  TRACE_CALL(__func__);
    248  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    249 
    250  REMMINA_DEBUG("Opening connection");
    251 
    253  RemminaProtocolFeature *feature;
    254  gint num_plugin;
    255  gint num_ssh;
    256 
    257  gp->priv->closed = FALSE;
    258 
    259  plugin = gp->priv->plugin;
    260  plugin->init(gp);
    261 
    262  for (num_plugin = 0, feature = (RemminaProtocolFeature *)plugin->features; feature && feature->type; num_plugin++, feature++) {
    263  }
    264 
    265  num_ssh = 0;
    266 #ifdef HAVE_LIBSSH
    267  if (remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    268  num_ssh += 2;
    269 
    270 #endif
    271  if (num_plugin + num_ssh == 0) {
    272  gp->priv->features = NULL;
    273  } else {
    274  gp->priv->features = g_new0(RemminaProtocolFeature, num_plugin + num_ssh + 1);
    275  feature = gp->priv->features;
    276  if (plugin->features) {
    277  memcpy(feature, plugin->features, sizeof(RemminaProtocolFeature) * num_plugin);
    278  feature += num_plugin;
    279  }
    280 #ifdef HAVE_LIBSSH
    281  REMMINA_DEBUG("Have SSH");
    282  if (num_ssh) {
    284  feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SSH;
    285  feature->opt1 = _("Connect via SSH from a new terminal");
    287  feature->opt2 = "utilities-terminal";
    289  feature->opt3 = NULL;
    291  feature++;
    292 
    294  feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SFTP;
    295  feature->opt1 = _("Open SFTP transfer…");
    297  feature->opt2 = "folder-remote";
    299  feature->opt3 = NULL;
    301  feature++;
    302  }
    304 #endif
    305  }
    306 
    307  if (!plugin->open_connection(gp))
    309 }
    310 
    311 static void cancel_open_connection_cb(void *cbdata, int btn)
    312 {
    314 
    316 }
    317 
    319 {
    320  TRACE_CALL(__func__);
    321  gchar *s;
    322  const gchar *name;
    323  RemminaMessagePanel *mp;
    324 
    325  /* Exec precommand before everything else */
    327  remmina_message_panel_setup_progress(mp, _("Executing external commands…"), NULL, NULL);
    329 
    330  remmina_ext_exec_new(gp->priv->remmina_file, "precommand");
    332 
    333  name = remmina_file_get_string(gp->priv->remmina_file, "name");
    334  // TRANSLATORS: “%s” is a placeholder for the connection profile name
    335  s = g_strdup_printf(_("Connecting to “%s”…"), (name ? name : "*"));
    336 
    339  g_free(s);
    340  gp->priv->connect_message_panel = mp;
    342 
    344 }
    345 
    346 static gboolean conn_closed_real(gpointer data, int button){
    347  TRACE_CALL(__func__);
    349 
    350  #ifdef HAVE_LIBSSH
    351  /* This will close all tunnels */
    353 #endif
    354  /* Exec postcommand */
    355  remmina_ext_exec_new(gp->priv->remmina_file, "postcommand");
    356  /* Notify listeners (usually rcw) that the connection is closed */
    357  g_signal_emit_by_name(G_OBJECT(gp), "disconnect");
    358  return G_SOURCE_REMOVE;
    359 
    360 }
    361 
    362 static gboolean conn_closed(gpointer data)
    363 {
    364  TRACE_CALL(__func__);
    366 
    367  if (!gp->priv->user_disconnect && !gp->priv->has_error){
    368  const char* msg = "Plugin Disconnected";
    369  if (gp->priv->has_error){
    372  }
    373  gp->priv->user_disconnect = FALSE;
    374  RemminaMessagePanel* mp = remmina_message_panel_new();
    377  }
    378  else{
    379  conn_closed_real(gp, 0);
    380  }
    381 
    382 }
    383 
    385 {
    386  /* User told us that they closed the connection,
    387  * or the connection was closed with a known error,
    388  * add async event to main thread to complete our close tasks */
    389  TRACE_CALL(__func__);
    390  gp->priv->closed = TRUE;
    391  g_idle_add(conn_closed, (gpointer)gp);
    392 }
    393 
    394 static gboolean conn_opened(gpointer data)
    395 {
    396  TRACE_CALL(__func__);
    398 
    399 #ifdef HAVE_LIBSSH
    400  if (gp->priv->ssh_tunnels) {
    401  for (guint i = 0; i < gp->priv->ssh_tunnels->len; i++)
    403  }
    404 #endif
    405  if (gp->priv->listen_message_panel) {
    407  gp->priv->listen_message_panel = NULL;
    408  }
    409  if (gp->priv->connect_message_panel) {
    411  gp->priv->connect_message_panel = NULL;
    412  }
    413  if (gp->priv->retry_message_panel) {
    415  gp->priv->retry_message_panel = NULL;
    416  }
    417  g_signal_emit_by_name(G_OBJECT(gp), "connect");
    418  return G_SOURCE_REMOVE;
    419 }
    420 
    422 {
    423  /* Plugin told us that it opened the connection,
    424  * add async event to main thread to complete our close tasks */
    425  TRACE_CALL(__func__);
    426  g_idle_add(conn_opened, (gpointer)gp);
    427 }
    428 
    429 static gboolean update_align(gpointer data)
    430 {
    431  TRACE_CALL(__func__);
    433 
    434  g_signal_emit_by_name(G_OBJECT(gp), "update-align");
    435  return G_SOURCE_REMOVE;
    436 }
    437 
    439 {
    440  /* Called by the plugin to do updates on rcw */
    441  TRACE_CALL(__func__);
    442  g_idle_add(update_align, (gpointer)gp);
    443 }
    444 
    445 static gboolean lock_dynres(gpointer data)
    446 {
    447  TRACE_CALL(__func__);
    449 
    450  g_signal_emit_by_name(G_OBJECT(gp), "lock-dynres");
    451  return G_SOURCE_REMOVE;
    452 }
    453 
    454 static gboolean unlock_dynres(gpointer data)
    455 {
    456  TRACE_CALL(__func__);
    458 
    459  g_signal_emit_by_name(G_OBJECT(gp), "unlock-dynres");
    460  return G_SOURCE_REMOVE;
    461 }
    462 
    464 {
    465  /* Called by the plugin to do updates on rcw */
    466  TRACE_CALL(__func__);
    467  g_idle_add(lock_dynres, (gpointer)gp);
    468 }
    469 
    471 {
    472  /* Called by the plugin to do updates on rcw */
    473  TRACE_CALL(__func__);
    474  g_idle_add(unlock_dynres, (gpointer)gp);
    475 }
    476 
    477 static gboolean desktop_resize(gpointer data)
    478 {
    479  TRACE_CALL(__func__);
    481 
    482  g_signal_emit_by_name(G_OBJECT(gp), "desktop-resize");
    483  return G_SOURCE_REMOVE;
    484 }
    485 
    487 {
    488  /* Called by the plugin to do updates on rcw */
    489  TRACE_CALL(__func__);
    490  g_idle_add(desktop_resize, (gpointer)gp);
    491 }
    492 
    493 
    495 {
    496  TRACE_CALL(__func__);
    497 
    498  /* kindly ask the protocol plugin to close the connection.
    499  * Nothing else is done here. */
    500 
    501  if (!GTK_IS_WIDGET(gp))
    502  return;
    503 
    504  if (gp->priv->chat_window) {
    505  gtk_widget_destroy(gp->priv->chat_window);
    506  gp->priv->chat_window = NULL;
    507  }
    508 
    509  if (gp->priv->closed) {
    510  /* Connection is already closed by the plugin, but
    511  * rcw is asking to close again (usually after an error panel)
    512  */
    513  /* Clear the current error, or "disconnect" signal func will reshow a panel */
    515  g_signal_emit_by_name(G_OBJECT(gp), "disconnect");
    516  return;
    517  }
    518  gp->priv->user_disconnect = TRUE;
    519 
    520  /* Ask the plugin to close, async.
    521  * The plugin will emit a "disconnect" signal on gp to call our
    522  * remmina_protocol_widget_on_disconnected() when done */
    523  gp->priv->plugin->close_connection(gp);
    524 
    525  return;
    526 }
    527 
    531 {
    532  return gp->priv->plugin->send_keystrokes ? TRUE : FALSE;
    533 }
    534 
    539 {
    540  TRACE_CALL(__func__);
    541  gchar *keystrokes = g_object_get_data(G_OBJECT(widget), "keystrokes");
    542  guint *keyvals;
    543  gint i;
    544  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    545  gunichar character;
    546  guint keyval;
    547  GdkKeymapKey *keys;
    548  gint n_keys;
    549 
    550  /* Single keystroke replace */
    551  typedef struct _KeystrokeReplace {
    552  gchar * search;
    553  gchar * replace;
    554  guint keyval;
    555  } KeystrokeReplace;
    556  /* Special characters to replace */
    557  KeystrokeReplace keystrokes_replaces[] =
    558  {
    559  { "\\n", "\n", GDK_KEY_Return },
    560  { "\\t", "\t", GDK_KEY_Tab },
    561  { "\\b", "\b", GDK_KEY_BackSpace },
    562  { "\\e", "\e", GDK_KEY_Escape },
    563  { "\\\\", "\\", GDK_KEY_backslash },
    564  { NULL, NULL, 0 }
    565  };
    566 
    567  /* Keystrokes can only be sent to plugins that accepts them */
    569  /* Replace special characters */
    570  for (i = 0; keystrokes_replaces[i].replace; i++) {
    571  REMMINA_DEBUG("Keystrokes before replacement is \'%s\'", keystrokes);
    572  keystrokes = g_strdup(remmina_public_str_replace_in_place(keystrokes,
    573  keystrokes_replaces[i].search,
    574  keystrokes_replaces[i].replace));
    575  REMMINA_DEBUG("Keystrokes after replacement is \'%s\'", keystrokes);
    576  }
    577  gchar *iter = g_strdup(keystrokes);
    578  keyvals = (guint *)g_malloc(strlen(keystrokes));
    579  while (TRUE) {
    580  /* Process each character in the keystrokes */
    581  character = g_utf8_get_char_validated(iter, -1);
    582  if (character == 0)
    583  break;
    584  keyval = gdk_unicode_to_keyval(character);
    585  /* Replace all the special character with its keyval */
    586  for (i = 0; keystrokes_replaces[i].replace; i++) {
    587  if (character == keystrokes_replaces[i].replace[0]) {
    588  keys = g_new0(GdkKeymapKey, 1);
    589  keyval = keystrokes_replaces[i].keyval;
    590  /* A special character was generated, no keyval lookup needed */
    591  character = 0;
    592  break;
    593  }
    594  }
    595  /* Decode character if it’s not a special character */
    596  if (character) {
    597  /* get keyval without modifications */
    598  if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
    599  g_warning("keyval 0x%04x has no keycode!", keyval);
    600  iter = g_utf8_find_next_char(iter, NULL);
    601  continue;
    602  }
    603  }
    604  /* Add modifier keys */
    605  n_keys = 0;
    606  if (keys->level & 1)
    607  keyvals[n_keys++] = GDK_KEY_Shift_L;
    608  if (keys->level & 2)
    609  keyvals[n_keys++] = GDK_KEY_Alt_R;
    610  keyvals[n_keys++] = keyval;
    611  /* Send keystroke to the plugin */
    612  gp->priv->plugin->send_keystrokes(gp, keyvals, n_keys);
    613  g_free(keys);
    614  /* Process next character in the keystrokes */
    615  iter = g_utf8_find_next_char(iter, NULL);
    616  }
    617  g_free(keyvals);
    618  }
    619  g_free(keystrokes);
    620  return;
    621 }
    622 
    629 void remmina_protocol_widget_send_clip_strokes(GtkClipboard *clipboard, const gchar *clip_text, gpointer data)
    630 {
    631  TRACE_CALL(__func__);
    632  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    633  gchar *text = g_utf8_normalize(clip_text, -1, G_NORMALIZE_DEFAULT_COMPOSE);
    634  guint *keyvals;
    635  gint i;
    636  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    637  gunichar character;
    638  guint keyval;
    639  GdkKeymapKey *keys;
    640  gint n_keys;
    641 
    642  /* Single keystroke replace */
    643  typedef struct _KeystrokeReplace {
    644  gchar * search;
    645  gchar * replace;
    646  guint keyval;
    647  } KeystrokeReplace;
    648  /* Special characters to replace */
    649  KeystrokeReplace text_replaces[] =
    650  {
    651  { "\\n", "\n", GDK_KEY_Return },
    652  { "\\t", "\t", GDK_KEY_Tab },
    653  { "\\b", "\b", GDK_KEY_BackSpace },
    654  { "\\e", "\e", GDK_KEY_Escape },
    655  { "\\\\", "\\", GDK_KEY_backslash },
    656  { NULL, NULL, 0 }
    657  };
    658 
    660  if (text) {
    661  /* Replace special characters */
    662  for (i = 0; text_replaces[i].replace; i++) {
    663  REMMINA_DEBUG("Text clipboard before replacement is \'%s\'", text);
    664  text = g_strdup(remmina_public_str_replace_in_place(text,
    665  text_replaces[i].search,
    666  text_replaces[i].replace));
    667  REMMINA_DEBUG("Text clipboard after replacement is \'%s\'", text);
    668  }
    669  gchar *iter = g_strdup(text);
    670  REMMINA_DEBUG("Iter: %s", iter),
    671  keyvals = (guint *)g_malloc(strlen(text));
    672  while (TRUE) {
    673  /* Process each character in the keystrokes */
    674  character = g_utf8_get_char_validated(iter, -1);
    675  REMMINA_DEBUG("Char: U+%04" G_GINT32_FORMAT"X", character);
    676  if (character == 0)
    677  break;
    678  keyval = gdk_unicode_to_keyval(character);
    679  REMMINA_DEBUG("Keyval: %u", keyval);
    680  /* Replace all the special character with its keyval */
    681  for (i = 0; text_replaces[i].replace; i++) {
    682  if (character == text_replaces[i].replace[0]) {
    683  keys = g_new0(GdkKeymapKey, 1);
    684  keyval = text_replaces[i].keyval;
    685  REMMINA_DEBUG("Special Keyval: %u", keyval);
    686  /* A special character was generated, no keyval lookup needed */
    687  character = 0;
    688  break;
    689  }
    690  }
    691  /* Decode character if it’s not a special character */
    692  if (character) {
    693  /* get keyval without modifications */
    694  if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
    695  REMMINA_WARNING("keyval 0x%04x has no keycode!", keyval);
    696  iter = g_utf8_find_next_char(iter, NULL);
    697  continue;
    698  }
    699  }
    700  /* Add modifier keys */
    701  n_keys = 0;
    702  if (keys->level & 1)
    703  keyvals[n_keys++] = GDK_KEY_Shift_L;
    704  if (keys->level & 2)
    705  keyvals[n_keys++] = GDK_KEY_Alt_R;
    706  /*
    707  * @fixme heap buffer overflow
    708  * In some cases, for example sending \t as the only sequence
    709  * may lead to a buffer overflow
    710  */
    711  keyvals[n_keys++] = keyval;
    712  /* Send keystroke to the plugin */
    713  gp->priv->plugin->send_keystrokes(gp, keyvals, n_keys);
    714  g_free(keys);
    715  /* Process next character in the keystrokes */
    716  iter = g_utf8_find_next_char(iter, NULL);
    717  }
    718  g_free(keyvals);
    719  }
    720  g_free(text);
    721  }
    722  return;
    723 }
    724 
    726 {
    727  TRACE_CALL(__func__);
    728  GtkClipboard *clipboard;
    729 
    730  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
    731 
    732  /* Request the contents of the clipboard, contents_received will be
    733  * called when we do get the contents.
    734  */
    735  gtk_clipboard_request_text(clipboard,
    737 }
    738 
    740 {
    741  TRACE_CALL(__func__);
    742  if (!gp->priv->plugin->get_plugin_screenshot) {
    743  REMMINA_DEBUG("plugin screenshot function is not implemented, using core Remmina functionality");
    744  return FALSE;
    745  }
    746 
    747  return gp->priv->plugin->get_plugin_screenshot(gp, rpsd);
    748 }
    749 
    751 {
    752  TRACE_CALL(__func__);
    753  if (!gp->priv->plugin->map_event) {
    754  REMMINA_DEBUG("Map plugin function not implemented");
    755  return FALSE;
    756  }
    757 
    758  REMMINA_DEBUG("Calling plugin mapping function");
    759  return gp->priv->plugin->map_event(gp);
    760 }
    761 
    763 {
    764  TRACE_CALL(__func__);
    765  if (!gp->priv->plugin->unmap_event) {
    766  REMMINA_DEBUG("Unmap plugin function not implemented");
    767  return FALSE;
    768  }
    769 
    770  REMMINA_DEBUG("Calling plugin unmapping function");
    771  return gp->priv->plugin->unmap_event(gp);
    772 }
    773 
    775 {
    776  TRACE_CALL(__func__);
    777 
    778  REMMINA_DEBUG("Emitting signals should be used from the object itself, not from another object");
    779  raise(SIGINT);
    780 
    782  /* Allow the execution of this function from a non main thread */
    784  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    785  d->func = FUNC_PROTOCOLWIDGET_EMIT_SIGNAL;
    786  d->p.protocolwidget_emit_signal.signal_name = signal_name;
    787  d->p.protocolwidget_emit_signal.gp = gp;
    789  g_free(d);
    790  return;
    791  }
    792  g_signal_emit_by_name(G_OBJECT(gp), signal_name);
    793 }
    794 
    796 {
    797  TRACE_CALL(__func__);
    798  return gp->priv->features;
    799 }
    800 
    802 {
    803  TRACE_CALL(__func__);
    804  const RemminaProtocolFeature *feature;
    805 
    806 #ifdef HAVE_LIBSSH
    808  remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    809  return TRUE;
    810 
    811 #endif
    812  for (feature = gp->priv->plugin->features; feature && feature->type; feature++)
    813  if (feature->type == type)
    814  return TRUE;
    815  return FALSE;
    816 }
    817 
    819 {
    820  TRACE_CALL(__func__);
    821  return gp->priv->plugin->query_feature(gp, feature);
    822 }
    823 
    825 {
    826  TRACE_CALL(__func__);
    827  const RemminaProtocolFeature *feature;
    828 
    829  for (feature = gp->priv->plugin->features; feature && feature->type; feature++) {
    830  if (feature->type == type && (id == 0 || feature->id == id)) {
    832  break;
    833  }
    834  }
    835 }
    836 
    838 {
    839  TRACE_CALL(__func__);
    840  switch (feature->id) {
    841 #ifdef HAVE_LIBSSH
    842  case REMMINA_PROTOCOL_FEATURE_TOOL_SSH:
    843  if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) {
    846  (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0], NULL);
    847  return;
    848  }
    849  break;
    850 
    851  case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP:
    852  if (gp->priv->ssh_tunnels && gp->priv->ssh_tunnels->len > 0) {
    855  gp->priv->ssh_tunnels->pdata[0], NULL);
    856  return;
    857  }
    858  break;
    859 #endif
    860  default:
    861  break;
    862  }
    863  gp->priv->plugin->call_feature(gp, feature);
    864 }
    865 
    866 static gboolean remmina_protocol_widget_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    867 {
    868  TRACE_CALL(__func__);
    869  if (gp->priv->hostkey_func)
    870  return gp->priv->hostkey_func(gp, event->keyval, FALSE);
    871  return FALSE;
    872 }
    873 
    874 static gboolean remmina_protocol_widget_on_key_release(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    875 {
    876  TRACE_CALL(__func__);
    877  if (gp->priv->hostkey_func)
    878  return gp->priv->hostkey_func(gp, event->keyval, TRUE);
    879 
    880  return FALSE;
    881 }
    882 
    884 {
    885  TRACE_CALL(__func__);
    886  g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(remmina_protocol_widget_on_key_press), gp);
    887  g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(remmina_protocol_widget_on_key_release), gp);
    888 }
    889 
    891 {
    892  TRACE_CALL(__func__);
    893  gp->priv->hostkey_func = func;
    894 }
    895 
    896 RemminaMessagePanel *remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    897 {
    898  RemminaMessagePanel *mp;
    899 
    901  /* Allow the execution of this function from a non main thread */
    903  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    904  d->func = FUNC_PROTOCOLWIDGET_MPPROGRESS;
    905  d->p.protocolwidget_mpprogress.cnnobj = cnnobj;
    906  d->p.protocolwidget_mpprogress.message = msg;
    907  d->p.protocolwidget_mpprogress.response_callback = response_callback;
    908  d->p.protocolwidget_mpprogress.response_callback_data = response_callback_data;
    910  mp = d->p.protocolwidget_mpprogress.ret_mp;
    911  g_free(d);
    912  return mp;
    913  }
    914 
    916  remmina_message_panel_setup_progress(mp, msg, response_callback, response_callback_data);
    917  rco_show_message_panel(cnnobj, mp);
    918  return mp;
    919 }
    920 
    921 void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    922 {
    924  /* Allow the execution of this function from a non main thread */
    926  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    927  d->func = FUNC_PROTOCOLWIDGET_MPDESTROY;
    928  d->p.protocolwidget_mpdestroy.cnnobj = cnnobj;
    929  d->p.protocolwidget_mpdestroy.mp = mp;
    931  g_free(d);
    932  return;
    933  }
    934  rco_destroy_message_panel(cnnobj, mp);
    935 }
    936 
    937 #ifdef HAVE_LIBSSH
    938 static void cancel_init_tunnel_cb(void *cbdata, int btn)
    939 {
    940  printf("Remmina: Cancelling an opening tunnel is not implemented\n");
    941 }
    942 
    944 {
    945  TRACE_CALL(__func__);
    946  RemminaSSHTunnel *tunnel;
    947  gint ret;
    948  gchar *msg;
    949  RemminaMessagePanel *mp;
    950  gboolean partial = FALSE;
    951  gboolean cont = FALSE;
    952 
    954 
    955  REMMINA_DEBUG("Creating SSH tunnel to “%s” via SSH…", REMMINA_SSH(tunnel)->server);
    956  // TRANSLATORS: “%s” is a placeholder for an hostname or an IP address.
    957  msg = g_strdup_printf(_("Connecting to “%s” via SSH…"), REMMINA_SSH(tunnel)->server);
    958 
    960  g_free(msg);
    961 
    962 
    963 
    964  while (1) {
    965  if (!partial) {
    966  if (!remmina_ssh_init_session(REMMINA_SSH(tunnel))) {
    967  REMMINA_DEBUG("SSH Tunnel init session error: %s", REMMINA_SSH(tunnel)->error);
    968  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    969  // exit the loop here: OK
    970  break;
    971  }
    972  }
    973 
    974  ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file);
    975  REMMINA_DEBUG("Tunnel auth returned %d", ret);
    976  switch (ret) {
    978  REMMINA_DEBUG("Authentication success");
    979  break;
    981  REMMINA_DEBUG("Continue with the next auth method");
    982  partial = TRUE;
    983  // Continue the loop: OK
    984  continue;
    985  break;
    987  REMMINA_DEBUG("Reconnecting…");
    988  if (REMMINA_SSH(tunnel)->session) {
    989  ssh_disconnect(REMMINA_SSH(tunnel)->session);
    990  ssh_free(REMMINA_SSH(tunnel)->session);
    991  REMMINA_SSH(tunnel)->session = NULL;
    992  }
    993  g_free(REMMINA_SSH(tunnel)->callback);
    994  // Continue the loop: OK
    995  continue;
    996  break;
    998  REMMINA_DEBUG("Interrupted by the user");
    999  // exit the loop here: OK
    1000  goto BREAK;
    1001  break;
    1002  default:
    1003  REMMINA_DEBUG("Error during the authentication: %s", REMMINA_SSH(tunnel)->error);
    1004  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1005  // exit the loop here: OK
    1006  goto BREAK;
    1007  }
    1008 
    1009 
    1010  cont = TRUE;
    1011  break;
    1012  }
    1013 
    1014 #if 0
    1015 
    1016  if (!remmina_ssh_init_session(REMMINA_SSH(tunnel))) {
    1017  REMMINA_DEBUG("Cannot init SSH session with tunnel struct");
    1018  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1019  remmina_ssh_tunnel_free(tunnel);
    1020  return NULL;
    1021  }
    1022 
    1023  ret = remmina_ssh_auth_gui(REMMINA_SSH(tunnel), gp, gp->priv->remmina_file);
    1024  REMMINA_DEBUG("Tunnel auth returned %d", ret);
    1025  if (ret != REMMINA_SSH_AUTH_SUCCESS) {
    1026  if (ret != REMMINA_SSH_AUTH_USERCANCEL)
    1027  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1028  remmina_ssh_tunnel_free(tunnel);
    1029  return NULL;
    1030  }
    1031 
    1032 #endif
    1033 
    1034 BREAK:
    1035  if (!cont) {
    1036  remmina_ssh_tunnel_free(tunnel);
    1037  return NULL;
    1038  }
    1040 
    1041  return tunnel;
    1042 }
    1043 #endif
    1044 
    1045 
    1046 #ifdef HAVE_LIBSSH
    1047 static void cancel_start_direct_tunnel_cb(void *cbdata, int btn)
    1048 {
    1049  printf("Remmina: Cancelling start_direct_tunnel is not implemented\n");
    1050 }
    1051 
    1052 static gboolean remmina_protocol_widget_tunnel_destroy(RemminaSSHTunnel *tunnel, gpointer data)
    1053 {
    1054  TRACE_CALL(__func__);
    1055  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1056  guint idx = 0;
    1057 
    1058 #if GLIB_CHECK_VERSION(2, 54, 0)
    1059  gboolean found = g_ptr_array_find(gp->priv->ssh_tunnels, tunnel, &idx);
    1060 #else
    1061  int i;
    1062  gboolean found = FALSE;
    1063  for (i = 0; i < gp->priv->ssh_tunnels->len; i++) {
    1064  if ((RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[i] == tunnel) {
    1065  found = TRUE;
    1066  idx = i;
    1067  }
    1068  }
    1069 #endif
    1070 
    1071  printf("Tunnel %s found at idx = %d\n", found ? "yes": "not", idx);
    1072 
    1073  if (found) {
    1074 #ifdef HAVE_LIBSSH
    1075  REMMINA_DEBUG("[Tunnel with idx %u has been disconnected", idx);
    1076  remmina_ssh_tunnel_free(tunnel);
    1077 #endif
    1078  g_ptr_array_remove(gp->priv->ssh_tunnels, tunnel);
    1079  }
    1080  return TRUE;
    1081 }
    1082 #endif
    1083 
    1088 gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
    1089 {
    1090  TRACE_CALL(__func__);
    1091  const gchar *server;
    1092  const gchar *ssh_tunnel_server;
    1093  gchar *ssh_tunnel_host, *srv_host, *dest;
    1094  gint srv_port, ssh_tunnel_port = 0;
    1095 
    1096  REMMINA_DEBUG("SSH tunnel initialization…");
    1097 
    1098  server = remmina_file_get_string(gp->priv->remmina_file, "server");
    1099  ssh_tunnel_server = remmina_file_get_string(gp->priv->remmina_file, "ssh_tunnel_server");
    1100 
    1101  if (!server)
    1102  return g_strdup("");
    1103 
    1104  if (strstr(g_strdup(server), "unix:///") != NULL) {
    1105  REMMINA_DEBUG("%s is a UNIX socket", server);
    1106  return g_strdup(server);
    1107  }
    1108 
    1109  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1110  remmina_public_get_server_port(server, default_port, &srv_host, &srv_port);
    1111  REMMINA_DEBUG("Calling remmina_public_get_server_port (tunnel)");
    1112  remmina_public_get_server_port(ssh_tunnel_server, 22, &ssh_tunnel_host, &ssh_tunnel_port);
    1113  REMMINA_DEBUG("server: %s, port: %d", srv_host, srv_port);
    1114 
    1115  if (port_plus && srv_port < 100)
    1116  /* Protocols like VNC supports using instance number :0, :1, etc. as port number. */
    1117  srv_port += default_port;
    1118 
    1119 #ifdef HAVE_LIBSSH
    1120  gchar *msg;
    1121  RemminaMessagePanel *mp;
    1122  RemminaSSHTunnel *tunnel;
    1123 
    1124  if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE)) {
    1125  dest = g_strdup_printf("[%s]:%i", srv_host, srv_port);
    1126  g_free(srv_host);
    1127  g_free(ssh_tunnel_host);
    1128  return dest;
    1129  }
    1130 
    1132  if (!tunnel) {
    1133  g_free(srv_host);
    1134  g_free(ssh_tunnel_host);
    1135  REMMINA_DEBUG("remmina_protocol_widget_init_tunnel failed with error is %s",
    1137  return NULL;
    1138  }
    1139 
    1140  // TRANSLATORS: “%s” is a placeholder for an hostname or an IP address.
    1141  msg = g_strdup_printf(_("Connecting to “%s” via SSH…"), server);
    1143  g_free(msg);
    1144 
    1145  if (remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_loopback", FALSE)) {
    1146  g_free(srv_host);
    1147  g_free(ssh_tunnel_host);
    1148  ssh_tunnel_host = NULL;
    1149  srv_host = g_strdup("127.0.0.1");
    1150  }
    1151 
    1152  REMMINA_DEBUG("Starting tunnel to: %s, port: %d", ssh_tunnel_host, ssh_tunnel_port);
    1153  if (!remmina_ssh_tunnel_open(tunnel, srv_host, srv_port, remmina_pref.sshtunnel_port)) {
    1154  g_free(srv_host);
    1155  g_free(ssh_tunnel_host);
    1156  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1157  remmina_ssh_tunnel_free(tunnel);
    1158  return NULL;
    1159  }
    1160  g_free(srv_host);
    1161  g_free(ssh_tunnel_host);
    1162 
    1164 
    1166  tunnel->destroy_func_callback_data = (gpointer)gp;
    1167 
    1168  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1169 
    1170  return g_strdup_printf("127.0.0.1:%i", remmina_pref.sshtunnel_port);
    1171 
    1172 #else
    1173 
    1174  dest = g_strdup_printf("[%s]:%i", srv_host, srv_port);
    1175  g_free(srv_host);
    1176  g_free(ssh_tunnel_host);
    1177  return dest;
    1178 
    1179 #endif
    1180 }
    1181 
    1182 #ifdef HAVE_LIBSSH
    1183 static void cancel_start_reverse_tunnel_cb(void *cbdata, int btn)
    1184 {
    1185  printf("Remmina: Cancelling start_reverse_tunnel is not implemented\n");
    1186 }
    1187 #endif
    1188 
    1189 
    1191 {
    1192  TRACE_CALL(__func__);
    1193 #ifdef HAVE_LIBSSH
    1194  gchar *msg;
    1195  RemminaMessagePanel *mp;
    1196  RemminaSSHTunnel *tunnel;
    1197 
    1198  if (!remmina_file_get_int(gp->priv->remmina_file, "ssh_tunnel_enabled", FALSE))
    1199  return TRUE;
    1200 
    1201  if (!(tunnel = remmina_protocol_widget_init_tunnel(gp)))
    1202  return FALSE;
    1203 
    1204  // TRANSLATORS: “%i” is a placeholder for a TCP port number.
    1205  msg = g_strdup_printf(_("Awaiting incoming SSH connection on port %i…"), remmina_file_get_int(gp->priv->remmina_file, "listenport", 0));
    1207  g_free(msg);
    1208 
    1209  if (!remmina_ssh_tunnel_reverse(tunnel, remmina_file_get_int(gp->priv->remmina_file, "listenport", 0), local_port)) {
    1210  remmina_ssh_tunnel_free(tunnel);
    1211  remmina_protocol_widget_set_error(gp, REMMINA_SSH(tunnel)->error);
    1212  return FALSE;
    1213  }
    1215  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1216 #endif
    1217 
    1218  return TRUE;
    1219 }
    1220 
    1221 gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...)
    1222 {
    1223  TRACE_CALL(__func__);
    1224 #ifdef HAVE_LIBSSH
    1225  RemminaSSHTunnel *tunnel;
    1226  ssh_channel channel;
    1227  gint status;
    1228  gboolean ret = FALSE;
    1229  gchar *cmd, *ptr;
    1230  va_list args;
    1231 
    1232  if (gp->priv->ssh_tunnels->len < 1)
    1233  return FALSE;
    1234 
    1235  tunnel = (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0];
    1236 
    1237  if ((channel = ssh_channel_new(REMMINA_SSH(tunnel)->session)) == NULL)
    1238  return FALSE;
    1239 
    1240  va_start(args, fmt);
    1241  cmd = g_strdup_vprintf(fmt, args);
    1242  va_end(args);
    1243 
    1244  if (ssh_channel_open_session(channel) == SSH_OK &&
    1245  ssh_channel_request_exec(channel, cmd) == SSH_OK) {
    1246  if (wait) {
    1247  ssh_channel_send_eof(channel);
    1248  status = ssh_channel_get_exit_status(channel);
    1249  ptr = strchr(cmd, ' ');
    1250  if (ptr) *ptr = '\0';
    1251  switch (status) {
    1252  case 0:
    1253  ret = TRUE;
    1254  break;
    1255  case 127:
    1256  // TRANSLATORS: “%s” is a place holder for a unix command path.
    1257  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
    1258  _("The “%s” command is not available on the SSH server."), cmd);
    1259  break;
    1260  default:
    1261  // TRANSLATORS: “%s” is a place holder for a unix command path. “%i” is a placeholder for an error code number.
    1262  remmina_ssh_set_application_error(REMMINA_SSH(tunnel),
    1263  _("Could not run the “%s” command on the SSH server (status = %i)."), cmd, status);
    1264  break;
    1265  }
    1266  } else {
    1267  ret = TRUE;
    1268  }
    1269  } else {
    1270  // TRANSLATORS: %s is a placeholder for an error message
    1271  remmina_ssh_set_error(REMMINA_SSH(tunnel), _("Could not run command. %s"));
    1272  }
    1273  g_free(cmd);
    1274  if (wait)
    1275  ssh_channel_close(channel);
    1276  ssh_channel_free(channel);
    1277  return ret;
    1278 
    1279 #else
    1280 
    1281  return FALSE;
    1282 
    1283 #endif
    1284 }
    1285 
    1286 #ifdef HAVE_LIBSSH
    1288 {
    1289  TRACE_CALL(__func__);
    1290  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1291  gchar *server;
    1292  gint port;
    1293  gboolean ret;
    1294 
    1295  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1296  remmina_public_get_server_port(remmina_file_get_string(gp->priv->remmina_file, "server"), 177, &server, &port);
    1297  ret = ((RemminaXPortTunnelInitFunc)gp->priv->init_func)(gp,
    1298  tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
    1299  g_free(server);
    1300 
    1301  return ret;
    1302 }
    1303 
    1305 {
    1306  TRACE_CALL(__func__);
    1307  return TRUE;
    1308 }
    1309 
    1311 {
    1312  TRACE_CALL(__func__);
    1313  RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(data);
    1314 
    1315  if (REMMINA_SSH(tunnel)->error)
    1316  remmina_protocol_widget_set_error(gp, "%s", REMMINA_SSH(tunnel)->error);
    1317 
    1318  IDLE_ADD((GSourceFunc)remmina_protocol_widget_close_connection, gp);
    1319  return TRUE;
    1320 }
    1321 #endif
    1322 #ifdef HAVE_LIBSSH
    1323 static void cancel_connect_xport_cb(void *cbdata, int btn)
    1324 {
    1325  printf("Remmina: Cancelling an XPort connection is not implemented\n");
    1326 }
    1327 #endif
    1329 {
    1330  TRACE_CALL(__func__);
    1331 #ifdef HAVE_LIBSSH
    1332  gboolean bindlocalhost;
    1333  gchar *server;
    1334  gchar *msg;
    1335  RemminaMessagePanel *mp;
    1336  RemminaSSHTunnel *tunnel;
    1337 
    1338  if (!(tunnel = remmina_protocol_widget_init_tunnel(gp))) return FALSE;
    1339 
    1340  // TRANSLATORS: “%s” is a placeholder for a hostname or IP address.
    1341  msg = g_strdup_printf(_("Connecting to %s via SSH…"), remmina_file_get_string(gp->priv->remmina_file, "server"));
    1343  g_free(msg);
    1344 
    1345  gp->priv->init_func = init_func;
    1349  tunnel->callback_data = gp;
    1350 
    1351  REMMINA_DEBUG("Calling remmina_public_get_server_port");
    1352  remmina_public_get_server_port(remmina_file_get_string(gp->priv->remmina_file, "server"), 0, &server, NULL);
    1353  bindlocalhost = (g_strcmp0(REMMINA_SSH(tunnel)->server, server) == 0);
    1354  g_free(server);
    1355 
    1356  if (!remmina_ssh_tunnel_xport(tunnel, bindlocalhost)) {
    1357  remmina_protocol_widget_set_error(gp, "Could not open channel, %s",
    1358  ssh_get_error(REMMINA_SSH(tunnel)->session));
    1359  remmina_ssh_tunnel_free(tunnel);
    1360  return FALSE;
    1361  }
    1362 
    1364  g_ptr_array_add(gp->priv->ssh_tunnels, tunnel);
    1365 
    1366  return TRUE;
    1367 
    1368 #else
    1369  return FALSE;
    1370 #endif
    1371 }
    1372 
    1374 {
    1375  TRACE_CALL(__func__);
    1376 #ifdef HAVE_LIBSSH
    1377  RemminaSSHTunnel *tunnel;
    1378  if (gp->priv->ssh_tunnels->len < 1)
    1379  return;
    1380  tunnel = (RemminaSSHTunnel *)gp->priv->ssh_tunnels->pdata[0];
    1381  if (tunnel->localdisplay) g_free(tunnel->localdisplay);
    1382  tunnel->localdisplay = g_strdup_printf("unix:%i", display);
    1383 #endif
    1384 }
    1385 
    1387 {
    1388  TRACE_CALL(__func__);
    1389  /* Returns the width of remote desktop as chosen by the user profile */
    1390  return gp->priv->profile_remote_width;
    1391 }
    1392 
    1394 {
    1395  TRACE_CALL(__func__);
    1396  /* Returns ehenever multi monitor is enabled (1) */
    1397  gp->priv->multimon = remmina_file_get_int(gp->priv->remmina_file, "multimon", -1);
    1398  REMMINA_DEBUG("Multi monitor is set to %d", gp->priv->multimon);
    1399  return gp->priv->multimon;
    1400 }
    1401 
    1403 {
    1404  TRACE_CALL(__func__);
    1405  /* Returns the height of remote desktop as chosen by the user profile */
    1406  return gp->priv->profile_remote_height;
    1407 }
    1408 
    1410 {
    1411  TRACE_CALL(__func__);
    1412  return gp ? gp->plugin ? gp->plugin->name : NULL : NULL;
    1413 }
    1414 
    1416 {
    1417  TRACE_CALL(__func__);
    1418  return gp->priv->width;
    1419 }
    1420 
    1422 {
    1423  TRACE_CALL(__func__);
    1424  gp->priv->width = width;
    1425 }
    1426 
    1428 {
    1429  TRACE_CALL(__func__);
    1430  return gp->priv->height;
    1431 }
    1432 
    1434 {
    1435  TRACE_CALL(__func__);
    1436  gp->priv->height = height;
    1437 }
    1438 
    1440 {
    1441  TRACE_CALL(__func__);
    1442  return gp->priv->scalemode;
    1443 }
    1444 
    1446 {
    1447  TRACE_CALL(__func__);
    1448  gp->priv->scalemode = scalemode;
    1449 }
    1450 
    1452 {
    1453  TRACE_CALL(__func__);
    1454  return gp->priv->scaler_expand;
    1455 }
    1456 
    1458 {
    1459  TRACE_CALL(__func__);
    1460  gp->priv->scaler_expand = expand;
    1461  return;
    1462 }
    1463 
    1465 {
    1466  TRACE_CALL(__func__);
    1467  return gp->priv->has_error;
    1468 }
    1469 
    1471 {
    1472  TRACE_CALL(__func__);
    1473  return gp->priv->error_message;
    1474 }
    1475 
    1477 {
    1478  TRACE_CALL(__func__);
    1479  va_list args;
    1480 
    1481  if (gp->priv->error_message) g_free(gp->priv->error_message);
    1482 
    1483  if (fmt == NULL) {
    1484  gp->priv->has_error = FALSE;
    1485  gp->priv->error_message = NULL;
    1486  return;
    1487  }
    1488 
    1489  va_start(args, fmt);
    1490  gp->priv->error_message = g_strdup_vprintf(fmt, args);
    1491  va_end(args);
    1492 
    1493  gp->priv->has_error = TRUE;
    1494 }
    1495 
    1497 {
    1498  TRACE_CALL(__func__);
    1499  return gp->priv->closed;
    1500 }
    1501 
    1503 {
    1504  TRACE_CALL(__func__);
    1505  return gp->priv->remmina_file;
    1506 }
    1507 
    1509  /* Input data */
    1511  gchar * title;
    1516  enum panel_type dtype;
    1519  /* Running status */
    1520  pthread_mutex_t pt_mutex;
    1521  pthread_cond_t pt_cond;
    1522  /* Output/retval */
    1524 };
    1525 
    1526 static void authpanel_mt_cb(void *user_data, int button)
    1527 {
    1529 
    1530  d->rcbutton = button;
    1531  if (button == GTK_RESPONSE_OK) {
    1532  if (d->dtype == RPWDT_AUTH) {
    1537  } else if (d->dtype == RPWDT_AUTHX509) {
    1542  }
    1543  }
    1544 
    1545  if (d->called_from_subthread) {
    1546  /* Hide and destroy message panel, we can do it now because we are on the main thread */
    1548 
    1549  /* Awake the locked subthread, when called from subthread */
    1550  pthread_mutex_lock(&d->pt_mutex);
    1551  pthread_cond_signal(&d->pt_cond);
    1552  pthread_mutex_unlock(&d->pt_mutex);
    1553  } else {
    1554  /* Signal completion, when called from main thread. Message panel will be destroyed by the caller */
    1556  }
    1557 }
    1558 
    1559 static gboolean remmina_protocol_widget_dialog_mt_setup(gpointer user_data)
    1560 {
    1562 
    1563  RemminaFile *remminafile = d->gp->priv->remmina_file;
    1564  RemminaMessagePanel *mp;
    1565  const gchar *s;
    1566 
    1567  if (d->gp->cnnobj == NULL)
    1568  return FALSE;
    1569 
    1571 
    1572  if (d->dtype == RPWDT_AUTH) {
    1580  } else if (d->dtype == RPWDT_QUESTIONYESNO) {
    1582  } else if (d->dtype == RPWDT_AUTHX509) {
    1584  if ((s = remmina_file_get_string(remminafile, "cacert")) != NULL)
    1586  if ((s = remmina_file_get_string(remminafile, "cacrl")) != NULL)
    1588  if ((s = remmina_file_get_string(remminafile, "clientcert")) != NULL)
    1590  if ((s = remmina_file_get_string(remminafile, "clientkey")) != NULL)
    1592  }
    1593 
    1594  d->gp->priv->auth_message_panel = mp;
    1595  rco_show_message_panel(d->gp->cnnobj, mp);
    1596 
    1597  return FALSE;
    1598 }
    1599 
    1600 typedef struct {
    1601  RemminaMessagePanel * mp;
    1602  GMainLoop * loop;
    1603  gint response;
    1604  gboolean destroyed;
    1605 } MpRunInfo;
    1606 
    1607 static void shutdown_loop(MpRunInfo *mpri)
    1608 {
    1609  if (g_main_loop_is_running(mpri->loop))
    1610  g_main_loop_quit(mpri->loop);
    1611 }
    1612 
    1613 static void run_response_handler(RemminaMessagePanel *mp, gint response_id, gpointer data)
    1614 {
    1615  MpRunInfo *mpri = (MpRunInfo *)data;
    1616 
    1617  mpri->response = response_id;
    1618  shutdown_loop(mpri);
    1619 }
    1620 
    1621 static void run_unmap_handler(RemminaMessagePanel *mp, gpointer data)
    1622 {
    1623  MpRunInfo *mpri = (MpRunInfo *)data;
    1624 
    1625  mpri->response = GTK_RESPONSE_CANCEL;
    1626  shutdown_loop(mpri);
    1627 }
    1628 
    1629 static void run_destroy_handler(RemminaMessagePanel *mp, gpointer data)
    1630 {
    1631  MpRunInfo *mpri = (MpRunInfo *)data;
    1632 
    1633  mpri->destroyed = TRUE;
    1634  mpri->response = GTK_RESPONSE_CANCEL;
    1635  shutdown_loop(mpri);
    1636 }
    1637 
    1639  const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain,
    1640  const gchar *strpasswordlabel)
    1641 {
    1642  TRACE_CALL(__func__);
    1643 
    1645  int rcbutton;
    1646 
    1647  d->gp = gp;
    1648  d->pflags = pflags;
    1649  d->dtype = dtype;
    1650  d->title = g_strdup(title);
    1651  d->strpasswordlabel = g_strdup(strpasswordlabel);
    1652  d->default_username = g_strdup(default_username);
    1653  d->default_password = g_strdup(default_password);
    1654  d->default_domain = g_strdup(default_domain);
    1655  d->called_from_subthread = FALSE;
    1656 
    1658  /* Run the MessagePanel in main thread, in a very similar way of gtk_dialog_run() */
    1659  MpRunInfo mpri = { NULL, NULL, GTK_RESPONSE_CANCEL, FALSE };
    1660 
    1661  gulong unmap_handler;
    1662  gulong destroy_handler;
    1663  gulong response_handler;
    1664 
    1666 
    1667  mpri.mp = d->gp->priv->auth_message_panel;
    1668 
    1669  if (!gtk_widget_get_visible(GTK_WIDGET(mpri.mp)))
    1670  gtk_widget_show(GTK_WIDGET(mpri.mp));
    1671  response_handler = g_signal_connect(mpri.mp, "response", G_CALLBACK(run_response_handler), &mpri);
    1672  unmap_handler = g_signal_connect(mpri.mp, "unmap", G_CALLBACK(run_unmap_handler), &mpri);
    1673  destroy_handler = g_signal_connect(mpri.mp, "destroy", G_CALLBACK(run_destroy_handler), &mpri);
    1674 
    1675  g_object_ref(mpri.mp);
    1676 
    1677  mpri.loop = g_main_loop_new(NULL, FALSE);
    1678  g_main_loop_run(mpri.loop);
    1679  g_main_loop_unref(mpri.loop);
    1680 
    1681  if (!mpri.destroyed) {
    1682  g_signal_handler_disconnect(mpri.mp, response_handler);
    1683  g_signal_handler_disconnect(mpri.mp, destroy_handler);
    1684  g_signal_handler_disconnect(mpri.mp, unmap_handler);
    1685  }
    1686  g_object_unref(mpri.mp);
    1687 
    1689 
    1690  rcbutton = mpri.response;
    1691  } else {
    1692  d->called_from_subthread = TRUE;
    1693  // pthread_cleanup_push(ptcleanup, (void*)d);
    1694  pthread_cond_init(&d->pt_cond, NULL);
    1695  pthread_mutex_init(&d->pt_mutex, NULL);
    1697  pthread_mutex_lock(&d->pt_mutex);
    1698  pthread_cond_wait(&d->pt_cond, &d->pt_mutex);
    1699  // pthread_cleanup_pop(0);
    1700  pthread_mutex_destroy(&d->pt_mutex);
    1701  pthread_cond_destroy(&d->pt_cond);
    1702 
    1703  rcbutton = d->rcbutton;
    1704  }
    1705 
    1706  g_free(d->title);
    1707  g_free(d->strpasswordlabel);
    1708  g_free(d->default_username);
    1709  g_free(d->default_password);
    1710  g_free(d->default_domain);
    1711  g_free(d);
    1712  return rcbutton;
    1713 }
    1714 
    1716 {
    1717  return remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, msg, NULL, NULL, NULL, NULL);
    1718 }
    1719 
    1721  const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    1722 {
    1723  TRACE_CALL(__func__);
    1724  return remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, title, default_username,
    1725  default_password, default_domain, password_prompt == NULL ? _("Password") : password_prompt);
    1726 }
    1727 
    1728 gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    1729 {
    1730  TRACE_CALL(__func__);
    1731  unsigned pflags;
    1732  RemminaFile *remminafile = gp->priv->remmina_file;
    1733  const gchar *username, *password;
    1734 
    1736  if (remmina_file_get_filename(remminafile) != NULL &&
    1737  !remminafile->prevent_saving && allow_password_saving)
    1739 
    1740  username = remmina_file_get_string(remminafile, "ssh_tunnel_username");
    1741  password = remmina_file_get_string(remminafile, "ssh_tunnel_password");
    1742 
    1743  return remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, _("Type in SSH username and password."), username,
    1744  password, NULL, _("Password"));
    1745 }
    1746 
    1747 /*
    1748  * gint remmina_protocol_widget_panel_authpwd(RemminaProtocolWidget* gp, RemminaAuthpwdType authpwd_type, gboolean allow_password_saving)
    1749  * {
    1750  * TRACE_CALL(__func__);
    1751  * unsigned pflags;
    1752  * RemminaFile* remminafile = gp->priv->remmina_file;
    1753  * char *password_prompt;
    1754  * int rc;
    1755  *
    1756  * pflags = 0;
    1757  * if (remmina_file_get_filename(remminafile) != NULL &&
    1758  * !remminafile->prevent_saving && allow_password_saving)
    1759  * pflags |= REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD;
    1760  *
    1761  * switch (authpwd_type) {
    1762  * case REMMINA_AUTHPWD_TYPE_PROTOCOL:
    1763  * password_prompt = g_strdup_printf(_("%s password"), remmina_file_get_string(remminafile, "protocol"));
    1764  * break;
    1765  * case REMMINA_AUTHPWD_TYPE_SSH_PWD:
    1766  * password_prompt = g_strdup(_("SSH password"));
    1767  * break;
    1768  * case REMMINA_AUTHPWD_TYPE_SSH_PRIVKEY:
    1769  * password_prompt = g_strdup(_("SSH private key passphrase"));
    1770  * break;
    1771  * default:
    1772  * password_prompt = g_strdup(_("Password"));
    1773  * break;
    1774  * }
    1775  *
    1776  * rc = remmina_protocol_widget_dialog(RPWDT_AUTH, gp, pflags, password_prompt);
    1777  * g_free(password_prompt);
    1778  * return rc;
    1779  *
    1780  * }
    1781  */
    1783 {
    1784  TRACE_CALL(__func__);
    1785 
    1786  return remmina_protocol_widget_dialog(RPWDT_AUTHX509, gp, 0, NULL, NULL, NULL, NULL, NULL);
    1787 }
    1788 
    1789 
    1790 gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    1791 {
    1792  TRACE_CALL(__func__);
    1793  gchar *s;
    1794  int rc;
    1795 
    1796  if (remmina_pref_get_boolean("trust_all")) {
    1797  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1798  remmina_public_send_notification("remmina-security-trust-all-id", _("Fingerprint automatically accepted"), fingerprint);
    1799  rc = GTK_RESPONSE_OK;
    1800  return rc;
    1801  }
    1802  // For markup see https://developer.gnome.org/pygtk/stable/pango-markup-language.html
    1803  s = g_strdup_printf(
    1804  "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
    1805  // TRANSLATORS: The user is asked to verify a new SSL certificate.
    1806  _("Certificate details:"),
    1807  // TRANSLATORS: An SSL certificate subject is usually the remote server the user connect to.
    1808  _("Subject:"), subject,
    1809  // TRANSLATORS: The name or email of the entity that have issued the SSL certificate
    1810  _("Issuer:"), issuer,
    1811  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1812  _("Fingerprint:"), fingerprint,
    1813  // TRANSLATORS: The user is asked to accept or refuse a new SSL certificate.
    1814  _("Accept certificate?"));
    1815  rc = remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, s, NULL, NULL, NULL, NULL);
    1816  g_free(s);
    1817 
    1818  /* For compatibility with plugin API: the plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1819  return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
    1820 }
    1821 
    1822 gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    1823 {
    1824  TRACE_CALL(__func__);
    1825  gchar *s;
    1826  int rc;
    1827 
    1828  if (remmina_pref_get_boolean("trust_all")) {
    1829  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1830  remmina_public_send_notification("remmina-security-trust-all-id", _("Fingerprint automatically accepted"), new_fingerprint);
    1831  rc = GTK_RESPONSE_OK;
    1832  return rc;
    1833  }
    1834  // For markup see https://developer.gnome.org/pygtk/stable/pango-markup-language.html
    1835  s = g_strdup_printf(
    1836  "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
    1837  // TRANSLATORS: The user is asked to verify a new SSL certificate.
    1838  _("The certificate changed! Details:"),
    1839  // TRANSLATORS: An SSL certificate subject is usually the remote server the user connect to.
    1840  _("Subject:"), subject,
    1841  // TRANSLATORS: The name or email of the entity that have issued the SSL certificate
    1842  _("Issuer:"), issuer,
    1843  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1844  _("Old fingerprint:"), old_fingerprint,
    1845  // TRANSLATORS: An SSL certificate fingerprint, is a hash of a certificate calculated on all certificate's data and its signature.
    1846  _("New fingerprint:"), new_fingerprint,
    1847  // TRANSLATORS: The user is asked to accept or refuse a new SSL certificate.
    1848  _("Accept changed certificate?"));
    1849  rc = remmina_protocol_widget_dialog(RPWDT_QUESTIONYESNO, gp, 0, s, NULL, NULL, NULL, NULL);
    1850  g_free(s);
    1851 
    1852  /* For compatibility with plugin API: The plugin expects GTK_RESPONSE_OK when user confirms new cert */
    1853  return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
    1854 }
    1855 
    1857 {
    1858  TRACE_CALL(__func__);
    1859  return g_strdup(gp->priv->username);
    1860 }
    1861 
    1863 {
    1864  TRACE_CALL(__func__);
    1865  return g_strdup(gp->priv->password);
    1866 }
    1867 
    1869 {
    1870  TRACE_CALL(__func__);
    1871  return g_strdup(gp->priv->domain);
    1872 }
    1873 
    1875 {
    1876  TRACE_CALL(__func__);
    1877  return gp->priv->save_password;
    1878 }
    1879 
    1881 {
    1882  TRACE_CALL(__func__);
    1883  gchar *s;
    1884 
    1885  s = gp->priv->cacert;
    1886  return s && s[0] ? g_strdup(s) : NULL;
    1887 }
    1888 
    1890 {
    1891  TRACE_CALL(__func__);
    1892  gchar *s;
    1893 
    1894  s = gp->priv->cacrl;
    1895  return s && s[0] ? g_strdup(s) : NULL;
    1896 }
    1897 
    1899 {
    1900  TRACE_CALL(__func__);
    1901  gchar *s;
    1902 
    1903  s = gp->priv->clientcert;
    1904  return s && s[0] ? g_strdup(s) : NULL;
    1905 }
    1906 
    1908 {
    1909  TRACE_CALL(__func__);
    1910  gchar *s;
    1911 
    1912  s = gp->priv->clientkey;
    1913  return s && s[0] ? g_strdup(s) : NULL;
    1914 }
    1915 
    1917 {
    1918  TRACE_CALL(__func__);
    1919 
    1920  RemminaFile *remminafile = gp->priv->remmina_file;
    1921  gchar *s;
    1922  gboolean save = FALSE;
    1923 
    1925  /* Allow the execution of this function from a non main thread */
    1926  RemminaMTExecData *d;
    1927  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    1928  d->func = FUNC_INIT_SAVE_CRED;
    1929  d->p.init_save_creds.gp = gp;
    1931  g_free(d);
    1932  return;
    1933  }
    1934 
    1935  /* Save username and certificates if any; save the password if it’s requested to do so */
    1936  s = gp->priv->username;
    1937  if (s && s[0]) {
    1938  remmina_file_set_string(remminafile, "username", s);
    1939  save = TRUE;
    1940  }
    1941  s = gp->priv->cacert;
    1942  if (s && s[0]) {
    1943  remmina_file_set_string(remminafile, "cacert", s);
    1944  save = TRUE;
    1945  }
    1946  s = gp->priv->cacrl;
    1947  if (s && s[0]) {
    1948  remmina_file_set_string(remminafile, "cacrl", s);
    1949  save = TRUE;
    1950  }
    1951  s = gp->priv->clientcert;
    1952  if (s && s[0]) {
    1953  remmina_file_set_string(remminafile, "clientcert", s);
    1954  save = TRUE;
    1955  }
    1956  s = gp->priv->clientkey;
    1957  if (s && s[0]) {
    1958  remmina_file_set_string(remminafile, "clientkey", s);
    1959  save = TRUE;
    1960  }
    1961  if (gp->priv->save_password) {
    1962  remmina_file_set_string(remminafile, "password", gp->priv->password);
    1963  save = TRUE;
    1964  }
    1965  if (save)
    1966  remmina_file_save(remminafile);
    1967 }
    1968 
    1969 
    1971 {
    1972  TRACE_CALL(__func__);
    1973  RemminaMessagePanel *mp;
    1974  gchar *s;
    1975 
    1977  /* Allow the execution of this function from a non main thread */
    1978  RemminaMTExecData *d;
    1979  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    1980  d->func = FUNC_PROTOCOLWIDGET_PANELSHOWLISTEN;
    1982  d->p.protocolwidget_panelshowlisten.port = port;
    1984  g_free(d);
    1985  return;
    1986  }
    1987 
    1989  s = g_strdup_printf(
    1990  // TRANSLATORS: “%i” is a placeholder for a port number. “%s” is a placeholder for a protocol name (VNC).
    1991  _("Listening on port %i for an incoming %s connection…"), port,
    1992  remmina_file_get_string(gp->priv->remmina_file, "protocol"));
    1993  remmina_message_panel_setup_progress(mp, s, NULL, NULL);
    1994  g_free(s);
    1995  gp->priv->listen_message_panel = mp;
    1996  rco_show_message_panel(gp->cnnobj, mp);
    1997 }
    1998 
    2000 {
    2001  TRACE_CALL(__func__);
    2002  RemminaMessagePanel *mp;
    2003 
    2005  /* Allow the execution of this function from a non main thread */
    2006  RemminaMTExecData *d;
    2007  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    2008  d->func = FUNC_PROTOCOLWIDGET_MPSHOWRETRY;
    2011  g_free(d);
    2012  return;
    2013  }
    2014 
    2016  remmina_message_panel_setup_progress(mp, _("Could not authenticate, attempting reconnection…"), NULL, NULL);
    2017  gp->priv->retry_message_panel = mp;
    2018  rco_show_message_panel(gp->cnnobj, mp);
    2019 }
    2020 
    2022 {
    2023  TRACE_CALL(__func__);
    2024  printf("Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
    2025 }
    2026 
    2028 {
    2029  TRACE_CALL(__func__);
    2030  printf("Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
    2031 }
    2032 
    2034 {
    2035  TRACE_CALL(__func__);
    2036  gp->priv->chat_window = NULL;
    2037 }
    2038 
    2040  void (*on_send)(RemminaProtocolWidget *gp, const gchar *text), void (*on_destroy)(RemminaProtocolWidget *gp))
    2041 {
    2042  TRACE_CALL(__func__);
    2043  if (gp->priv->chat_window) {
    2044  gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
    2045  } else {
    2046  gp->priv->chat_window = remmina_chat_window_new(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp))), name);
    2047  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "send", G_CALLBACK(on_send), gp);
    2048  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy",
    2049  G_CALLBACK(remmina_protocol_widget_chat_on_destroy), gp);
    2050  g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy", G_CALLBACK(on_destroy), gp);
    2051  gtk_widget_show(gp->priv->chat_window);
    2052  }
    2053 }
    2054 
    2056 {
    2057  TRACE_CALL(__func__);
    2058  if (gp->priv->chat_window)
    2059  gtk_widget_destroy(gp->priv->chat_window);
    2060 }
    2061 
    2063 {
    2064  TRACE_CALL(__func__);
    2065  /* This function can be called from a non main thread */
    2066 
    2067  if (gp->priv->chat_window) {
    2069  /* Allow the execution of this function from a non main thread */
    2070  RemminaMTExecData *d;
    2071  d = (RemminaMTExecData *)g_malloc(sizeof(RemminaMTExecData));
    2072  d->func = FUNC_CHAT_RECEIVE;
    2073  d->p.chat_receive.gp = gp;
    2074  d->p.chat_receive.text = text;
    2076  g_free(d);
    2077  return;
    2078  }
    2079  remmina_chat_window_receive(REMMINA_CHAT_WINDOW(gp->priv->chat_window), _("Server"), text);
    2080  gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
    2081  }
    2082 }
    2083 
    2085 {
    2087 
    2088  gp->priv->remmina_file = remminafile;
    2089  gp->cnnobj = cnnobj;
    2090 
    2091  /* Locate the protocol plugin */
    2093  remmina_file_get_string(remminafile, "protocol"));
    2094 
    2095  if (!plugin || !plugin->init || !plugin->open_connection) {
    2096  // TRANSLATORS: “%s” is a placeholder for a protocol name, like “RDP”.
    2097  remmina_protocol_widget_set_error(gp, _("Install the %s protocol plugin first."),
    2098  remmina_file_get_string(remminafile, "protocol"));
    2099  gp->priv->plugin = NULL;
    2100  return;
    2101  }
    2102  gp->priv->plugin = plugin;
    2103  gp->plugin = plugin;
    2104 
    2105  gp->priv->scalemode = remmina_file_get_int(gp->priv->remmina_file, "scale", FALSE);
    2106  gp->priv->scaler_expand = remmina_file_get_int(gp->priv->remmina_file, "scaler_expand", FALSE);
    2107 }
    2108 
    2110 {
    2111  return rcw_get_gtkwindow(gp->cnnobj);
    2112 }
    2113 
    2115 {
    2116  return rcw_get_gtkviewport(gp->cnnobj);
    2117 }
    2118 
    2120 {
    2121  return GTK_WIDGET(g_object_new(REMMINA_TYPE_PROTOCOL_WIDGET, NULL));
    2122 }
    2123 
    2124 /* Send one or more keystrokes to a specific widget by firing key-press and
    2125  * key-release events.
    2126  * GdkEventType action can be GDK_KEY_PRESS or GDK_KEY_RELEASE or both to
    2127  * press the keys and release them in reversed order. */
    2128 void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    2129 {
    2130  TRACE_CALL(__func__);
    2131  int i;
    2132  GdkEventKey event;
    2133  gboolean result;
    2134  GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
    2135 
    2136  event.window = gtk_widget_get_window(widget);
    2137  event.send_event = TRUE;
    2138  event.time = GDK_CURRENT_TIME;
    2139  event.state = 0;
    2140  event.length = 0;
    2141  event.string = "";
    2142  event.group = 0;
    2143 
    2144  if (action & GDK_KEY_PRESS) {
    2145  /* Press the requested buttons */
    2146  event.type = GDK_KEY_PRESS;
    2147  for (i = 0; i < keyvals_length; i++) {
    2148  event.keyval = keyvals[i];
    2149  event.hardware_keycode = remmina_public_get_keycode_for_keyval(keymap, event.keyval);
    2150  event.is_modifier = (int)remmina_public_get_modifier_for_keycode(keymap, event.hardware_keycode);
    2151  REMMINA_DEBUG("Sending keyval: %u, hardware_keycode: %u", event.keyval, event.hardware_keycode);
    2152  g_signal_emit_by_name(G_OBJECT(widget), "key-press-event", &event, &result);
    2153  }
    2154  }
    2155 
    2156  if (action & GDK_KEY_RELEASE) {
    2157  /* Release the requested buttons in reverse order */
    2158  event.type = GDK_KEY_RELEASE;
    2159  for (i = (keyvals_length - 1); i >= 0; i--) {
    2160  event.keyval = keyvals[i];
    2161  event.hardware_keycode = remmina_public_get_keycode_for_keyval(keymap, event.keyval);
    2162  event.is_modifier = (int)remmina_public_get_modifier_for_keycode(keymap, event.hardware_keycode);
    2163  g_signal_emit_by_name(G_OBJECT(widget), "key-release-event", &event, &result);
    2164  }
    2165  }
    2166 }
    2167 
    2169 {
    2170  TRACE_CALL(__func__);
    2171  GdkRectangle rect;
    2172  gint w, h;
    2173  gint wfile, hfile;
    2176 
    2177  rco_get_monitor_geometry(gp->cnnobj, &rect);
    2178 
    2179  /* Integrity check: check that we have a cnnwin visible and get t */
    2180 
    2181  res_mode = remmina_file_get_int(gp->priv->remmina_file, "resolution_mode", RES_INVALID);
    2183  wfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_width", -1);
    2184  hfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_height", -1);
    2185 
    2186  /* If resolution_mode is non-existent (-1), then we try to calculate it
    2187  * as we did before having resolution_mode */
    2188  if (res_mode == RES_INVALID) {
    2189  if (wfile <= 0 || hfile <= 0)
    2190  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
    2191  else
    2192  res_mode = RES_USE_CUSTOM;
    2193  }
    2194 
    2196  /* Use internal window size as remote desktop size */
    2197  GtkAllocation al;
    2198  gtk_widget_get_allocation(GTK_WIDGET(gp), &al);
    2199  /* use a multiple of four to mitigate scaling when remote host rounds up */
    2200  w = al.width - al.width % 4;
    2201  h = al.height - al.height % 4;
    2202  if (w < 10) {
    2203  printf("Remmina warning: %s RemminaProtocolWidget w=%d h=%d are too small, adjusting to 640x480\n", __func__, w, h);
    2204  w = 640;
    2205  h = 480;
    2206  }
    2207  /* Due to approximations while GTK calculates scaling, (w x h) may exceed our monitor geometry
    2208  * Adjust to fit. */
    2209  if (w > rect.width)
    2210  w = rect.width;
    2211  if (h > rect.height)
    2212  h = rect.height;
    2213  } else if (res_mode == RES_USE_CLIENT) {
    2214  w = rect.width;
    2215  h = rect.height;
    2216  } else {
    2217  w = wfile;
    2218  h = hfile;
    2219  }
    2220  gp->priv->profile_remote_width = w;
    2221  gp->priv->profile_remote_height = h;
    2222 }
    +
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    - -
    static gboolean desktop_resize(gpointer data)
    -
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    + +
    static gboolean desktop_resize(gpointer data)
    +
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    -
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    +
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    struct remmina_masterthread_exec_data::@12::@14 init_save_creds
    -
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    - +
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    +
    enum remmina_ssh_auth_result remmina_ssh_auth_gui(RemminaSSH *ssh, RemminaProtocolWidget *gp, RemminaFile *remminafile)
    -
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    -
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    +
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    struct _RemminaProtocolWidgetSignalData RemminaProtocolWidgetSignalData
    -
    static gboolean lock_dynres(gpointer data)
    +
    static gboolean lock_dynres(gpointer data)
    const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
    Definition: remmina_file.c:516
    -
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    -
    static gboolean unlock_dynres(gpointer data)
    -
    static gboolean remmina_protocol_widget_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    +
    static gboolean unlock_dynres(gpointer data)
    +
    static gboolean remmina_protocol_widget_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    -
    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.
    +
    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.
    RemminaSSHTunnelCallback destroy_func
    Definition: remmina_ssh.h:180
    -
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    gboolean remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port)
    - +
    void remmina_message_panel_setup_auth(RemminaMessagePanel *mp, RemminaMessagePanelCallback response_callback, gpointer response_callback_data, const gchar *title, const gchar *password_prompt, unsigned flags)
    void(* call_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: plugin.h:83
    -
    static void remmina_protocol_widget_destroy(RemminaProtocolWidget *gp, gpointer data)
    -
    static gboolean remmina_protocol_widget_dialog_mt_setup(gpointer user_data)
    - +
    static void remmina_protocol_widget_destroy(RemminaProtocolWidget *gp, gpointer data)
    +
    static gboolean remmina_protocol_widget_dialog_mt_setup(gpointer user_data)
    +
    void remmina_message_panel_setup_question(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    -
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    +
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    gchar * remmina_message_panel_field_get_filename(RemminaMessagePanel *mp, int entryid)
    -
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    -
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    -
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    - -
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    + +
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    const gchar * remmina_file_get_filename(RemminaFile *remminafile)
    Definition: remmina_file.c:210
    -
    static gboolean remmina_protocol_widget_xport_tunnel_connect_callback(RemminaSSHTunnel *tunnel, gpointer data)
    +
    static gboolean remmina_protocol_widget_xport_tunnel_connect_callback(RemminaSSHTunnel *tunnel, gpointer data)
    void remmina_public_send_notification(const gchar *notification_id, const gchar *notification_title, const gchar *notification_message)
    -
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    - -
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    + +
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    -
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    - - - - -
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    +
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    + + + + +
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    void rco_show_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    Each cnnobj->page can have more than one RemminaMessagePanel, but 0 or 1 are visible.
    Definition: rcw.c:4769
    -
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    - -
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    -
    static gboolean remmina_protocol_widget_on_key_release(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    -
    static void shutdown_loop(MpRunInfo *mpri)
    +
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    + +
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    +
    static gboolean remmina_protocol_widget_on_key_release(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    +
    static void shutdown_loop(MpRunInfo *mpri)
    gpointer destroy_func_callback_data
    Definition: remmina_ssh.h:181
    RemminaFile * remmina_file_dup_temp_protocol(RemminaFile *remminafile, const gchar *new_protocol)
    Definition: remmina_file.c:899
    GtkWidget * rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
    Definition: rcw.c:4506
    void remmina_message_panel_setup_auth_x509(RemminaMessagePanel *mp, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    -
    static int remmina_protocol_widget_dialog(enum panel_type dtype, RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *strpasswordlabel)
    -
    static void run_response_handler(RemminaMessagePanel *mp, gint response_id, gpointer data)
    -
    static gboolean remmina_protocol_widget_xport_tunnel_init_callback(RemminaSSHTunnel *tunnel, gpointer data)
    +
    static int remmina_protocol_widget_dialog(enum panel_type dtype, RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *strpasswordlabel)
    +
    static void run_response_handler(RemminaMessagePanel *mp, gint response_id, gpointer data)
    +
    static gboolean remmina_protocol_widget_xport_tunnel_init_callback(RemminaSSHTunnel *tunnel, gpointer data)
    void(* init)(RemminaProtocolWidget *gp)
    Definition: plugin.h:79
    -
    static void cancel_init_tunnel_cb(void *cbdata, int btn)
    +
    static void cancel_init_tunnel_cb(void *cbdata, int btn)
    -
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    +
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    - -
    RemminaMessagePanel * listen_message_panel
    -
    static RemminaSSHTunnel * remmina_protocol_widget_init_tunnel(RemminaProtocolWidget *gp)
    + +
    RemminaMessagePanel * listen_message_panel
    +
    static RemminaSSHTunnel * remmina_protocol_widget_init_tunnel(RemminaProtocolWidget *gp)
    const RemminaProtocolFeature * features
    Definition: plugin.h:77
    - + - - -
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    + + +
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    struct remmina_masterthread_exec_data::@12::@24 protocolwidget_panelshowlisten
    -
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    -
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    +
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    void rco_destroy_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    Deletes a RemminaMessagePanel from the current cnnobj and if it was visible, make visible the last re...
    Definition: rcw.c:4722
    -
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    +
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    gboolean bindlocalhost
    Definition: remmina_ssh.h:172
    -
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    -
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    +
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    - -
    static gboolean conn_opened(gpointer data)
    +
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    + +
    static gboolean conn_opened(gpointer data)
    -
    void remmina_protocol_widget_send_clip_strokes(GtkClipboard *clipboard, const gchar *clip_text, gpointer data)
    Send to the plugin some keystrokes from the content of the clipboard This is a copy of remmina_protoc...
    -
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    -
    static void cancel_open_connection_cb(void *cbdata, int btn)
    +
    void remmina_protocol_widget_send_clip_strokes(GtkClipboard *clipboard, const gchar *clip_text, gpointer data)
    Send to the plugin some keystrokes from the content of the clipboard This is a copy of remmina_protoc...
    +
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    +
    static void cancel_open_connection_cb(void *cbdata, int btn)
    gboolean(* open_connection)(RemminaProtocolWidget *gp)
    Definition: plugin.h:80
    -
    RemminaMessagePanel * retry_message_panel
    +
    RemminaMessagePanel * retry_message_panel
    void remmina_message_panel_field_set_string(RemminaMessagePanel *mp, int entryid, const gchar *text)
    - +
    RemminaProtocolPlugin * plugin
    -
    static void run_unmap_handler(RemminaMessagePanel *mp, gpointer data)
    - -
    static gboolean conn_closed(gpointer data)
    -
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    +
    static void run_unmap_handler(RemminaMessagePanel *mp, gpointer data)
    + +
    static gboolean conn_closed(gpointer data)
    +
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    RemminaProtocolWidgetResolutionMode
    Definition: types.h:148
    -
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    +
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    RemminaSSHTunnelCallback disconnect_func
    Definition: remmina_ssh.h:177
    - -
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    + +
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    RemminaProtocolFeature * features
    - +
    gchar * remmina_public_str_replace_in_place(gchar *string, const gchar *search, const gchar *replacement)
    GtkDialog * remmina_ext_exec_new(RemminaFile *remminafile, const char *remmina_ext_exec_type)
    -
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    -
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    +
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    +
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    -
    static void cancel_start_reverse_tunnel_cb(void *cbdata, int btn)
    +
    static void cancel_start_reverse_tunnel_cb(void *cbdata, int btn)
    struct remmina_masterthread_exec_data::@12::@21 protocolwidget_mpprogress
    - +
    RemminaMessagePanelFlags
    Definition: types.h:156
    @@ -229,90 +229,91 @@ $(document).ready(function(){initNavTree('remmina__protocol__widget_8c_source.ht
    gboolean remmina_masterthread_exec_is_main_thread()
    struct remmina_masterthread_exec_data::@12::@22 protocolwidget_mpdestroy
    -
    void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
    gboolean(* unmap_event)(RemminaProtocolWidget *gp)
    Definition: plugin.h:87
    -
    GtkWidget * remmina_protocol_widget_new(void)
    -
    static guint remmina_protocol_widget_signals[LAST_SIGNAL]
    +
    GtkWidget * remmina_protocol_widget_new(void)
    +
    static guint remmina_protocol_widget_signals[LAST_SIGNAL]
    struct remmina_masterthread_exec_data::@12::@23 protocolwidget_mpshowretry
    - -
    void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    + +
    void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    -
    RemminaMessagePanel * auth_message_panel
    +
    RemminaMessagePanel * auth_message_panel
    RemminaProtocolFeatureType type
    Definition: types.h:73
    -
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    - -
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    +
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    + +
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    RemminaProtocolPlugin * plugin
    void(* send_keystrokes)(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    Definition: plugin.h:84
    - + -
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    - +
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    + -
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    +
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    void remmina_ssh_set_error(RemminaSSH *ssh, const gchar *fmt)
    Definition: remmina_ssh.c:653
    -
    RemminaMessagePanel * mp
    -
    static void cancel_connect_xport_cb(void *cbdata, int btn)
    +
    RemminaMessagePanel * mp
    +
    static void cancel_connect_xport_cb(void *cbdata, int btn)
    gboolean remmina_ssh_tunnel_xport(RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
    -
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    RemminaSSHTunnel * remmina_ssh_tunnel_new_from_file(RemminaFile *remminafile)
    RemminaProtocolWidgetPriv * priv
    -
    static void remmina_protocol_widget_init(RemminaProtocolWidget *gp)
    -
    static void authpanel_mt_cb(void *user_data, int button)
    +
    static void remmina_protocol_widget_init(RemminaProtocolWidget *gp)
    +
    static void authpanel_mt_cb(void *user_data, int button)
    -
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    +
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    RemminaSSHTunnelCallback init_func
    Definition: remmina_ssh.h:175
    gboolean(* RemminaHostkeyFunc)(RemminaProtocolWidget *gp, guint keyval, gboolean release)
    -
    G_DEFINE_TYPE(RemminaProtocolWidget, remmina_protocol_widget, GTK_TYPE_EVENT_BOX)
    -
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    +
    G_DEFINE_TYPE(RemminaProtocolWidget, remmina_protocol_widget, GTK_TYPE_EVENT_BOX)
    +
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    void remmina_message_panel_field_set_switch(RemminaMessagePanel *mp, int entryid, gboolean state)
    gpointer callback_data
    Definition: remmina_ssh.h:178
    RemminaConnectionObject * cnnobj
    -
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    -
    GtkWindow * remmina_protocol_widget_get_gtkwindow(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    +
    GtkWindow * remmina_protocol_widget_get_gtkwindow(RemminaProtocolWidget *gp)
    RemminaTypeHint opt1_type_hint
    Definition: types.h:78
    -
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    -
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    +
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    +
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    gboolean remmina_pref_get_boolean(const gchar *key)
    void remmina_ssh_tunnel_cancel_accept(RemminaSSHTunnel *tunnel)
    -
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    -
    RemminaMessagePanel * connect_message_panel
    -
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    -
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    - +
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    +
    RemminaMessagePanel * connect_message_panel
    +
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    +
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    +
    void remmina_ssh_tunnel_free(RemminaSSHTunnel *tunnel)
    - + - -
    static void remmina_protocol_widget_close_all_tunnels(RemminaProtocolWidget *gp)
    -
    static void remmina_protocol_widget_chat_on_destroy(RemminaProtocolWidget *gp)
    -
    static gboolean remmina_protocol_widget_xport_tunnel_disconnect_callback(RemminaSSHTunnel *tunnel, gpointer data)
    + +
    static gboolean conn_closed_real(gpointer data, int button)
    +
    static void remmina_protocol_widget_close_all_tunnels(RemminaProtocolWidget *gp)
    +
    static void remmina_protocol_widget_chat_on_destroy(RemminaProtocolWidget *gp)
    +
    static gboolean remmina_protocol_widget_xport_tunnel_disconnect_callback(RemminaSSHTunnel *tunnel, gpointer data)
    RemminaProtocolFeatureType
    Definition: types.h:46
    -
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    +
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    gboolean(* close_connection)(RemminaProtocolWidget *gp)
    Definition: plugin.h:81
    void remmina_masterthread_exec_and_wait(RemminaMTExecData *d)
    GtkWidget * rcw_get_gtkviewport(RemminaConnectionObject *cnnobj)
    Definition: rcw.c:4707
    void(* RemminaMessagePanelCallback)(void *user_data, int button)
    -
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    +
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    gchar * remmina_message_panel_field_get_string(RemminaMessagePanel *mp, int entryid)
    RemminaTypeHint opt2_type_hint
    Definition: types.h:79
    -
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    RemminaPref remmina_pref
    Definition: rcw.c:79
    -
    static void run_destroy_handler(RemminaMessagePanel *mp, gpointer data)
    +
    static void run_destroy_handler(RemminaMessagePanel *mp, gpointer data)
    void remmina_message_panel_setup_progress(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    RemminaScaleMode
    Definition: types.h:142
    @@ -320,78 +321,80 @@ $(document).ready(function(){initNavTree('remmina__protocol__widget_8c_source.ht
    gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
    Definition: remmina_file.c:603
    -
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    + +
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    gboolean(* map_event)(RemminaProtocolWidget *gp)
    Definition: plugin.h:86
    -
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    - - + +
    gboolean(* query_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: plugin.h:82
    -
    static gboolean remmina_protocol_widget_tunnel_destroy(RemminaSSHTunnel *tunnel, gpointer data)
    +
    static gboolean remmina_protocol_widget_tunnel_destroy(RemminaSSHTunnel *tunnel, gpointer data)
    RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
    - -
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    + +
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    - -
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    + +
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    guint16 remmina_public_get_keycode_for_keyval(GdkKeymap *keymap, guint keyval)
    gpointer RemminaTunnelInitFunc
    Definition: types.h:94
    const gchar * name
    Definition: plugin.h:67
    - + - -
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    + +
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    gboolean remmina_public_get_modifier_for_keycode(GdkKeymap *keymap, guint16 keycode)
    struct remmina_masterthread_exec_data::@12::@15 chat_receive
    - +
    union remmina_masterthread_exec_data::@12 p
    - +
    gint sshtunnel_port
    Definition: remmina_pref.h:168
    -
    gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    -
    static void cancel_start_direct_tunnel_cb(void *cbdata, int btn)
    +
    gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    +
    static void cancel_start_direct_tunnel_cb(void *cbdata, int btn)
    struct remmina_masterthread_exec_data::@12::@20 protocolwidget_emit_signal
    -
    static gboolean update_align(gpointer data)
    +
    static gboolean update_align(gpointer data)
    +
    void remmina_message_panel_setup_message(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    gboolean(* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    Definition: plugin.h:85
    -
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    +
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    gboolean remmina_message_panel_field_get_switch_state(RemminaMessagePanel *mp, int entryid)
    void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
    Definition: remmina_file.c:469
    void remmina_file_save(RemminaFile *remminafile)
    Definition: remmina_file.c:730
    -
    static void remmina_protocol_widget_class_init(RemminaProtocolWidgetClass *klass)
    +
    static void remmina_protocol_widget_class_init(RemminaProtocolWidgetClass *klass)
    void rco_get_monitor_geometry(RemminaConnectionObject *cnnobj, GdkRectangle *sz)
    Definition: rcw.c:1009
    - -
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    + +
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    -
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    - +
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    +
    void remmina_ssh_set_application_error(RemminaSSH *ssh, const gchar *fmt,...)
    Definition: remmina_ssh.c:663
    void remmina_chat_window_receive(RemminaChatWindow *window, const gchar *name, const gchar *text)
    -
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    void remmina_public_get_server_port(const gchar *server, gint defaultport, gchar **host, gint *port)
    gboolean remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port)
    GtkWidget * remmina_chat_window_new(GtkWindow *parent, const gchar *chat_with)
    -
    void remmina_protocol_widget_open_connection_real(gpointer data)
    -
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_open_connection_real(gpointer data)
    +
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    enum remmina_masterthread_exec_data::@11 func
    gchar * localdisplay
    Definition: remmina_ssh.h:173
    gboolean(* RemminaXPortTunnelInitFunc)(RemminaProtocolWidget *gp, gint remotedisplay, const gchar *server, gint port)
    Definition: types.h:95
    void remmina_message_panel_response(RemminaMessagePanel *mp, gint response_id)
    -
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    +
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    RemminaMessagePanel * remmina_message_panel_new()
    RemminaTypeHint opt3_type_hint
    Definition: types.h:80
    - +
    RemminaSSHTunnelCallback connect_func
    Definition: remmina_ssh.h:176
    -
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    gboolean remmina_ssh_init_session(RemminaSSH *ssh)
    - +
    diff --git a/public/remmina__protocol__widget_8h.html b/public/remmina__protocol__widget_8h.html index 40afd2a0c..dad24002c 100644 --- a/public/remmina__protocol__widget_8h.html +++ b/public/remmina__protocol__widget_8h.html @@ -345,7 +345,7 @@ Functions
    -

    Definition at line 811 of file remmina_protocol_widget.c.

    +

    Definition at line 837 of file remmina_protocol_widget.c.

    @@ -381,7 +381,7 @@ Functions
    -

    Definition at line 798 of file remmina_protocol_widget.c.

    +

    Definition at line 824 of file remmina_protocol_widget.c.

    @@ -401,7 +401,7 @@ Functions
    -

    Definition at line 2029 of file remmina_protocol_widget.c.

    +

    Definition at line 2055 of file remmina_protocol_widget.c.

    @@ -443,7 +443,7 @@ Functions
    -

    Definition at line 2013 of file remmina_protocol_widget.c.

    +

    Definition at line 2039 of file remmina_protocol_widget.c.

    @@ -473,7 +473,7 @@ Functions
    -

    Definition at line 2036 of file remmina_protocol_widget.c.

    +

    Definition at line 2062 of file remmina_protocol_widget.c.

    @@ -493,7 +493,7 @@ Functions
    -

    Definition at line 469 of file remmina_protocol_widget.c.

    +

    Definition at line 494 of file remmina_protocol_widget.c.

    @@ -513,7 +513,7 @@ Functions
    -

    Definition at line 461 of file remmina_protocol_widget.c.

    +

    Definition at line 486 of file remmina_protocol_widget.c.

    @@ -543,7 +543,7 @@ Functions
    -

    Definition at line 748 of file remmina_protocol_widget.c.

    +

    Definition at line 774 of file remmina_protocol_widget.c.

    @@ -563,7 +563,7 @@ Functions
    -

    Definition at line 1854 of file remmina_protocol_widget.c.

    +

    Definition at line 1880 of file remmina_protocol_widget.c.

    @@ -583,7 +583,7 @@ Functions
    -

    Definition at line 1863 of file remmina_protocol_widget.c.

    +

    Definition at line 1889 of file remmina_protocol_widget.c.

    @@ -603,7 +603,7 @@ Functions
    -

    Definition at line 1872 of file remmina_protocol_widget.c.

    +

    Definition at line 1898 of file remmina_protocol_widget.c.

    @@ -623,7 +623,7 @@ Functions
    -

    Definition at line 1881 of file remmina_protocol_widget.c.

    +

    Definition at line 1907 of file remmina_protocol_widget.c.

    @@ -643,7 +643,7 @@ Functions
    -

    Definition at line 1413 of file remmina_protocol_widget.c.

    +

    Definition at line 1439 of file remmina_protocol_widget.c.

    @@ -663,7 +663,7 @@ Functions
    -

    Definition at line 1842 of file remmina_protocol_widget.c.

    +

    Definition at line 1868 of file remmina_protocol_widget.c.

    @@ -683,7 +683,7 @@ Functions
    -

    Definition at line 1444 of file remmina_protocol_widget.c.

    +

    Definition at line 1470 of file remmina_protocol_widget.c.

    @@ -703,7 +703,7 @@ Functions
    -

    Definition at line 1425 of file remmina_protocol_widget.c.

    +

    Definition at line 1451 of file remmina_protocol_widget.c.

    @@ -723,7 +723,7 @@ Functions
    -

    Definition at line 769 of file remmina_protocol_widget.c.

    +

    Definition at line 795 of file remmina_protocol_widget.c.

    @@ -743,7 +743,7 @@ Functions
    -

    Definition at line 1476 of file remmina_protocol_widget.c.

    +

    Definition at line 1502 of file remmina_protocol_widget.c.

    @@ -763,7 +763,7 @@ Functions
    -

    Definition at line 2083 of file remmina_protocol_widget.c.

    +

    Definition at line 2109 of file remmina_protocol_widget.c.

    @@ -783,7 +783,7 @@ Functions
    -

    Definition at line 1401 of file remmina_protocol_widget.c.

    +

    Definition at line 1427 of file remmina_protocol_widget.c.

    @@ -803,7 +803,7 @@ Functions
    -

    Definition at line 1367 of file remmina_protocol_widget.c.

    +

    Definition at line 1393 of file remmina_protocol_widget.c.

    @@ -823,7 +823,7 @@ Functions
    -

    Definition at line 1383 of file remmina_protocol_widget.c.

    +

    Definition at line 1409 of file remmina_protocol_widget.c.

    @@ -843,7 +843,7 @@ Functions
    -

    Definition at line 1836 of file remmina_protocol_widget.c.

    +

    Definition at line 1862 of file remmina_protocol_widget.c.

    @@ -863,7 +863,7 @@ Functions
    -

    Definition at line 1376 of file remmina_protocol_widget.c.

    +

    Definition at line 1402 of file remmina_protocol_widget.c.

    @@ -883,7 +883,7 @@ Functions
    -

    Definition at line 1360 of file remmina_protocol_widget.c.

    +

    Definition at line 1386 of file remmina_protocol_widget.c.

    @@ -903,7 +903,7 @@ Functions
    -

    Definition at line 1848 of file remmina_protocol_widget.c.

    +

    Definition at line 1874 of file remmina_protocol_widget.c.

    @@ -941,7 +941,7 @@ Functions
    -

    Definition at line 1830 of file remmina_protocol_widget.c.

    +

    Definition at line 1856 of file remmina_protocol_widget.c.

    @@ -961,7 +961,7 @@ Functions
    -

    Definition at line 1389 of file remmina_protocol_widget.c.

    +

    Definition at line 1415 of file remmina_protocol_widget.c.

    @@ -981,7 +981,7 @@ Functions
    -

    Definition at line 217 of file remmina_protocol_widget.c.

    +

    Definition at line 218 of file remmina_protocol_widget.c.

    @@ -1001,7 +1001,7 @@ Functions
    -

    Definition at line 2088 of file remmina_protocol_widget.c.

    +

    Definition at line 2114 of file remmina_protocol_widget.c.

    @@ -1021,7 +1021,7 @@ Functions
    -

    Definition at line 1438 of file remmina_protocol_widget.c.

    +

    Definition at line 1464 of file remmina_protocol_widget.c.

    @@ -1041,7 +1041,7 @@ Functions
    -

    Definition at line 1470 of file remmina_protocol_widget.c.

    +

    Definition at line 1496 of file remmina_protocol_widget.c.

    @@ -1061,7 +1061,7 @@ Functions
    -

    Definition at line 438 of file remmina_protocol_widget.c.

    +

    Definition at line 463 of file remmina_protocol_widget.c.

    @@ -1081,7 +1081,7 @@ Functions
    -

    Definition at line 724 of file remmina_protocol_widget.c.

    +

    Definition at line 750 of file remmina_protocol_widget.c.

    @@ -1111,7 +1111,7 @@ Functions
    -

    Definition at line 895 of file remmina_protocol_widget.c.

    +

    Definition at line 921 of file remmina_protocol_widget.c.

    @@ -1153,7 +1153,7 @@ Functions
    -

    Definition at line 870 of file remmina_protocol_widget.c.

    +

    Definition at line 896 of file remmina_protocol_widget.c.

    @@ -1173,7 +1173,7 @@ Functions
    -

    Definition at line 2093 of file remmina_protocol_widget.c.

    +

    Definition at line 2119 of file remmina_protocol_widget.c.

    @@ -1193,7 +1193,7 @@ Functions
    -

    Definition at line 316 of file remmina_protocol_widget.c.

    +

    Definition at line 318 of file remmina_protocol_widget.c.

    @@ -1253,7 +1253,7 @@ Functions
    -

    Definition at line 1694 of file remmina_protocol_widget.c.

    +

    Definition at line 1720 of file remmina_protocol_widget.c.

    @@ -1289,7 +1289,7 @@ Functions
    -

    Definition at line 1702 of file remmina_protocol_widget.c.

    +

    Definition at line 1728 of file remmina_protocol_widget.c.

    @@ -1309,7 +1309,7 @@ Functions
    -

    Definition at line 1756 of file remmina_protocol_widget.c.

    +

    Definition at line 1782 of file remmina_protocol_widget.c.

    @@ -1357,7 +1357,7 @@ Functions
    -

    Definition at line 1796 of file remmina_protocol_widget.c.

    +

    Definition at line 1822 of file remmina_protocol_widget.c.

    @@ -1395,7 +1395,7 @@ Functions
    -

    Definition at line 2001 of file remmina_protocol_widget.c.

    +

    Definition at line 2027 of file remmina_protocol_widget.c.

    @@ -1437,7 +1437,7 @@ Functions
    -

    Definition at line 1764 of file remmina_protocol_widget.c.

    +

    Definition at line 1790 of file remmina_protocol_widget.c.

    @@ -1467,7 +1467,7 @@ Functions
    -

    Definition at line 1689 of file remmina_protocol_widget.c.

    +

    Definition at line 1715 of file remmina_protocol_widget.c.

    @@ -1487,7 +1487,7 @@ Functions
    -

    Definition at line 1995 of file remmina_protocol_widget.c.

    +

    Definition at line 2021 of file remmina_protocol_widget.c.

    @@ -1517,7 +1517,7 @@ Functions
    -

    Definition at line 1944 of file remmina_protocol_widget.c.

    +

    Definition at line 1970 of file remmina_protocol_widget.c.

    @@ -1537,7 +1537,7 @@ Functions
    -

    Definition at line 1973 of file remmina_protocol_widget.c.

    +

    Definition at line 1999 of file remmina_protocol_widget.c.

    @@ -1559,7 +1559,7 @@ Functions

    Check if the plugin accepts keystrokes.

    -

    Definition at line 504 of file remmina_protocol_widget.c.

    +

    Definition at line 530 of file remmina_protocol_widget.c.

    @@ -1589,7 +1589,7 @@ Functions
    -

    Definition at line 713 of file remmina_protocol_widget.c.

    +

    Definition at line 739 of file remmina_protocol_widget.c.

    @@ -1619,7 +1619,7 @@ Functions
    -

    Definition at line 792 of file remmina_protocol_widget.c.

    +

    Definition at line 818 of file remmina_protocol_widget.c.

    @@ -1649,7 +1649,7 @@ Functions
    -

    Definition at line 775 of file remmina_protocol_widget.c.

    +

    Definition at line 801 of file remmina_protocol_widget.c.

    @@ -1679,7 +1679,7 @@ Functions
    -

    Definition at line 857 of file remmina_protocol_widget.c.

    +

    Definition at line 883 of file remmina_protocol_widget.c.

    @@ -1699,7 +1699,7 @@ Functions
    -

    Definition at line 1890 of file remmina_protocol_widget.c.

    +

    Definition at line 1916 of file remmina_protocol_widget.c.

    @@ -1729,7 +1729,7 @@ Functions
    -

    Definition at line 699 of file remmina_protocol_widget.c.

    +

    Definition at line 725 of file remmina_protocol_widget.c.

    @@ -1771,7 +1771,7 @@ Functions
    -

    Definition at line 2102 of file remmina_protocol_widget.c.

    +

    Definition at line 2128 of file remmina_protocol_widget.c.

    @@ -1803,7 +1803,7 @@ Functions

    Send to the plugin some keystrokes.

    -

    Definition at line 512 of file remmina_protocol_widget.c.

    +

    Definition at line 538 of file remmina_protocol_widget.c.

    @@ -1833,7 +1833,7 @@ Functions
    -

    Definition at line 1419 of file remmina_protocol_widget.c.

    +

    Definition at line 1445 of file remmina_protocol_widget.c.

    @@ -1863,7 +1863,7 @@ Functions
    -

    Definition at line 1347 of file remmina_protocol_widget.c.

    +

    Definition at line 1373 of file remmina_protocol_widget.c.

    @@ -1899,7 +1899,7 @@ Functions
    -

    Definition at line 1450 of file remmina_protocol_widget.c.

    +

    Definition at line 1476 of file remmina_protocol_widget.c.

    @@ -1929,7 +1929,7 @@ Functions
    -

    Definition at line 1431 of file remmina_protocol_widget.c.

    +

    Definition at line 1457 of file remmina_protocol_widget.c.

    @@ -1959,7 +1959,7 @@ Functions
    -

    Definition at line 1407 of file remmina_protocol_widget.c.

    +

    Definition at line 1433 of file remmina_protocol_widget.c.

    @@ -1989,7 +1989,7 @@ Functions
    -

    Definition at line 864 of file remmina_protocol_widget.c.

    +

    Definition at line 890 of file remmina_protocol_widget.c.

    @@ -2019,7 +2019,7 @@ Functions
    -

    Definition at line 1395 of file remmina_protocol_widget.c.

    +

    Definition at line 1421 of file remmina_protocol_widget.c.

    @@ -2055,7 +2055,7 @@ Functions
    -

    Definition at line 2058 of file remmina_protocol_widget.c.

    +

    Definition at line 2084 of file remmina_protocol_widget.c.

    @@ -2075,7 +2075,7 @@ Functions
    -

    Definition at line 360 of file remmina_protocol_widget.c.

    +

    Definition at line 384 of file remmina_protocol_widget.c.

    @@ -2095,7 +2095,7 @@ Functions
    -

    Definition at line 396 of file remmina_protocol_widget.c.

    +

    Definition at line 421 of file remmina_protocol_widget.c.

    @@ -2137,7 +2137,7 @@ Functions
    -

    Definition at line 1195 of file remmina_protocol_widget.c.

    +

    Definition at line 1221 of file remmina_protocol_widget.c.

    @@ -2175,7 +2175,7 @@ Functions

    Start an SSH tunnel if possible and return the host:port string.

    -

    Definition at line 1062 of file remmina_protocol_widget.c.

    +

    Definition at line 1088 of file remmina_protocol_widget.c.

    @@ -2205,7 +2205,7 @@ Functions
    -

    Definition at line 1164 of file remmina_protocol_widget.c.

    +

    Definition at line 1190 of file remmina_protocol_widget.c.

    @@ -2235,7 +2235,7 @@ Functions
    -

    Definition at line 1302 of file remmina_protocol_widget.c.

    +

    Definition at line 1328 of file remmina_protocol_widget.c.

    @@ -2255,7 +2255,7 @@ Functions
    -

    Definition at line 445 of file remmina_protocol_widget.c.

    +

    Definition at line 470 of file remmina_protocol_widget.c.

    @@ -2275,7 +2275,7 @@ Functions
    -

    Definition at line 736 of file remmina_protocol_widget.c.

    +

    Definition at line 762 of file remmina_protocol_widget.c.

    @@ -2295,7 +2295,7 @@ Functions
    -

    Definition at line 413 of file remmina_protocol_widget.c.

    +

    Definition at line 438 of file remmina_protocol_widget.c.

    @@ -2315,7 +2315,7 @@ Functions
    -

    Definition at line 2142 of file remmina_protocol_widget.c.

    +

    Definition at line 2168 of file remmina_protocol_widget.c.

    diff --git a/public/remmina__protocol__widget_8h_source.html b/public/remmina__protocol__widget_8h_source.html index 4e03cf008..64115bb82 100644 --- a/public/remmina__protocol__widget_8h_source.html +++ b/public/remmina__protocol__widget_8h_source.html @@ -86,109 +86,109 @@ $(document).ready(function(){initNavTree('remmina__protocol__widget_8h_source.ht
    remmina_protocol_widget.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-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #pragma once
    38 
    39 #include "rcw.h"
    40 #include "remmina_file.h"
    41 #include "remmina_ssh.h"
    42 
    43 G_BEGIN_DECLS
    44 
    45 #define REMMINA_PROTOCOL_FEATURE_TOOL_SSH -1
    46 #define REMMINA_PROTOCOL_FEATURE_TOOL_SFTP -2
    47 
    48 #define REMMINA_TYPE_PROTOCOL_WIDGET (remmina_protocol_widget_get_type())
    49 #define REMMINA_PROTOCOL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidget))
    50 #define REMMINA_PROTOCOL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidgetClass))
    51 #define REMMINA_IS_PROTOCOL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), REMMINA_TYPE_PROTOCOL_WIDGET))
    52 #define REMMINA_IS_PROTOCOL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), REMMINA_TYPE_PROTOCOL_WIDGET))
    53 #define REMMINA_PROTOCOL_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidgetClass))
    54 
    57 
    59  GtkEventBox event_box;
    63 };
    64 
    66  GtkEventBoxClass parent_class;
    67 
    68  void (*connect)(RemminaProtocolWidget *gp);
    69  void (*disconnect)(RemminaProtocolWidget *gp);
    74 };
    75 
    77 G_GNUC_CONST;
    78 
    81 
    82 GtkWidget *remmina_protocol_widget_new(void);
    84 
    93 
    100 void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt, ...);
    103 
    118 /* Provide thread-safe way to emit signals */
    119 void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name);
    121 
    122 typedef gboolean (*RemminaHostkeyFunc)(RemminaProtocolWidget *gp, guint keyval, gboolean release);
    124 
    125 gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...);
    126 
    127 /* Start a SSH tunnel if it’s enabled. Returns a newly allocated string indicating:
    128  * 1. The actual destination (host:port) if SSH tunnel is disable
    129  * 2. The tunnel local destination (127.0.0.1:port) if SSH tunnel is enabled
    130  */
    131 gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus);
    132 
    136 
    137 /* Extension for remmina_protocol_widget_panel_authuserpwd() not currently exported to plugins */
    138 gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving);
    139 
    140 /* Dialog panel API used by the plugins */
    141 
    142 gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt);
    143 gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint);
    144 gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint);
    146 
    153 
    155 
    164 
    165 void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void (*on_send)(RemminaProtocolWidget *gp, const gchar *text), void (*on_destroy)(RemminaProtocolWidget *gp));
    168 void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action);
    169 /* Check if the plugin accepts keystrokes */
    171 /* Send to the plugin some keystrokes */
    174 /* Take screenshot of plugin */
    176 /* Deal with the remimna connection window map/unmap events */
    179 
    181 
    182 /* Functions to support execution of GTK code on master thread */
    183 RemminaMessagePanel *remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data);
    185 
    186 
    187 G_END_DECLS
    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.
    -
    static gboolean desktop_resize(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-2023 Antenore Gatta, Giovanni Panozzo
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    20  * Boston, MA 02110-1301, USA.
    21  *
    22  * In addition, as a special exception, the copyright holders give
    23  * permission to link the code of portions of this program with the
    24  * OpenSSL library under certain conditions as described in each
    25  * individual source file, and distribute linked combinations
    26  * including the two.
    27  * You must obey the GNU General Public License in all respects
    28  * for all of the code used other than OpenSSL. * If you modify
    29  * file(s) with this exception, you may extend this exception to your
    30  * version of the file(s), but you are not obligated to do so. * If you
    31  * do not wish to do so, delete this exception statement from your
    32  * version. * If you delete this exception statement from all source
    33  * files in the program, then also delete it here.
    34  *
    35  */
    36 
    37 #pragma once
    38 
    39 #include "rcw.h"
    40 #include "remmina_file.h"
    41 #include "remmina_ssh.h"
    42 
    43 G_BEGIN_DECLS
    44 
    45 #define REMMINA_PROTOCOL_FEATURE_TOOL_SSH -1
    46 #define REMMINA_PROTOCOL_FEATURE_TOOL_SFTP -2
    47 
    48 #define REMMINA_TYPE_PROTOCOL_WIDGET (remmina_protocol_widget_get_type())
    49 #define REMMINA_PROTOCOL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidget))
    50 #define REMMINA_PROTOCOL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidgetClass))
    51 #define REMMINA_IS_PROTOCOL_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), REMMINA_TYPE_PROTOCOL_WIDGET))
    52 #define REMMINA_IS_PROTOCOL_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), REMMINA_TYPE_PROTOCOL_WIDGET))
    53 #define REMMINA_PROTOCOL_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), REMMINA_TYPE_PROTOCOL_WIDGET, RemminaProtocolWidgetClass))
    54 
    57 
    59  GtkEventBox event_box;
    63 };
    64 
    66  GtkEventBoxClass parent_class;
    67 
    68  void (*connect)(RemminaProtocolWidget *gp);
    69  void (*disconnect)(RemminaProtocolWidget *gp);
    74 };
    75 
    77 G_GNUC_CONST;
    78 
    81 
    82 GtkWidget *remmina_protocol_widget_new(void);
    84 
    93 
    100 void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt, ...);
    103 
    118 /* Provide thread-safe way to emit signals */
    119 void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name);
    121 
    122 typedef gboolean (*RemminaHostkeyFunc)(RemminaProtocolWidget *gp, guint keyval, gboolean release);
    124 
    125 gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt, ...);
    126 
    127 /* Start a SSH tunnel if it’s enabled. Returns a newly allocated string indicating:
    128  * 1. The actual destination (host:port) if SSH tunnel is disable
    129  * 2. The tunnel local destination (127.0.0.1:port) if SSH tunnel is enabled
    130  */
    131 gchar *remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus);
    132 
    136 
    137 /* Extension for remmina_protocol_widget_panel_authuserpwd() not currently exported to plugins */
    138 gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving);
    139 
    140 /* Dialog panel API used by the plugins */
    141 
    142 gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt);
    143 gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint);
    144 gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint);
    146 
    153 
    155 
    164 
    165 void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void (*on_send)(RemminaProtocolWidget *gp, const gchar *text), void (*on_destroy)(RemminaProtocolWidget *gp));
    168 void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action);
    169 /* Check if the plugin accepts keystrokes */
    171 /* Send to the plugin some keystrokes */
    174 /* Take screenshot of plugin */
    176 /* Deal with the remimna connection window map/unmap events */
    179 
    181 
    182 /* Functions to support execution of GTK code on master thread */
    183 RemminaMessagePanel *remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data);
    185 
    186 
    187 G_END_DECLS
    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.
    +
    static gboolean desktop_resize(gpointer data)
    -
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    -
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    -
    static gboolean lock_dynres(gpointer data)
    -
    void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
    -
    static gboolean unlock_dynres(gpointer data)
    +
    gint remmina_protocol_widget_panel_new_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    +
    void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_lock_dynres(RemminaProtocolWidget *gp)
    +
    static gboolean lock_dynres(gpointer data)
    +
    void remmina_protocol_widget_signal_connection_closed(RemminaProtocolWidget *gp)
    +
    static gboolean unlock_dynres(gpointer data)
    -
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_clientkey(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_chat_close(RemminaProtocolWidget *gp)
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    -
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    -
    gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    -
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    -
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    -
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    +
    RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_send_clipboard(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    +
    gint remmina_protocol_widget_panel_authuserpwd_ssh_tunnel(RemminaProtocolWidget *gp, gboolean want_domain, gboolean allow_password_saving)
    +
    void remmina_protocol_widget_chat_receive(RemminaProtocolWidget *gp, const gchar *text)
    +
    gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget *gp, gboolean wait, const gchar *fmt,...)
    +
    void remmina_protocol_widget_panel_show(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_save_cred(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    -
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget *gp, gint local_port)
    +
    gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    -
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    -
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    -
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    -
    GtkWidget * remmina_protocol_widget_new(void)
    +
    gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget *gp, GtkWidget *widget)
    +
    void remmina_protocol_widget_mpdestroy(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
    +
    gchar * remmina_protocol_widget_get_cacert(RemminaProtocolWidget *gp)
    +
    GtkWidget * remmina_protocol_widget_new(void)
    RemminaMessagePanelFlags
    Definition: types.h:156
    -
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    -
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    -
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    -
    GtkWindow * remmina_protocol_widget_get_gtkwindow(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_setup(RemminaProtocolWidget *gp, RemminaFile *remminafile, RemminaConnectionObject *cnnobj)
    +
    void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget *gp, GtkMenuItem *widget)
    Send to the plugin some keystrokes.
    +
    gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget *gp)
    Check if the plugin accepts keystrokes.
    +
    GtkWindow * remmina_protocol_widget_get_gtkwindow(RemminaProtocolWidget *gp)
    RemminaProtocolPlugin * plugin
    void remmina_protocol_widget_panel_destroy(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    -
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    -
    void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget *gp, RemminaXPortTunnelInitFunc init_func)
    +
    void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode)
    +
    void remmina_protocol_widget_desktop_resize(RemminaProtocolWidget *gp)
    RemminaProtocolWidgetPriv * priv
    -
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget *gp)
    gboolean(* RemminaHostkeyFunc)(RemminaProtocolWidget *gp, guint keyval, gboolean release)
    -
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    -
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    +
    void remmina_protocol_widget_panel_show_listen(RemminaProtocolWidget *gp, gint port)
    +
    gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    RemminaConnectionObject * cnnobj
    -
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    -
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    -
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    -
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    -
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_cacrl(RemminaProtocolWidget *gp)
    +
    const gchar * remmina_protocol_widget_get_error_message(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height)
    +
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    +
    gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_panel_hide(RemminaProtocolWidget *gp)
    +
    const gchar * remmina_protocol_widget_get_name(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_clientcert(RemminaProtocolWidget *gp)
    RemminaProtocolFeatureType
    Definition: types.h:46
    -
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    void(* RemminaMessagePanelCallback)(void *user_data, int button)
    GType remmina_protocol_widget_get_type(void) G_GNUC_CONST
    -
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    +
    void remmina_protocol_widget_set_expand(RemminaProtocolWidget *gp, gboolean expand)
    RemminaScaleMode
    Definition: types.h:142
    -
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    -
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    -
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    -
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    -
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    -
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    -
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    -
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    -
    static gboolean update_align(gpointer data)
    -
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    -
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    -
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    -
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_signal_connection_opened(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_emit_signal(RemminaProtocolWidget *gp, const gchar *signal_name)
    +
    gint remmina_protocol_widget_panel_authx509(RemminaProtocolWidget *gp)
    +
    GtkWidget * remmina_protocol_widget_gtkviewport(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_domain(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_unlock_dynres(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_display(RemminaProtocolWidget *gp, gint display)
    +
    RemminaMessagePanel * remmina_protocol_widget_mpprogress(RemminaConnectionObject *cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
    +
    void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    +
    void remmina_protocol_widget_panel_show_retry(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *fmt,...)
    +
    gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_unmap_event(RemminaProtocolWidget *gp)
    +
    static gboolean update_align(gpointer data)
    +
    void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *keyvals, int keyvals_length, GdkEventType action)
    +
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    +
    void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget *gp, RemminaHostkeyFunc func)
    +
    gint remmina_protocol_widget_get_width(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    -
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    -
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    -
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    -
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    -
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    -
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    +
    void remmina_protocol_widget_update_align(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    +
    gboolean remmina_protocol_widget_map_event(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type)
    +
    void remmina_protocol_widget_chat_open(RemminaProtocolWidget *gp, const gchar *name, void(*on_send)(RemminaProtocolWidget *gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget *gp))
    +
    const RemminaProtocolFeature * remmina_protocol_widget_get_features(RemminaProtocolWidget *gp)
    +
    gint remmina_protocol_widget_panel_changed_certificate(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    gboolean(* RemminaXPortTunnelInitFunc)(RemminaProtocolWidget *gp, gint remotedisplay, const gchar *server, gint port)
    Definition: types.h:95
    -
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget *gp)
    -
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    -
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    -
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    +
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_set_width(RemminaProtocolWidget *gp, gint width)
    +
    gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp)
    +
    void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp)
    diff --git a/public/remmina__ssh_8c_source.html b/public/remmina__ssh_8c_source.html index 982efbedc..df40206de 100644 --- a/public/remmina__ssh_8c_source.html +++ b/public/remmina__ssh_8c_source.html @@ -112,10 +112,10 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
    gchar * run_line
    Definition: remmina_ssh.h:249
    gchar * error
    Definition: remmina_ssh.h:80
    gchar * passphrase
    Definition: remmina_ssh.h:84
    -
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    +
    gint remmina_protocol_widget_panel_auth(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
    Definition: types.h:158
    pthread_mutex_t ssh_mutex
    Definition: remmina_ssh.h:82
    -
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    +
    gboolean remmina_protocol_widget_get_savepassword(RemminaProtocolWidget *gp)
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    gchar * ciphers
    Definition: remmina_ssh.h:74
    static void remmina_ssh_delete_item(ssh_channel channel)
    Definition: remmina_ssh.c:226
    @@ -168,7 +168,7 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
    static int remmina_ssh_cp_to_fd_cb(ssh_session session, ssh_channel channel, void *data, uint32_t len, int is_stderr, void *userdata)
    Definition: remmina_ssh.c:537
    Definition: remmina_ssh.h:114
    -
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    +
    gint remmina_protocol_widget_panel_question_yesno(RemminaProtocolWidget *gp, const char *msg)
    gchar * buffer
    Definition: remmina_ssh.h:162
    gint tunnel_entrance_port
    Definition: remmina_ssh.h:89
    RemminaSSHShell * remmina_ssh_shell_new_from_file(RemminaFile *remminafile)
    @@ -226,7 +226,7 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
    RemminaSSHExitFunc exit_callback
    Definition: remmina_ssh.h:253
    gchar * remmina_ssh_convert(RemminaSSH *ssh, const gchar *from)
    gchar * exec
    Definition: remmina_ssh.h:248
    -
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_password(RemminaProtocolWidget *gp)
    Definition: remmina_file.h:68
    ssh_callbacks callback
    Definition: remmina_ssh.h:61
    gboolean remmina_sftp_open(RemminaSFTP *sftp)
    @@ -246,7 +246,7 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
    void remmina_public_get_server_port(const gchar *server, gint defaultport, gchar **host, gint *port)
    gboolean remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port)
    RemminaSFTP * remmina_sftp_new_from_file(RemminaFile *remminafile)
    -
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    +
    RemminaFile * remmina_protocol_widget_get_file(RemminaProtocolWidget *gp)
    static int remmina_ssh_connect_local_xsocket(int display_number)
    Definition: remmina_ssh.c:377
    gchar * certfile
    Definition: remmina_ssh.h:70
    gint master
    Definition: remmina_ssh.h:246
    @@ -259,7 +259,7 @@ $(document).ready(function(){initNavTree('remmina__ssh_8c_source.html','');});
    RemminaSSHTunnelCallback connect_func
    Definition: remmina_ssh.h:176
    Definition: remmina_file.h:70
    -
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    +
    gchar * remmina_protocol_widget_get_username(RemminaProtocolWidget *gp)
    gboolean is_multiauth
    Definition: remmina_ssh.h:87
    gboolean remmina_ssh_init_session(RemminaSSH *ssh)
    enum remmina_ssh_auth_result remmina_ssh_auth(RemminaSSH *ssh, const gchar *password, RemminaProtocolWidget *gp, RemminaFile *remminafile)
    Definition: remmina_ssh.c:1085
    diff --git a/public/remmina__ssh__plugin_8c_source.html b/public/remmina__ssh__plugin_8c_source.html index fcd9199e5..7517e1d5a 100644 --- a/public/remmina__ssh__plugin_8c_source.html +++ b/public/remmina__ssh__plugin_8c_source.html @@ -135,7 +135,7 @@ $(document).ready(function(){initNavTree('remmina__ssh__plugin_8c_source.html','
    gchar * color2
    Definition: remmina_pref.h:117
    Definition: remmina_ssh.h:59
    GtkToggleButton * wrap_around_checkbutton
    -
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    +
    void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget *gp, RemminaProtocolFeatureType type, gint id)
    Definition: remmina_ssh.h:113
    const GdkRGBA tango_palette[PALETTE_SIZE]
    diff --git a/public/search/all_12.js b/public/search/all_12.js index aed5a86df..86af78bd5 100644 --- a/public/search/all_12.js +++ b/public/search/all_12.js @@ -1429,8 +1429,8 @@ var searchData= ['remmina_5fssh_5ftunnel_5fcancel_5faccept',['remmina_ssh_tunnel_cancel_accept',['../remmina__ssh_8h.html#ae9f52b1a3a545acae8c93007e20ec909',1,'remmina_ssh.h']]], ['remmina_5fssh_5ftunnel_5ffree',['remmina_ssh_tunnel_free',['../remmina__ssh_8h.html#a223f8dd7a678bcec2ece40a2d8f7ea06',1,'remmina_ssh.h']]], ['remmina_5fssh_5ftunnel_5fnew_5ffrom_5ffile',['remmina_ssh_tunnel_new_from_file',['../remmina__ssh_8h.html#abf04fd329ab77bbd4f6aa1cb1eaa349d',1,'remmina_ssh.h']]], - ['remmina_5fssh_5ftunnel_5fopen',['remmina_ssh_tunnel_open',['../remmina__ssh_8h.html#a52b3f47eac79f2781ba81d61505f4f53',1,'remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port): remmina_ssh.h'],['../remmina__ssh_8h.html#a77867ab4129f63159b37bca3b652a798a78cac65c66c1f72592488c7c5728ea14',1,'REMMINA_SSH_TUNNEL_OPEN(): remmina_ssh.h']]], - ['remmina_5fssh_5ftunnel_5freverse',['REMMINA_SSH_TUNNEL_REVERSE',['../remmina__ssh_8h.html#a77867ab4129f63159b37bca3b652a798ae14c0d50235951946ca18866a1329459',1,'REMMINA_SSH_TUNNEL_REVERSE(): remmina_ssh.h'],['../remmina__ssh_8h.html#ae47c8270267b02b9c0ff5b36074101c2',1,'remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port): remmina_ssh.h']]], + ['remmina_5fssh_5ftunnel_5fopen',['REMMINA_SSH_TUNNEL_OPEN',['../remmina__ssh_8h.html#a77867ab4129f63159b37bca3b652a798a78cac65c66c1f72592488c7c5728ea14',1,'REMMINA_SSH_TUNNEL_OPEN(): remmina_ssh.h'],['../remmina__ssh_8h.html#a52b3f47eac79f2781ba81d61505f4f53',1,'remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port): remmina_ssh.h']]], + ['remmina_5fssh_5ftunnel_5freverse',['remmina_ssh_tunnel_reverse',['../remmina__ssh_8h.html#ae47c8270267b02b9c0ff5b36074101c2',1,'remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port): remmina_ssh.h'],['../remmina__ssh_8h.html#a77867ab4129f63159b37bca3b652a798ae14c0d50235951946ca18866a1329459',1,'REMMINA_SSH_TUNNEL_REVERSE(): remmina_ssh.h']]], ['remmina_5fssh_5ftunnel_5fterminated',['remmina_ssh_tunnel_terminated',['../remmina__ssh_8h.html#aeb20d31243a4d30e469a34fe01684e38',1,'remmina_ssh.h']]], ['remmina_5fssh_5ftunnel_5fxport',['REMMINA_SSH_TUNNEL_XPORT',['../remmina__ssh_8h.html#a77867ab4129f63159b37bca3b652a798afbca41cd7b252c2594e1d53cd081b326',1,'REMMINA_SSH_TUNNEL_XPORT(): remmina_ssh.h'],['../remmina__ssh_8h.html#aba49db2ced40e21e8adfad69dcfda2c4',1,'remmina_ssh_tunnel_xport(RemminaSSHTunnel *tunnel, gboolean bindlocalhost): remmina_ssh.h']]], ['remmina_5fssh_5funconvert',['remmina_ssh_unconvert',['../remmina__ssh_8h.html#aeccf94afb57bcad37b4241d45fcb3fea',1,'remmina_ssh.h']]], @@ -1604,7 +1604,7 @@ var searchData= ['remminalanguagewrapperplugin',['RemminaLanguageWrapperPlugin',['../plugin_8h.html#a4cc4789bb1ba76d339b61b364399c304',1,'plugin.h']]], ['remminalogwindow',['RemminaLogWindow',['../remmina__log_8c.html#ad5a920aad512279bb932bcb26a2c3c19',1,'remmina_log.c']]], ['remminalogwindowclass',['RemminaLogWindowClass',['../remmina__log_8c.html#a5682db89dd84e1c413326e17a4f79dbe',1,'remmina_log.c']]], - ['remminamain',['remminamain',['../remmina__main_8c.html#ab7c680e1f6ffeef21cb928a083d36d89',1,'remminamain(): remmina_main.c'],['../remmina__main_8h.html#ad17d9a48f2b3f84e17baa91104bc6cb1',1,'RemminaMain(): remmina_main.h']]], + ['remminamain',['RemminaMain',['../remmina__main_8h.html#ad17d9a48f2b3f84e17baa91104bc6cb1',1,'RemminaMain(): remmina_main.h'],['../remmina__main_8c.html#ab7c680e1f6ffeef21cb928a083d36d89',1,'remminamain(): remmina_main.c']]], ['remminamainpriv',['RemminaMainPriv',['../remmina__main_8h.html#a49e7c1b5d4dcfd155886e39d78b3d052',1,'remmina_main.h']]], ['remminamessagepanelcallback',['RemminaMessagePanelCallback',['../remmina__message__panel_8h.html#ae2923c94c1caf1ac4a7eb48361d2670a',1,'remmina_message_panel.h']]], ['remminamessagepanelflags',['RemminaMessagePanelFlags',['../types_8h.html#a341a0a8b6509633809d99348cc3ba486',1,'types.h']]], diff --git a/public/search/all_15.js b/public/search/all_15.js index 39b4698a5..844f8ba5a 100644 --- a/public/search/all_15.js +++ b/public/search/all_15.js @@ -39,6 +39,7 @@ var searchData= ['user',['user',['../struct___remmina_s_s_h.html#a3a8dc7679e22208bbdf076c520f25bbb',1,'_RemminaSSH']]], ['user_5fcancelled',['user_cancelled',['../structrf__context.html#acacad775c2c168f900deaa6c90481319',1,'rf_context']]], ['user_5fdata',['user_data',['../struct___remmina_s_s_h_shell.html#adedb04066148973fed2de9f04b80286d',1,'_RemminaSSHShell']]], + ['user_5fdisconnect',['user_disconnect',['../struct___remmina_protocol_widget_priv.html#a8fc83f0db5c5d5d8fad8467d96e35642',1,'_RemminaProtocolWidgetPriv']]], ['username',['username',['../structmpchanger__params.html#a634dd9d08486b2a435fba15119db6742',1,'mpchanger_params::username()'],['../struct___remmina_protocol_widget_priv.html#ae3feb5e5dad00109813fac890d913885',1,'_RemminaProtocolWidgetPriv::username()'],['../struct___connection_data.html#af15752c3cf9e16fff53be579bf747541',1,'_ConnectionData::username()']]], ['ustats_5ftoggle',['ustats_toggle',['../struct___remmina_main.html#aa1e811e50525f5a74bb781f8c8a10670',1,'_RemminaMain']]] ]; diff --git a/public/search/all_3.js b/public/search/all_3.js index 0bf74d284..664249992 100644 --- a/public/search/all_3.js +++ b/public/search/all_3.js @@ -168,6 +168,7 @@ var searchData= ['confirm_5fclose',['confirm_close',['../struct___remmina_pref.html#aa9a057b8d4095678d3c0806ab37af365',1,'_RemminaPref']]], ['conn',['conn',['../struct___g_vnc_plugin_data.html#a45a2c89f810b30ea993ba3245a3312e9',1,'_GVncPluginData']]], ['conn_5fclosed',['conn_closed',['../remmina__protocol__widget_8c.html#a69757e0c39fa9fcf31800f6375772016',1,'remmina_protocol_widget.c']]], + ['conn_5fclosed_5freal',['conn_closed_real',['../remmina__protocol__widget_8c.html#aa905484fffd7eaa072b834db6ffb642c',1,'remmina_protocol_widget.c']]], ['conn_5fopened',['conn_opened',['../remmina__protocol__widget_8c.html#af4a20ef0ff8cc86feeba345498179e48',1,'remmina_protocol_widget.c']]], ['connect',['connect',['../struct___remmina_protocol_widget_class.html#a5cf457e2e48c9c2b831b0c8a4f88c760',1,'_RemminaProtocolWidgetClass']]], ['connect_5fdata',['connect_data',['../struct___x2_go_custom_user_data.html#a7091e9cd5dd55bd4f245721ee5bc1c83',1,'_X2GoCustomUserData']]], diff --git a/public/search/functions_3.js b/public/search/functions_3.js index 4b11c8cb0..73a72e90f 100644 --- a/public/search/functions_3.js +++ b/public/search/functions_3.js @@ -18,6 +18,7 @@ var searchData= ['compile_5fregex_5ffor_5fsearch',['compile_regex_for_search',['../remmina__ssh__plugin_8c.html#aa8645147eb398022c5e64887f7d143c7',1,'remmina_ssh_plugin.c']]], ['complete_5fcleanup_5fon_5fmain_5fthread',['complete_cleanup_on_main_thread',['../rdp__plugin_8c.html#a6aa88468d17f574532ca959f554a70c5',1,'rdp_plugin.c']]], ['conn_5fclosed',['conn_closed',['../remmina__protocol__widget_8c.html#a69757e0c39fa9fcf31800f6375772016',1,'remmina_protocol_widget.c']]], + ['conn_5fclosed_5freal',['conn_closed_real',['../remmina__protocol__widget_8c.html#aa905484fffd7eaa072b834db6ffb642c',1,'remmina_protocol_widget.c']]], ['conn_5fopened',['conn_opened',['../remmina__protocol__widget_8c.html#af4a20ef0ff8cc86feeba345498179e48',1,'remmina_protocol_widget.c']]], ['crlf2lf',['crlf2lf',['../rdp__cliprdr_8c.html#a55dec77cdcdc16a6d85680943eb2a859',1,'rdp_cliprdr.c']]] ]; diff --git a/public/search/variables_14.js b/public/search/variables_14.js index 651adfddf..f02fa3dcf 100644 --- a/public/search/variables_14.js +++ b/public/search/variables_14.js @@ -28,6 +28,7 @@ var searchData= ['user',['user',['../struct___remmina_s_s_h.html#a3a8dc7679e22208bbdf076c520f25bbb',1,'_RemminaSSH']]], ['user_5fcancelled',['user_cancelled',['../structrf__context.html#acacad775c2c168f900deaa6c90481319',1,'rf_context']]], ['user_5fdata',['user_data',['../struct___remmina_s_s_h_shell.html#adedb04066148973fed2de9f04b80286d',1,'_RemminaSSHShell']]], + ['user_5fdisconnect',['user_disconnect',['../struct___remmina_protocol_widget_priv.html#a8fc83f0db5c5d5d8fad8467d96e35642',1,'_RemminaProtocolWidgetPriv']]], ['username',['username',['../structmpchanger__params.html#a634dd9d08486b2a435fba15119db6742',1,'mpchanger_params::username()'],['../struct___remmina_protocol_widget_priv.html#ae3feb5e5dad00109813fac890d913885',1,'_RemminaProtocolWidgetPriv::username()'],['../struct___connection_data.html#af15752c3cf9e16fff53be579bf747541',1,'_ConnectionData::username()']]], ['ustats_5ftoggle',['ustats_toggle',['../struct___remmina_main.html#aa1e811e50525f5a74bb781f8c8a10670',1,'_RemminaMain']]] ]; diff --git a/public/struct___remmina_protocol_widget_priv.html b/public/struct___remmina_protocol_widget_priv.html index 7ade4c3b2..49feea52f 100644 --- a/public/struct___remmina_protocol_widget_priv.html +++ b/public/struct___remmina_protocol_widget_priv.html @@ -109,6 +109,8 @@ Data Fields   gchar * error_message   +gboolean user_disconnect +  GPtrArray * ssh_tunnels   RemminaTunnelInitFunc init_func @@ -166,7 +168,7 @@ Data Fields
    -

    Definition at line 89 of file remmina_protocol_widget.c.

    +

    Definition at line 90 of file remmina_protocol_widget.c.

    @@ -182,7 +184,7 @@ Data Fields
    -

    Definition at line 98 of file remmina_protocol_widget.c.

    +

    Definition at line 99 of file remmina_protocol_widget.c.

    @@ -198,7 +200,7 @@ Data Fields
    -

    Definition at line 99 of file remmina_protocol_widget.c.

    +

    Definition at line 100 of file remmina_protocol_widget.c.

    @@ -214,7 +216,7 @@ Data Fields
    -

    Definition at line 77 of file remmina_protocol_widget.c.

    +

    Definition at line 78 of file remmina_protocol_widget.c.

    @@ -230,7 +232,7 @@ Data Fields
    -

    Definition at line 100 of file remmina_protocol_widget.c.

    +

    Definition at line 101 of file remmina_protocol_widget.c.

    @@ -246,7 +248,7 @@ Data Fields
    -

    Definition at line 101 of file remmina_protocol_widget.c.

    +

    Definition at line 102 of file remmina_protocol_widget.c.

    @@ -262,7 +264,7 @@ Data Fields
    -

    Definition at line 79 of file remmina_protocol_widget.c.

    +

    Definition at line 80 of file remmina_protocol_widget.c.

    @@ -278,7 +280,7 @@ Data Fields
    -

    Definition at line 87 of file remmina_protocol_widget.c.

    +

    Definition at line 88 of file remmina_protocol_widget.c.

    @@ -294,7 +296,7 @@ Data Fields
    -

    Definition at line 95 of file remmina_protocol_widget.c.

    +

    Definition at line 96 of file remmina_protocol_widget.c.

    @@ -374,7 +376,7 @@ Data Fields
    -

    Definition at line 81 of file remmina_protocol_widget.c.

    +

    Definition at line 82 of file remmina_protocol_widget.c.

    @@ -390,7 +392,7 @@ Data Fields
    -

    Definition at line 75 of file remmina_protocol_widget.c.

    +

    Definition at line 76 of file remmina_protocol_widget.c.

    @@ -406,7 +408,7 @@ Data Fields
    -

    Definition at line 88 of file remmina_protocol_widget.c.

    +

    Definition at line 89 of file remmina_protocol_widget.c.

    @@ -422,7 +424,7 @@ Data Fields
    -

    Definition at line 85 of file remmina_protocol_widget.c.

    +

    Definition at line 86 of file remmina_protocol_widget.c.

    @@ -438,7 +440,7 @@ Data Fields
    -

    Definition at line 94 of file remmina_protocol_widget.c.

    +

    Definition at line 95 of file remmina_protocol_widget.c.

    @@ -470,7 +472,7 @@ Data Fields
    -

    Definition at line 84 of file remmina_protocol_widget.c.

    +

    Definition at line 85 of file remmina_protocol_widget.c.

    @@ -486,7 +488,7 @@ Data Fields
    -

    Definition at line 83 of file remmina_protocol_widget.c.

    +

    Definition at line 84 of file remmina_protocol_widget.c.

    @@ -518,7 +520,7 @@ Data Fields
    -

    Definition at line 90 of file remmina_protocol_widget.c.

    +

    Definition at line 91 of file remmina_protocol_widget.c.

    @@ -534,7 +536,7 @@ Data Fields
    -

    Definition at line 96 of file remmina_protocol_widget.c.

    +

    Definition at line 97 of file remmina_protocol_widget.c.

    @@ -582,7 +584,23 @@ Data Fields
    -

    Definition at line 74 of file remmina_protocol_widget.c.

    +

    Definition at line 75 of file remmina_protocol_widget.c.

    + +
    + + +

    ◆ user_disconnect

    + +
    +
    + + + + +
    gboolean _RemminaProtocolWidgetPriv::user_disconnect
    +
    + +

    Definition at line 72 of file remmina_protocol_widget.c.

    @@ -598,7 +616,7 @@ Data Fields
    -

    Definition at line 93 of file remmina_protocol_widget.c.

    +

    Definition at line 94 of file remmina_protocol_widget.c.

    diff --git a/public/struct___remmina_protocol_widget_priv.js b/public/struct___remmina_protocol_widget_priv.js index fc4f86be8..02f71bdbb 100644 --- a/public/struct___remmina_protocol_widget_priv.js +++ b/public/struct___remmina_protocol_widget_priv.js @@ -27,6 +27,7 @@ var struct___remmina_protocol_widget_priv = [ "scalemode", "struct___remmina_protocol_widget_priv.html#aa37ce53d4329aaaa7c4059c60882a533", null ], [ "scaler_expand", "struct___remmina_protocol_widget_priv.html#a94ef3b8e64d6ced7cd639b7917026f4c", null ], [ "ssh_tunnels", "struct___remmina_protocol_widget_priv.html#a277fd3954a4f89c6ddddd68f4ffb5116", null ], + [ "user_disconnect", "struct___remmina_protocol_widget_priv.html#a8fc83f0db5c5d5d8fad8467d96e35642", null ], [ "username", "struct___remmina_protocol_widget_priv.html#ae3feb5e5dad00109813fac890d913885", null ], [ "width", "struct___remmina_protocol_widget_priv.html#a5cbea00dcc608759fcf66186e6afde93", null ] ]; \ No newline at end of file diff --git a/public/struct___remmina_protocol_widget_signal_data.html b/public/struct___remmina_protocol_widget_signal_data.html index 9b8f4a9ba..59dc4f76f 100644 --- a/public/struct___remmina_protocol_widget_signal_data.html +++ b/public/struct___remmina_protocol_widget_signal_data.html @@ -98,7 +98,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 122 of file remmina_protocol_widget.c.

    +

    Definition at line 123 of file remmina_protocol_widget.c.

    Field Documentation

    ◆ gp

    @@ -112,7 +112,7 @@ Data Fields
    -

    Definition at line 123 of file remmina_protocol_widget.c.

    +

    Definition at line 124 of file remmina_protocol_widget.c.

    @@ -128,7 +128,7 @@ Data Fields
    -

    Definition at line 124 of file remmina_protocol_widget.c.

    +

    Definition at line 125 of file remmina_protocol_widget.c.

    diff --git a/public/struct_mp_run_info.html b/public/struct_mp_run_info.html index bedeef52b..4d64c058e 100644 --- a/public/struct_mp_run_info.html +++ b/public/struct_mp_run_info.html @@ -102,7 +102,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 1574 of file remmina_protocol_widget.c.

    +

    Definition at line 1600 of file remmina_protocol_widget.c.

    Field Documentation

    ◆ destroyed

    @@ -116,7 +116,7 @@ Data Fields
    -

    Definition at line 1578 of file remmina_protocol_widget.c.

    +

    Definition at line 1604 of file remmina_protocol_widget.c.

    @@ -132,7 +132,7 @@ Data Fields
    -

    Definition at line 1576 of file remmina_protocol_widget.c.

    +

    Definition at line 1602 of file remmina_protocol_widget.c.

    @@ -148,7 +148,7 @@ Data Fields
    -

    Definition at line 1575 of file remmina_protocol_widget.c.

    +

    Definition at line 1601 of file remmina_protocol_widget.c.

    @@ -164,7 +164,7 @@ Data Fields
    -

    Definition at line 1577 of file remmina_protocol_widget.c.

    +

    Definition at line 1603 of file remmina_protocol_widget.c.

    diff --git a/public/structremmina__protocol__widget__dialog__mt__data__t.html b/public/structremmina__protocol__widget__dialog__mt__data__t.html index 6d5e3e655..dda5a2244 100644 --- a/public/structremmina__protocol__widget__dialog__mt__data__t.html +++ b/public/structremmina__protocol__widget__dialog__mt__data__t.html @@ -118,7 +118,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 1482 of file remmina_protocol_widget.c.

    +

    Definition at line 1508 of file remmina_protocol_widget.c.

    Field Documentation

    ◆ called_from_subthread

    @@ -132,7 +132,7 @@ Data Fields
    -

    Definition at line 1492 of file remmina_protocol_widget.c.

    +

    Definition at line 1518 of file remmina_protocol_widget.c.

    @@ -148,7 +148,7 @@ Data Fields
    -

    Definition at line 1488 of file remmina_protocol_widget.c.

    +

    Definition at line 1514 of file remmina_protocol_widget.c.

    @@ -164,7 +164,7 @@ Data Fields
    -

    Definition at line 1487 of file remmina_protocol_widget.c.

    +

    Definition at line 1513 of file remmina_protocol_widget.c.

    @@ -180,7 +180,7 @@ Data Fields
    -

    Definition at line 1486 of file remmina_protocol_widget.c.

    +

    Definition at line 1512 of file remmina_protocol_widget.c.

    @@ -196,7 +196,7 @@ Data Fields
    -

    Definition at line 1490 of file remmina_protocol_widget.c.

    +

    Definition at line 1516 of file remmina_protocol_widget.c.

    @@ -212,7 +212,7 @@ Data Fields
    -

    Definition at line 1484 of file remmina_protocol_widget.c.

    +

    Definition at line 1510 of file remmina_protocol_widget.c.

    @@ -228,7 +228,7 @@ Data Fields
    -

    Definition at line 1491 of file remmina_protocol_widget.c.

    +

    Definition at line 1517 of file remmina_protocol_widget.c.

    @@ -244,7 +244,7 @@ Data Fields
    -

    Definition at line 1495 of file remmina_protocol_widget.c.

    +

    Definition at line 1521 of file remmina_protocol_widget.c.

    @@ -260,7 +260,7 @@ Data Fields
    -

    Definition at line 1494 of file remmina_protocol_widget.c.

    +

    Definition at line 1520 of file remmina_protocol_widget.c.

    @@ -276,7 +276,7 @@ Data Fields
    -

    Definition at line 1497 of file remmina_protocol_widget.c.

    +

    Definition at line 1523 of file remmina_protocol_widget.c.

    @@ -292,7 +292,7 @@ Data Fields
    -

    Definition at line 1489 of file remmina_protocol_widget.c.

    +

    Definition at line 1515 of file remmina_protocol_widget.c.

    @@ -308,7 +308,7 @@ Data Fields
    -

    Definition at line 1485 of file remmina_protocol_widget.c.

    +

    Definition at line 1511 of file remmina_protocol_widget.c.

    -- cgit v1.2.3