From 425b0af92fd847186f7ab506007b88a8779f1238 Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Fri, 8 Sep 2023 12:44:28 +0000 Subject: Automatic doc build by remmina-ci --- public/functions_e.html | 3 + public/functions_vars_e.html | 3 + public/navtreedata.js | 4 +- public/navtreeindex11.js | 2 +- public/navtreeindex16.js | 44 ++-- public/navtreeindex17.js | 4 +- public/navtreeindex18.js | 1 + public/rdp__channels_8c_source.html | 16 +- public/rdp__cliprdr_8c_source.html | 34 +-- public/rdp__cliprdr_8h_source.html | 4 +- public/rdp__event_8c.html | 78 +++---- public/rdp__event_8c_source.html | 198 ++++++++--------- public/rdp__event_8h.html | 20 +- public/rdp__event_8h_source.html | 22 +- public/rdp__graphics_8c_source.html | 34 +-- public/rdp__monitor_8c_source.html | 4 +- public/rdp__monitor_8h_source.html | 2 +- public/rdp__plugin_8c.html | 158 +++++++------- public/rdp__plugin_8c_source.html | 220 +++++++++---------- public/rdp__plugin_8h.html | 12 +- public/rdp__plugin_8h_source.html | 239 +++++++++++---------- public/search/all_14.js | 2 +- public/search/all_5.js | 1 + public/search/variables_13.js | 2 +- public/search/variables_5.js | 1 + public/structregion.html | 10 +- public/structremmina__plugin__rdp__event.html | 52 +++-- public/structremmina__plugin__rdp__event.js | 1 + .../structremmina__plugin__rdp__keymap__entry.html | 6 +- public/structremmina__plugin__rdp__ui__object.html | 54 ++--- public/structrf__context.html | 104 ++++----- 31 files changed, 682 insertions(+), 653 deletions(-) diff --git a/public/functions_e.html b/public/functions_e.html index c41042a65..f9dc96304 100644 --- a/public/functions_e.html +++ b/public/functions_e.html @@ -256,6 +256,9 @@ $(document).ready(function(){initNavTree('functions_e.html','');});
  • extended : remmina_plugin_rdp_event
  • +
  • extended1 +: remmina_plugin_rdp_event +
  • extra_args : _PyGClosure
  • diff --git a/public/functions_vars_e.html b/public/functions_vars_e.html index 558a94bca..faa41e6e4 100644 --- a/public/functions_vars_e.html +++ b/public/functions_vars_e.html @@ -256,6 +256,9 @@ $(document).ready(function(){initNavTree('functions_vars_e.html','');});
  • extended : remmina_plugin_rdp_event
  • +
  • extended1 +: remmina_plugin_rdp_event +
  • extra_args : _PyGClosure
  • diff --git a/public/navtreedata.js b/public/navtreedata.js index 35596ac91..31ae4ec5a 100644 --- a/public/navtreedata.js +++ b/public/navtreedata.js @@ -104,8 +104,8 @@ var NAVTREEINDEX = "struct___remmina_pref.html#a7c139ee405d50330b1d9bfb646c0258c", "struct___remmina_s_f_t_p.html#a7dab48a7603f1dd6671a8dd1efe1958e", "structitem.html#a1bfbfa35087440a4b217fd9fa4466bdb", -"structrf__context.html#a9d28c775fe1ee90ad48941d753564a76", -"www__plugin_8c.html#a282f3f57584e24a15a8a5d5cf5aa8d72" +"structrf__context.html#a96c4689f6bc062482536038cb3b24e78", +"www__plugin_8c.html#a1a152b9760d6b4808393569b0409f8b8" ]; var SYNCONMSG = 'click to disable panel synchronisation'; diff --git a/public/navtreeindex11.js b/public/navtreeindex11.js index d1fe2e449..65d7b204b 100644 --- a/public/navtreeindex11.js +++ b/public/navtreeindex11.js @@ -100,8 +100,8 @@ var NAVTREEINDEX11 = "spice__plugin__usb_8c_source.html":[61,0,156], "src_2pygobject_8h.html":[61,0,16], "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#a18eca93aad557c40e8a75b655961b159a6ca21e5d81f80ca35b556f92f5ca35cc":[61,0,16,12,0], "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], diff --git a/public/navtreeindex16.js b/public/navtreeindex16.js index d65849b0f..6787e3e00 100644 --- a/public/navtreeindex16.js +++ b/public/navtreeindex16.js @@ -119,31 +119,32 @@ var NAVTREEINDEX16 = "structremmina__masterthread__exec__data.html#af4aac360c396741c659474158d7c0e87":[60,0,104,22], "structremmina__plugin__rdp__event.html":[60,0,105], "structremmina__plugin__rdp__event.html#a008a5e7caebab7b0a5d4f6a48b4c63f6":[60,0,105,0], -"structremmina__plugin__rdp__event.html#a02c2d40efeac883dcc6294be9782e082":[60,0,105,17], -"structremmina__plugin__rdp__event.html#a0ff77bb8ed355ac55a7dc4ab28a02649":[60,0,105,10], -"structremmina__plugin__rdp__event.html#a18cb50afaa8b9df1759f87899892fdb6":[60,0,105,12], -"structremmina__plugin__rdp__event.html#a2822d7acc35ca8ecc5afb4c44b1ac117":[60,0,105,13], -"structremmina__plugin__rdp__event.html#a2f6b6cb00f2511b7849654b026cfd105":[60,0,105,26], +"structremmina__plugin__rdp__event.html#a02c2d40efeac883dcc6294be9782e082":[60,0,105,18], +"structremmina__plugin__rdp__event.html#a0ff77bb8ed355ac55a7dc4ab28a02649":[60,0,105,11], +"structremmina__plugin__rdp__event.html#a18cb50afaa8b9df1759f87899892fdb6":[60,0,105,13], +"structremmina__plugin__rdp__event.html#a2822d7acc35ca8ecc5afb4c44b1ac117":[60,0,105,14], +"structremmina__plugin__rdp__event.html#a2f6b6cb00f2511b7849654b026cfd105":[60,0,105,27], "structremmina__plugin__rdp__event.html#a30115ccc01062368d9b1189a0f378f57":[60,0,105,6], -"structremmina__plugin__rdp__event.html#a699aeed24ff4a648e00aced7a1e3adf6":[60,0,105,14], -"structremmina__plugin__rdp__event.html#a6c91276b122d70b8e723e046f6dbd151":[60,0,105,11], +"structremmina__plugin__rdp__event.html#a699aeed24ff4a648e00aced7a1e3adf6":[60,0,105,15], +"structremmina__plugin__rdp__event.html#a6c91276b122d70b8e723e046f6dbd151":[60,0,105,12], "structremmina__plugin__rdp__event.html#a72cd3fa2cc46eb03de7f68d63b2646b2":[60,0,105,2], -"structremmina__plugin__rdp__event.html#a7a1c9ce96d50f8902f7504bbfd0a057b":[60,0,105,23], -"structremmina__plugin__rdp__event.html#a7cee906e36975da3aadf6874da5da49c":[60,0,105,8], -"structremmina__plugin__rdp__event.html#a81b19d4696e8a38139182113d5d741ba":[60,0,105,20], -"structremmina__plugin__rdp__event.html#a84797e0cdf4484432740a8946325f126":[60,0,105,22], -"structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764":[60,0,105,21], -"structremmina__plugin__rdp__event.html#aab8e2356f6619d11ecc80b8b767ca815":[60,0,105,18], -"structremmina__plugin__rdp__event.html#ab1ee38a965bda260c81a55eedbd97114":[60,0,105,9], -"structremmina__plugin__rdp__event.html#ab834752f9089cbc4a8841fdc037aa094":[60,0,105,24], -"structremmina__plugin__rdp__event.html#ac8972b1def0a956b7c36534da0e56b3b":[60,0,105,25], +"structremmina__plugin__rdp__event.html#a7a1c9ce96d50f8902f7504bbfd0a057b":[60,0,105,24], +"structremmina__plugin__rdp__event.html#a7cee906e36975da3aadf6874da5da49c":[60,0,105,9], +"structremmina__plugin__rdp__event.html#a81b19d4696e8a38139182113d5d741ba":[60,0,105,21], +"structremmina__plugin__rdp__event.html#a84797e0cdf4484432740a8946325f126":[60,0,105,23], +"structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764":[60,0,105,22], +"structremmina__plugin__rdp__event.html#aab8e2356f6619d11ecc80b8b767ca815":[60,0,105,19], +"structremmina__plugin__rdp__event.html#ab1ee38a965bda260c81a55eedbd97114":[60,0,105,10], +"structremmina__plugin__rdp__event.html#ab834752f9089cbc4a8841fdc037aa094":[60,0,105,25], +"structremmina__plugin__rdp__event.html#ac8972b1def0a956b7c36534da0e56b3b":[60,0,105,26], +"structremmina__plugin__rdp__event.html#ac8c805908d492afeaeb6ef6ce6fad218":[60,0,105,8], "structremmina__plugin__rdp__event.html#acc5ea94958152ae483d269a28f34b0b0":[60,0,105,4], -"structremmina__plugin__rdp__event.html#ad3b01f14f235b582b54aa9a0057d5c1c":[60,0,105,16], +"structremmina__plugin__rdp__event.html#ad3b01f14f235b582b54aa9a0057d5c1c":[60,0,105,17], "structremmina__plugin__rdp__event.html#ad8c508c65e9f84c92f2f817eb7be2985":[60,0,105,5], -"structremmina__plugin__rdp__event.html#ada88729499d8df4337a81d1cd5bcd7bf":[60,0,105,15], +"structremmina__plugin__rdp__event.html#ada88729499d8df4337a81d1cd5bcd7bf":[60,0,105,16], "structremmina__plugin__rdp__event.html#ae1093ce4f4e4e4b632ca4704ecfa698e":[60,0,105,7], -"structremmina__plugin__rdp__event.html#af02b51a258600a3c4f6d57e868dc39cf":[60,0,105,27], -"structremmina__plugin__rdp__event.html#af62c17a8001e045d3f9e781a0a5089ef":[60,0,105,19], +"structremmina__plugin__rdp__event.html#af02b51a258600a3c4f6d57e868dc39cf":[60,0,105,28], +"structremmina__plugin__rdp__event.html#af62c17a8001e045d3f9e781a0a5089ef":[60,0,105,20], "structremmina__plugin__rdp__event.html#af6744820a897cbe91a79cf3e78b3e494":[60,0,105,1], "structremmina__plugin__rdp__event.html#af9cd4e060d42600c8a9089b04612a624":[60,0,105,3], "structremmina__plugin__rdp__keymap__entry.html":[60,0,106], @@ -248,6 +249,5 @@ var NAVTREEINDEX16 = "structrf__context.html#a9134f0b8a6352cc257e1e91e162efea3":[60,0,113,4], "structrf__context.html#a91f20005b39ad9e1073cf25bf6d7c2f2":[60,0,113,47], "structrf__context.html#a93dd55d1f081496959f1051d04cc3ba4":[60,0,113,31], -"structrf__context.html#a957e6f6867170470689210d55770342e":[60,0,113,12], -"structrf__context.html#a96c4689f6bc062482536038cb3b24e78":[60,0,113,37] +"structrf__context.html#a957e6f6867170470689210d55770342e":[60,0,113,12] }; diff --git a/public/navtreeindex17.js b/public/navtreeindex17.js index 870beebdf..d63914c62 100644 --- a/public/navtreeindex17.js +++ b/public/navtreeindex17.js @@ -1,5 +1,6 @@ var NAVTREEINDEX17 = { +"structrf__context.html#a96c4689f6bc062482536038cb3b24e78":[60,0,113,37], "structrf__context.html#a9d28c775fe1ee90ad48941d753564a76":[60,0,113,44], "structrf__context.html#aa04b5624216d612d134b7439658f8b17":[60,0,113,23], "structrf__context.html#aa0aafcfa61ad736204a06281153f0a5da0b7e911f34ade078b572b43780fc6982":[60,0,113,2], @@ -248,6 +249,5 @@ var NAVTREEINDEX17 = "www__config_8h_source.html":[61,0,168], "www__plugin_8c.html":[61,0,169], "www__plugin_8c.html#a05218b821edab542795439a87ad9d909":[61,0,169,5], -"www__plugin_8c.html#a18fa028449a5d5d455ce6cde7bfd2ef2":[61,0,169,4], -"www__plugin_8c.html#a1a152b9760d6b4808393569b0409f8b8":[61,0,169,18] +"www__plugin_8c.html#a18fa028449a5d5d455ce6cde7bfd2ef2":[61,0,169,4] }; diff --git a/public/navtreeindex18.js b/public/navtreeindex18.js index 916a1e976..6975add34 100644 --- a/public/navtreeindex18.js +++ b/public/navtreeindex18.js @@ -1,5 +1,6 @@ var NAVTREEINDEX18 = { +"www__plugin_8c.html#a1a152b9760d6b4808393569b0409f8b8":[61,0,169,18], "www__plugin_8c.html#a282f3f57584e24a15a8a5d5cf5aa8d72":[61,0,169,16], "www__plugin_8c.html#a298678121c7123265e772c0b060f5dcb":[61,0,169,20], "www__plugin_8c.html#a3874a40164919bc5389d166df691bfdb":[61,0,169,24], diff --git a/public/rdp__channels_8c_source.html b/public/rdp__channels_8c_source.html index 0973b7f07..e69689c75 100644 --- a/public/rdp__channels_8c_source.html +++ b/public/rdp__channels_8c_source.html @@ -86,24 +86,24 @@ $(document).ready(function(){initNavTree('rdp__channels_8c_source.html','');});
    rdp_channels.c
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2012-2012 Jean-Louis Dupond
    4  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    19  * Boston, MA 02110-1301, USA.
    20  *
    21  * In addition, as a special exception, the copyright holders give
    22  * permission to link the code of portions of this program with the
    23  * OpenSSL library under certain conditions as described in each
    24  * individual source file, and distribute linked combinations
    25  * including the two.
    26  * You must obey the GNU General Public License in all respects
    27  * for all of the code used other than OpenSSL. * If you modify
    28  * file(s) with this exception, you may extend this exception to your
    29  * version of the file(s), but you are not obligated to do so. * If you
    30  * do not wish to do so, delete this exception statement from your
    31  * version. * If you delete this exception statement from all source
    32  * files in the program, then also delete it here.
    33  *
    34  */
    35 
    36 #include "rdp_plugin.h"
    37 #include "rdp_cliprdr.h"
    38 #include "rdp_channels.h"
    39 #include "rdp_event.h"
    40 
    41 #include <freerdp/freerdp.h>
    42 #include <freerdp/channels/channels.h>
    43 #include <freerdp/client/cliprdr.h>
    44 #include <freerdp/gdi/gfx.h>
    45 
    46 void remmina_rdp_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
    47 {
    48  TRACE_CALL(__func__);
    49 
    50  rfContext* rfi = (rfContext*)context;
    51 
    52  if (g_strcmp0(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) {
    53  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    54  // xfc->rdpei = (RdpeiClientContext*) e->pInterface;
    55  }else if (g_strcmp0(e->name, TSMF_DVC_CHANNEL_NAME) == 0) {
    56  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    57  // xf_tsmf_init(xfc, (TsmfClientContext*) e->pInterface);
    58  }else if (g_strcmp0(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) {
    59  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SoftwareGdi)) {
    60  rfi->rdpgfxchan = TRUE;
    61  gdi_graphics_pipeline_init(rfi->context.gdi, (RdpgfxClientContext*) e->pInterface);
    62  }
    63  else
    64  g_print("Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
    65  }else if (g_strcmp0(e->name, RAIL_SVC_CHANNEL_NAME) == 0) {
    66  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    67  // xf_rail_init(xfc, (RailClientContext*) e->pInterface);
    68  }else if (g_strcmp0(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
    69  remmina_rdp_cliprdr_init( rfi, (CliprdrClientContext*)e->pInterface);
    70  }else if (g_strcmp0(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) {
    71  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    72  // xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface);
    73  }else if (g_strcmp0(e->name, DISP_DVC_CHANNEL_NAME) == 0) {
    74  // "disp" channel connected, save its context pointer
    75  rfi->dispcontext = (DispClientContext*)e->pInterface;
    76  // Notify rcw to unlock dynres capability
    78  // Send monitor layout message here to ask for resize of remote desktop now
    81  }
    82  }
    83  REMMINA_PLUGIN_DEBUG("Channel %s has been opened", e->name);
    84 }
    85 
    86 void remmina_rdp_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e)
    87 {
    88  TRACE_CALL(__func__);
    89  rfContext* rfi = (rfContext*)context;
    90 
    91  if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) {
    92  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SoftwareGdi))
    93  gdi_graphics_pipeline_uninit(rfi->context.gdi, (RdpgfxClientContext*) e->pInterface);
    94  }
    95  REMMINA_PLUGIN_DEBUG("Channel %s has been closed", e->name);
    96 
    97 }
    +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2012-2012 Jean-Louis Dupond
    4  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    19  * Boston, MA 02110-1301, USA.
    20  *
    21  * In addition, as a special exception, the copyright holders give
    22  * permission to link the code of portions of this program with the
    23  * OpenSSL library under certain conditions as described in each
    24  * individual source file, and distribute linked combinations
    25  * including the two.
    26  * You must obey the GNU General Public License in all respects
    27  * for all of the code used other than OpenSSL. * If you modify
    28  * file(s) with this exception, you may extend this exception to your
    29  * version of the file(s), but you are not obligated to do so. * If you
    30  * do not wish to do so, delete this exception statement from your
    31  * version. * If you delete this exception statement from all source
    32  * files in the program, then also delete it here.
    33  *
    34  */
    35 
    36 #include "rdp_plugin.h"
    37 #include "rdp_cliprdr.h"
    38 #include "rdp_channels.h"
    39 #include "rdp_event.h"
    40 
    41 #include <freerdp/freerdp.h>
    42 #include <freerdp/channels/channels.h>
    43 #include <freerdp/client/cliprdr.h>
    44 #include <freerdp/gdi/gfx.h>
    45 
    46 void remmina_rdp_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
    47 {
    48  TRACE_CALL(__func__);
    49 
    50  rfContext* rfi = (rfContext*)context;
    51 
    52  if (g_strcmp0(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) {
    53  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    54  // xfc->rdpei = (RdpeiClientContext*) e->pInterface;
    55  }else if (g_strcmp0(e->name, TSMF_DVC_CHANNEL_NAME) == 0) {
    56  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    57  // xf_tsmf_init(xfc, (TsmfClientContext*) e->pInterface);
    58  }else if (g_strcmp0(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) {
    59  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SoftwareGdi)) {
    60  rfi->rdpgfxchan = TRUE;
    61  gdi_graphics_pipeline_init(rfi->context.gdi, (RdpgfxClientContext*) e->pInterface);
    62  }
    63  else
    64  g_print("Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
    65  }else if (g_strcmp0(e->name, RAIL_SVC_CHANNEL_NAME) == 0) {
    66  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    67  // xf_rail_init(xfc, (RailClientContext*) e->pInterface);
    68  }else if (g_strcmp0(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
    69  remmina_rdp_cliprdr_init( rfi, (CliprdrClientContext*)e->pInterface);
    70  }else if (g_strcmp0(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) {
    71  g_print("Unimplemented: channel %s connected but we can’t use it\n", e->name);
    72  // xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface);
    73  }else if (g_strcmp0(e->name, DISP_DVC_CHANNEL_NAME) == 0) {
    74  // "disp" channel connected, save its context pointer
    75  rfi->dispcontext = (DispClientContext*)e->pInterface;
    76  // Notify rcw to unlock dynres capability
    78  // Send monitor layout message here to ask for resize of remote desktop now
    81  }
    82  }
    83  REMMINA_PLUGIN_DEBUG("Channel %s has been opened", e->name);
    84 }
    85 
    86 void remmina_rdp_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e)
    87 {
    88  TRACE_CALL(__func__);
    89  rfContext* rfi = (rfContext*)context;
    90 
    91  if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) {
    92  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SoftwareGdi))
    93  gdi_graphics_pipeline_uninit(rfi->context.gdi, (RdpgfxClientContext*) e->pInterface);
    94  }
    95  REMMINA_PLUGIN_DEBUG("Channel %s has been closed", e->name);
    96 
    97 }
    void remmina_rdp_cliprdr_init(rfContext *rfi, CliprdrClientContext *cliprdr)
    Definition: rdp_cliprdr.c:958
    -
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:341
    -
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:323
    +
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:342
    +
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:324
    void remmina_rdp_OnChannelConnectedEventHandler(void *context, ChannelConnectedEventArgs *e)
    Definition: rdp_channels.c:46
    void(* protocol_plugin_unlock_dynres)(RemminaProtocolWidget *gp)
    Definition: plugin.h:189
    static RemminaPluginService * remmina_plugin_service
    -
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:483
    -
    RemminaScaleMode scale
    Definition: rdp_plugin.h:330
    +
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:484
    +
    RemminaScaleMode scale
    Definition: rdp_plugin.h:331
    void remmina_rdp_OnChannelDisconnectedEventHandler(void *context, ChannelDisconnectedEventArgs *e)
    Definition: rdp_channels.c:86
    -
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:335
    +
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:336
    -
    rdpSettings * settings
    Definition: rdp_plugin.h:326
    +
    rdpSettings * settings
    Definition: rdp_plugin.h:327
    -
    rdpContext context
    Definition: rdp_plugin.h:320
    +
    rdpContext context
    Definition: rdp_plugin.h:321
    diff --git a/public/rdp__cliprdr_8c_source.html b/public/rdp__cliprdr_8c_source.html index a8b02577c..88e3351e3 100644 --- a/public/rdp__cliprdr_8c_source.html +++ b/public/rdp__cliprdr_8c_source.html @@ -87,9 +87,9 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
    Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2012-2012 Jean-Louis Dupond
    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 "rdp_plugin.h"
    38 #include "rdp_cliprdr.h"
    39 #include "rdp_event.h"
    40 
    41 #include <freerdp/freerdp.h>
    42 #include <freerdp/channels/channels.h>
    43 #include <freerdp/client/cliprdr.h>
    44 #include <sys/time.h>
    45 
    46 #define CLIPBOARD_TRANSFER_WAIT_TIME 6
    47 
    49 {
    50  TRACE_CALL(__func__);
    51  UINT32 rc;
    52  gchar *name = gdk_atom_name(atom);
    53  rc = 0;
    54  if (g_strcmp0("UTF8_STRING", name) == 0 || g_strcmp0("text/plain;charset=utf-8", name) == 0)
    55  rc = CF_UNICODETEXT;
    56  if (g_strcmp0("TEXT", name) == 0 || g_strcmp0("text/plain", name) == 0)
    57  rc = CF_TEXT;
    58  if (g_strcmp0("text/html", name) == 0)
    59  rc = CB_FORMAT_HTML;
    60  if (g_strcmp0("image/png", name) == 0)
    61  rc = CB_FORMAT_PNG;
    62  if (g_strcmp0("image/jpeg", name) == 0)
    63  rc = CB_FORMAT_JPEG;
    64  if (g_strcmp0("image/bmp", name) == 0)
    65  rc = CF_DIB;
    66  if (g_strcmp0("text/uri-list", name) == 0)
    67  rc = CB_FORMAT_TEXTURILIST;
    68  g_free(name);
    69  return rc;
    70 }
    71 
    72 /* Never used? */
    73 void remmina_rdp_cliprdr_get_target_types(UINT32 **formats, UINT16 *size, GdkAtom *types, int count)
    74 {
    75  TRACE_CALL(__func__);
    76  int i;
    77  *size = 1;
    78  *formats = (UINT32 *)malloc(sizeof(UINT32) * (count + 1));
    79 
    80  *formats[0] = 0;
    81  for (i = 0; i < count; i++) {
    82  UINT32 format = remmina_rdp_cliprdr_get_format_from_gdkatom(types[i]);
    83  if (format != 0) {
    84  (*formats)[*size] = format;
    85  (*size)++;
    86  }
    87  }
    88 
    89  *formats = realloc(*formats, sizeof(UINT32) * (*size));
    90 }
    91 
    92 static UINT8 *lf2crlf(UINT8 *data, int *size)
    93 {
    94  TRACE_CALL(__func__);
    95  UINT8 c;
    96  UINT8 *outbuf;
    97  UINT8 *out;
    98  UINT8 *in_end;
    99  UINT8 *in;
    100  int out_size;
    101 
    102  out_size = (*size) * 2 + 1;
    103  outbuf = (UINT8 *)malloc(out_size);
    104  out = outbuf;
    105  in = data;
    106  in_end = data + (*size);
    107 
    108  while (in < in_end) {
    109  c = *in++;
    110  if (c == '\n') {
    111  *out++ = '\r';
    112  *out++ = '\n';
    113  } else {
    114  *out++ = c;
    115  }
    116  }
    117 
    118  *out++ = 0;
    119  *size = out - outbuf;
    120 
    121  return outbuf;
    122 }
    123 
    124 static void crlf2lf(UINT8 *data, size_t *size)
    125 {
    126  TRACE_CALL(__func__);
    127  UINT8 c;
    128  UINT8 *out;
    129  UINT8 *in;
    130  UINT8 *in_end;
    131 
    132  out = data;
    133  in = data;
    134  in_end = data + (*size);
    135 
    136  while (in < in_end) {
    137  c = *in++;
    138  if (c != '\r')
    139  *out++ = c;
    140  }
    141 
    142  *size = out - data;
    143 }
    144 
    145 /* Never used? */
    146 int remmina_rdp_cliprdr_server_file_contents_request(CliprdrClientContext *context, CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest)
    147 {
    148  TRACE_CALL(__func__);
    149  return -1;
    150 }
    151 
    152 /* Never used? */
    153 int remmina_rdp_cliprdr_server_file_contents_response(CliprdrClientContext *context, CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse)
    154 {
    155  TRACE_CALL(__func__);
    156  return 1;
    157 }
    158 
    160 {
    161  TRACE_CALL(__func__);
    163  rfContext *rfi = GET_PLUGIN_DATA(gp);
    164  rfClipboard *clipboard;
    165  CLIPRDR_FORMAT_LIST *pFormatList;
    166  RemminaPluginRdpEvent rdp_event = { 0 };
    167 
    168  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    169  return;
    170 
    171  clipboard = &(rfi->clipboard);
    172 
    173  ui = g_new0(RemminaPluginRdpUiObject, 1);
    175  ui->clipboard.clipboard = clipboard;
    177  pFormatList = remmina_rdp_event_queue_ui_sync_retptr(gp, ui);
    178 
    180  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
    181  remmina_rdp_event_event_push(gp, &rdp_event);
    182 }
    183 
    185 {
    186  TRACE_CALL(__func__);
    187  CLIPRDR_CAPABILITIES capabilities;
    188  CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
    189 
    190  capabilities.cCapabilitiesSets = 1;
    191  capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet);
    192 
    193  generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
    194  generalCapabilitySet.capabilitySetLength = 12;
    195 
    196  generalCapabilitySet.version = CB_CAPS_VERSION_2;
    197  generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
    198 
    199  clipboard->context->ClientCapabilities(clipboard->context, &capabilities);
    200 }
    201 
    202 static UINT remmina_rdp_cliprdr_monitor_ready(CliprdrClientContext *context, const CLIPRDR_MONITOR_READY *monitorReady)
    203 {
    204  TRACE_CALL(__func__);
    205  rfClipboard *clipboard = (rfClipboard *)context->custom;
    207 
    209  gp = clipboard->rfi->protocol_widget;
    211 
    212  return CHANNEL_RC_OK;
    213 }
    214 
    215 static UINT remmina_rdp_cliprdr_server_capabilities(CliprdrClientContext *context, const CLIPRDR_CAPABILITIES *capabilities)
    216 {
    217  TRACE_CALL(__func__);
    218  return CHANNEL_RC_OK;
    219 }
    220 
    221 
    223 {
    224  TRACE_CALL(__func__);
    225  guint fmt;
    226 
    227  pthread_mutex_lock(&clipboard->srv_data_mutex);
    228  if (clipboard->srv_data != NULL) {
    229  fmt = clipboard->format;
    230  if (fmt == CB_FORMAT_PNG || fmt == CF_DIB || fmt == CF_DIBV5 || fmt == CB_FORMAT_JPEG) {
    231  g_object_unref(clipboard->srv_data);
    232  } else {
    233  free(clipboard->srv_data);
    234  }
    235  clipboard->srv_data = NULL;
    236  }
    237  pthread_mutex_unlock(&clipboard->srv_data_mutex);
    238 }
    239 
    240 
    241 static UINT remmina_rdp_cliprdr_server_format_list(CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST *formatList)
    242 {
    243  TRACE_CALL(__func__);
    244 
    245  /* Called when a user do a "Copy" on the server: we collect all formats
    246  * the server send us and then setup the local clipboard with the appropriate
    247  * targets to request server data */
    248 
    251  rfClipboard *clipboard;
    252  CLIPRDR_FORMAT *format;
    253  CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
    254  UINT rc;
    255 
    256  int has_dib_level = 0;
    257 
    258  int i;
    259 
    260  clipboard = (rfClipboard *)context->custom;
    261  gp = clipboard->rfi->protocol_widget;
    262 
    263  REMMINA_PLUGIN_DEBUG("gp=%p: Received a new ServerFormatList from server clipboard. Remmina version = %s",
    264  gp, VERSION);
    265 
    266  GtkTargetList *list = gtk_target_list_new(NULL, 0);
    267 
    268  if (clipboard->srv_clip_data_wait == SCDW_BUSY_WAIT) {
    269  REMMINA_PLUGIN_DEBUG("gp=%p: we already have a FormatDataRequest in progress to the server, aborting", gp);
    271  }
    272 
    274  clipboard->server_html_format_id = 0;
    275 
    276  REMMINA_PLUGIN_DEBUG("gp=%p: format list from the server:", gp);
    277  for (i = 0; i < formatList->numFormats; i++) {
    278  format = &formatList->formats[i];
    279  const char *serverFormatName = format->formatName;
    280  gchar *gtkFormatName = NULL;
    281  if (format->formatId == CF_UNICODETEXT) {
    282  serverFormatName = "CF_UNICODETEXT";
    283  gtkFormatName = "text/plain;charset=utf-8";
    284  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    285  gtk_target_list_add(list, atom, 0, CF_UNICODETEXT);
    286  /* Add also the older UTF8_STRING format for older applications */
    287  atom = gdk_atom_intern("UTF8_STRING", TRUE);
    288  gtk_target_list_add(list, atom, 0, CF_UNICODETEXT);
    289  } else if (format->formatId == CF_TEXT) {
    290  serverFormatName = "CF_TEXT";
    291  gtkFormatName = "text/plain";
    292  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    293  gtk_target_list_add(list, atom, 0, CF_TEXT);
    294  /* Add also the older TEXT format for older applications */
    295  atom = gdk_atom_intern("TEXT", TRUE);
    296  gtk_target_list_add(list, atom, 0, CF_TEXT);
    297  } else if (format->formatId == CF_DIB) {
    298  serverFormatName = "CF_DIB";
    299  if (has_dib_level < 1)
    300  has_dib_level = 1;
    301  } else if (format->formatId == CF_DIBV5) {
    302  serverFormatName = "CF_DIBV5";
    303  if (has_dib_level < 5)
    304  has_dib_level = 5;
    305  } else if (format->formatId == CB_FORMAT_JPEG) {
    306  serverFormatName = "CB_FORMAT_JPEG";
    307  gtkFormatName = "image/jpeg";
    308  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    309  gtk_target_list_add(list, atom, 0, CB_FORMAT_JPEG);
    310  } else if (format->formatId == CB_FORMAT_PNG) {
    311  serverFormatName = "CB_FORMAT_PNG";
    312  gtkFormatName = "image/png";
    313  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    314  gtk_target_list_add(list, atom, 0, CB_FORMAT_PNG);
    315  } else if (format->formatId == CB_FORMAT_HTML) {
    316  serverFormatName = "CB_FORMAT_HTML";
    317  gtkFormatName = "text/html";
    318  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    319  gtk_target_list_add(list, atom, 0, CB_FORMAT_HTML);
    320  } else if (format->formatId == CB_FORMAT_TEXTURILIST) {
    321  serverFormatName = "CB_FORMAT_TEXTURILIST";
    322  gtkFormatName = "text/uri-list";
    323  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    324  gtk_target_list_add(list, atom, 0, CB_FORMAT_TEXTURILIST);
    325  } else if (format->formatId == CF_LOCALE) {
    326  serverFormatName = "CF_LOCALE";
    327  } else if (format->formatId == CF_METAFILEPICT) {
    328  serverFormatName = "CF_METAFILEPICT";
    329  } else if (serverFormatName != NULL && strcmp(serverFormatName, "HTML Format") == 0) {
    330  gtkFormatName = "text/html";
    331  GdkAtom atom = gdk_atom_intern(gtkFormatName, TRUE);
    332  gtk_target_list_add(list, atom, 0, format->formatId);
    333  clipboard->server_html_format_id = format->formatId;
    334  }
    335  REMMINA_PLUGIN_DEBUG("the server has clipboard format %d: %s -> GTK %s", format->formatId, serverFormatName, gtkFormatName);
    336  }
    337 
    338  /* Keep only one DIB format, if present */
    339  if (has_dib_level) {
    340  GdkAtom atom = gdk_atom_intern("image/bmp", TRUE);
    341  if (has_dib_level == 5)
    342  gtk_target_list_add(list, atom, 0, CF_DIBV5);
    343  else
    344  gtk_target_list_add(list, atom, 0, CF_DIB);
    345  }
    346 
    347 
    348  REMMINA_PLUGIN_DEBUG("gp=%p: sending ClientFormatListResponse to server", gp);
    349  formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
    350  formatListResponse.msgFlags = CB_RESPONSE_OK; // Can be CB_RESPONSE_FAIL in case of error
    351  formatListResponse.dataLen = 0;
    352  rc = clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse);
    353  /* Schedule GTK event to tell GTK to change the local clipboard calling gtk_clipboard_set_with_owner
    354  * via REMMINA_RDP_UI_CLIPBOARD_SET_DATA
    355  * GTK will immediately fire an "owner-change" event, that we should ignore.
    356  * And if we are putting text on the clipboard, mutter or other clipboard
    357  * managers may try immediately request a clipboard transfer. */
    358 
    359  /* Ensure we have at least one target into list, or Gtk will not change owner
    360  when setting clipboard owner later.
    361  We put it directly in the clipboard cache (clipboard->srv_data),
    362  so remmina will never ask it to the server via ClientFormatDataRequest */
    363  gint n_targets;
    364  GtkTargetEntry *target_table = gtk_target_table_new_from_list(list, &n_targets);
    365  if (target_table)
    366  gtk_target_table_free(target_table, n_targets);
    367  if (n_targets == 0) {
    368  REMMINA_PLUGIN_DEBUG("gp=%p adding a dummy text target (empty text) for local clipboard, because we have no interesting targets from the server. Putting it in the local clipboard cache.");
    369  GdkAtom atom = gdk_atom_intern("text/plain;charset=utf-8", TRUE);
    370  gtk_target_list_add(list, atom, 0, CF_UNICODETEXT);
    371  pthread_mutex_lock(&clipboard->srv_data_mutex);
    372  clipboard->srv_data = malloc(1);
    373  ((char *)(clipboard->srv_data))[0] = 0;
    374  pthread_mutex_unlock(&clipboard->srv_data_mutex);
    375  clipboard->format = CF_UNICODETEXT;
    376  }
    377 
    378 
    379  ui = g_new0(RemminaPluginRdpUiObject, 1);
    381  ui->clipboard.clipboard = clipboard;
    383  ui->clipboard.targetlist = list;
    385 
    386  REMMINA_PLUGIN_DEBUG("gp=%p: processing of ServerFormatList ended, returning rc=%u to libfreerdp", gp, rc);
    387  return rc;
    388 }
    389 
    390 static UINT remmina_rdp_cliprdr_server_format_list_response(CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse)
    391 {
    392  TRACE_CALL(__func__);
    393  return CHANNEL_RC_OK;
    394 }
    395 
    396 static UINT remmina_rdp_cliprdr_server_format_data_request(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
    397 {
    398  TRACE_CALL(__func__);
    399 
    402  rfClipboard *clipboard;
    403 
    404  clipboard = (rfClipboard *)context->custom;
    405  gp = clipboard->rfi->protocol_widget;
    406 
    407  ui = g_new0(RemminaPluginRdpUiObject, 1);
    409  ui->clipboard.clipboard = clipboard;
    411  ui->clipboard.format = formatDataRequest->requestedFormatId;
    413 
    414  return CHANNEL_RC_OK;
    415 }
    416 
    417 int timeval_diff(struct timeval *start, struct timeval *end)
    418 {
    419  /* Returns the time elapsed from start to end, in ms */
    420  int64_t ms_end = (end->tv_sec * 1000) + (end->tv_usec / 1000);
    421  int64_t ms_start = (start->tv_sec * 1000) + (start->tv_usec / 1000);
    422 
    423  return (int)(ms_end - ms_start);
    424 }
    425 
    426 
    427 static UINT remmina_rdp_cliprdr_server_format_data_response(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse)
    428 {
    429  TRACE_CALL(__func__);
    430 
    431  const UINT8 *data;
    432  size_t size;
    433  rfContext *rfi;
    435  rfClipboard *clipboard;
    436  gpointer output = NULL;
    437  struct timeval now;
    438  int mstrans;
    439 
    440  clipboard = (rfClipboard *)context->custom;
    441  gp = clipboard->rfi->protocol_widget;
    442  rfi = GET_PLUGIN_DATA(gp);
    443 
    444  data = formatDataResponse->requestedFormatData;
    445  size = formatDataResponse->dataLen;
    446 
    447  REMMINA_PLUGIN_DEBUG("gp=%p server FormatDataResponse received: clipboard data arrived form server.", gp);
    448  gettimeofday(&now, NULL);
    450 
    451  /* Calculate stats */
    452  mstrans = timeval_diff(&(clipboard->clientformatdatarequest_tv), &now);
    453  REMMINA_PLUGIN_DEBUG("gp=%p %zu bytes transferred from server in %d ms. Speed is %d bytes/sec",
    454  gp, (size_t)size, mstrans, mstrans != 0 ? (int)((int64_t)size * 1000 / mstrans) : 0);
    455 
    456  if (size > 0) {
    457  switch (rfi->clipboard.format) {
    458  case CF_UNICODETEXT:
    459  {
    460  size = ConvertFromUnicode(CP_UTF8, 0, (WCHAR *)data, size / 2, (CHAR **)&output, 0, NULL, NULL);
    461  crlf2lf(output, &size);
    462  break;
    463  }
    464 
    465  case CF_TEXT:
    466  case CB_FORMAT_HTML:
    467  {
    468  output = (gpointer)calloc(1, size + 1);
    469  if (output) {
    470  memcpy(output, data, size);
    471  crlf2lf(output, &size);
    472  }
    473  break;
    474  }
    475 
    476  case CF_DIBV5:
    477  case CF_DIB:
    478  {
    479  wStream *s;
    480  UINT32 offset;
    481  GError *perr;
    482  BITMAPINFOHEADER *pbi;
    483  BITMAPV5HEADER *pbi5;
    484 
    485  pbi = (BITMAPINFOHEADER *)data;
    486 
    487  // offset calculation inspired by http://downloads.poolelan.com/MSDN/MSDNLibrary6/Disk1/Samples/VC/OS/WindowsXP/GetImage/BitmapUtil.cpp
    488  offset = 14 + pbi->biSize;
    489  if (pbi->biClrUsed != 0)
    490  offset += sizeof(RGBQUAD) * pbi->biClrUsed;
    491  else if (pbi->biBitCount <= 8)
    492  offset += sizeof(RGBQUAD) * (1 << pbi->biBitCount);
    493  if (pbi->biSize == sizeof(BITMAPINFOHEADER)) {
    494  if (pbi->biCompression == 3) // BI_BITFIELDS is 3
    495  offset += 12;
    496  } else if (pbi->biSize >= sizeof(BITMAPV5HEADER)) {
    497  pbi5 = (BITMAPV5HEADER *)pbi;
    498  if (pbi5->bV5ProfileData <= offset)
    499  offset += pbi5->bV5ProfileSize;
    500  }
    501  s = Stream_New(NULL, 14 + size);
    502  Stream_Write_UINT8(s, 'B');
    503  Stream_Write_UINT8(s, 'M');
    504  Stream_Write_UINT32(s, 14 + size);
    505  Stream_Write_UINT32(s, 0);
    506  Stream_Write_UINT32(s, offset);
    507  Stream_Write(s, data, size);
    508 
    509  data = Stream_Buffer(s);
    510  size = Stream_Length(s);
    511 
    512  GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
    513  perr = NULL;
    514  if (!gdk_pixbuf_loader_write(loader, data, size, &perr)) {
    515  Stream_Free(s, TRUE);
    516  g_warning("[RDP] rdp_cliprdr: gdk_pixbuf_loader_write() returned error %s\n", perr->message);
    517  } else {
    518  if (!gdk_pixbuf_loader_close(loader, &perr)) {
    519  g_warning("[RDP] rdp_cliprdr: gdk_pixbuf_loader_close() returned error %s\n", perr->message);
    520  perr = NULL;
    521  }
    522  Stream_Free(s, TRUE);
    523  output = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
    524  }
    525  g_object_unref(loader);
    526  break;
    527  }
    528 
    529  case CB_FORMAT_PNG:
    530  case CB_FORMAT_JPEG:
    531  {
    532  GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
    533  gdk_pixbuf_loader_write(loader, data, size, NULL);
    534  output = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
    535  gdk_pixbuf_loader_close(loader, NULL);
    536  g_object_unref(loader);
    537  break;
    538  }
    539  default:
    540  {
    541  if (rfi->clipboard.format == clipboard->server_html_format_id) {
    542  /* Converting from Microsoft HTML Clipboard Format to pure text/html
    543  * https://docs.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format */
    544  int p = 0, lstart = 0;
    545  size_t osize;
    546  char c;
    547  /* Find the 1st starting with '<' */
    548  while(p < size && (c = data[p]) != 0) {
    549  if (c == '<' && p == lstart) break;
    550  if (c == '\n') lstart = p + 1;
    551  p++;
    552  }
    553  if (p < size) {
    554  osize = size - lstart;
    555  output = (gpointer)calloc(1, osize + 1);
    556  if (output) {
    557  memcpy(output, data + lstart, osize);
    558  ((char *)output)[osize] = 0;
    559  }
    560  }
    561  }
    562  }
    563  }
    564  }
    565 
    566  pthread_mutex_lock(&clipboard->srv_data_mutex);
    567  clipboard->srv_data = output;
    568  pthread_mutex_unlock(&clipboard->srv_data_mutex);
    569 
    570  if (output != NULL)
    571  REMMINA_PLUGIN_DEBUG("gp=%p: clipboard local cache data has been loaded", gp);
    572  else
    573  REMMINA_PLUGIN_DEBUG("gp=%p: data from server is not valid (size=%zu format=%d), cannot load into cache", gp, size, rfi->clipboard.format);
    574 
    575 
    576  REMMINA_PLUGIN_DEBUG("gp=%p: signalling main GTK thread that we have some clipboard data.", gp);
    577 
    578  pthread_mutex_lock(&clipboard->transfer_clip_mutex);
    579  pthread_cond_signal(&clipboard->transfer_clip_cond);
    580  if (clipboard->srv_clip_data_wait == SCDW_BUSY_WAIT) {
    581  REMMINA_PLUGIN_DEBUG("gp=%p: clipboard transfer from server completed.", gp);
    582  } else {
    583  // Clipboard data arrived from server when we are not busy waiting on main loop
    584  // Unfortunately, we must discard it
    585  REMMINA_PLUGIN_DEBUG("gp=%p: clipboard transfer from server completed, but no local application is requesting it. Data is on local cache now, try to paste later.", gp);
    586  }
    587  clipboard->srv_clip_data_wait = SCDW_NONE;
    588  pthread_mutex_unlock(&clipboard->transfer_clip_mutex);
    589 
    590  return CHANNEL_RC_OK;
    591 }
    592 
    593 
    594 void remmina_rdp_cliprdr_request_data(GtkClipboard *gtkClipboard, GtkSelectionData *selection_data, guint info, RemminaProtocolWidget *gp)
    595 {
    596  TRACE_CALL(__func__);
    597 
    598  /* Called by GTK when someone presses "Paste" on the client side.
    599  * We ask to the server the data we need */
    600 
    601  CLIPRDR_FORMAT_DATA_REQUEST *pFormatDataRequest;
    602  rfClipboard *clipboard;
    603  rfContext *rfi = GET_PLUGIN_DATA(gp);
    604  RemminaPluginRdpEvent rdp_event = { 0 };
    605  struct timespec to;
    606  struct timeval tv;
    607  int rc;
    608  time_t tlimit, tlimit1s, tnow, tstart;
    609 
    610  REMMINA_PLUGIN_DEBUG("gp=%p: A local application has requested remote clipboard data for remote format id %d", gp, info);
    611 
    612  clipboard = &(rfi->clipboard);
    613  if (clipboard->srv_clip_data_wait != SCDW_NONE) {
    614  g_message("[RDP] Cannot paste now, I’m already transferring clipboard data from server. Try again later\n");
    615  return;
    616  }
    617 
    618  if (clipboard->format != info || clipboard->srv_data == NULL) {
    619  /* We do not have a local cached clipoard, so we have to start a remote request */
    621 
    622  clipboard->format = info;
    623 
    624  pthread_mutex_lock(&clipboard->transfer_clip_mutex);
    625 
    626  pFormatDataRequest = (CLIPRDR_FORMAT_DATA_REQUEST *)malloc(sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
    627  ZeroMemory(pFormatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
    628  pFormatDataRequest->requestedFormatId = clipboard->format;
    629 
    630  clipboard->srv_clip_data_wait = SCDW_BUSY_WAIT; // Annotate that we are waiting for ServerFormatDataResponse
    631 
    632  REMMINA_PLUGIN_DEBUG("gp=%p Requesting clipboard data with format %d from the server via ServerFormatDataRequest", gp, clipboard->format);
    634  rdp_event.clipboard_formatdatarequest.pFormatDataRequest = pFormatDataRequest;
    635  remmina_rdp_event_event_push(gp, &rdp_event);
    636 
    637  /* Busy wait clipboard data for CLIPBOARD_TRANSFER_WAIT_TIME seconds.
    638  * In the meanwhile allow GTK event loop to proceed */
    639 
    640  tstart = time(NULL);
    641  tlimit = tstart + CLIPBOARD_TRANSFER_WAIT_TIME;
    642  rc = 100000;
    643  tlimit1s = tstart + 1;
    644  while ((tnow = time(NULL)) < tlimit && rc != 0 && clipboard->srv_clip_data_wait == SCDW_BUSY_WAIT) {
    645 
    646  if (tnow >= tlimit1s) {
    647  REMMINA_PLUGIN_DEBUG("gp=%p, clipboard data is still not here after %u seconds", gp, (unsigned)(tnow - tstart));
    648  tlimit1s = time(NULL) + 1;
    649  }
    650 
    651  gettimeofday(&tv, NULL);
    652  to.tv_sec = tv.tv_sec;
    653  to.tv_nsec = tv.tv_usec * 1000 + 5000000; // wait for data for 5ms
    654  if (to.tv_nsec >= 1000000000) {
    655  to.tv_nsec -= 1000000000;
    656  to.tv_sec++;
    657  }
    658  rc = pthread_cond_timedwait(&clipboard->transfer_clip_cond, &clipboard->transfer_clip_mutex, &to);
    659  if (rc == 0)
    660  break;
    661 
    662  gtk_main_iteration_do(FALSE);
    663  }
    664 
    665  if (rc != 0) {
    666  /* Timeout, just log it and hope that data will arrive later */
    667  if (clipboard->srv_clip_data_wait == SCDW_ABORTING) {
    668  g_warning("[RDP] gp=%p Clipboard data wait aborted.",gp);
    669  } else {
    670  if (rc == ETIMEDOUT)
    671  g_warning("[RDP] gp=%p Clipboard data from the server is not available in %d seconds. No data will be available to user.",
    672  gp, CLIPBOARD_TRANSFER_WAIT_TIME);
    673  else
    674  g_warning("[RDP] gp=%p internal error: pthread_cond_timedwait() returned %d\n", gp, rc);
    675  }
    676  }
    677  pthread_mutex_unlock(&clipboard->transfer_clip_mutex);
    678 
    679  }
    680 
    681  pthread_mutex_lock(&clipboard->srv_data_mutex);
    682  if (clipboard->srv_data != NULL) {
    683  REMMINA_PLUGIN_DEBUG("gp=%p pasting data to local application", gp);
    684  /* We have data in cache, just paste it */
    685  if (info == CB_FORMAT_PNG || info == CF_DIB || info == CF_DIBV5 || info == CB_FORMAT_JPEG) {
    686  gtk_selection_data_set_pixbuf(selection_data, clipboard->srv_data);
    687  } else if (info == CB_FORMAT_HTML || info == clipboard->server_html_format_id) {
    688  REMMINA_PLUGIN_DEBUG("gp=%p returning %zu bytes of HTML in clipboard to requesting application", gp, strlen(clipboard->srv_data));
    689  GdkAtom atom = gdk_atom_intern("text/html", TRUE);
    690  gtk_selection_data_set(selection_data, atom, 8, clipboard->srv_data, strlen(clipboard->srv_data));
    691  } else {
    692  REMMINA_PLUGIN_DEBUG("gp=%p returning %zu bytes of text in clipboard to requesting application", gp, strlen(clipboard->srv_data));
    693  gtk_selection_data_set_text(selection_data, clipboard->srv_data, -1);
    694  }
    695  clipboard->srv_clip_data_wait = SCDW_NONE;
    696  } else {
    697  REMMINA_PLUGIN_DEBUG("gp=%p cannot paste data to local application because ->srv_data is NULL", gp);
    698  }
    699  pthread_mutex_unlock(&clipboard->srv_data_mutex);
    700 
    701 }
    702 
    703 void remmina_rdp_cliprdr_empty_clipboard(GtkClipboard *gtkClipboard, rfClipboard *clipboard)
    704 {
    705  TRACE_CALL(__func__);
    706  /* No need to do anything here */
    707 }
    708 
    710 {
    711  TRACE_CALL(__func__);
    712 
    713  GtkClipboard *gtkClipboard;
    714  rfContext *rfi = GET_PLUGIN_DATA(gp);
    715  GdkAtom *targets;
    716  gboolean result = 0;
    717  gint loccount, srvcount;
    718  gint formatId, i;
    719  CLIPRDR_FORMAT *formats;
    720  struct retp_t {
    721  CLIPRDR_FORMAT_LIST pFormatList;
    722  CLIPRDR_FORMAT formats[];
    723  } *retp;
    724 
    725  formats = NULL;
    726  retp = NULL;
    727  loccount = 0;
    728 
    729  gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    730  if (gtkClipboard)
    731  result = gtk_clipboard_wait_for_targets(gtkClipboard, &targets, &loccount);
    732  REMMINA_PLUGIN_DEBUG("gp=%p sending to server the following local clipboard content formats", gp);
    733  if (result && loccount > 0) {
    734  formats = (CLIPRDR_FORMAT *)malloc(loccount * sizeof(CLIPRDR_FORMAT));
    735  srvcount = 0;
    736  for (i = 0; i < loccount; i++) {
    737  formatId = remmina_rdp_cliprdr_get_format_from_gdkatom(targets[i]);
    738  if (formatId != 0) {
    739  gchar *name = gdk_atom_name(targets[i]);
    740  REMMINA_PLUGIN_DEBUG(" local clipboard format %s will be sent to remote as %d", name, formatId);
    741  g_free(name);
    742  formats[srvcount].formatId = formatId;
    743  formats[srvcount].formatName = NULL;
    744  srvcount++;
    745  }
    746  }
    747  if (srvcount > 0) {
    748  retp = (struct retp_t *)malloc(sizeof(struct retp_t) + sizeof(CLIPRDR_FORMAT) * srvcount);
    749  retp->pFormatList.formats = retp->formats;
    750  retp->pFormatList.numFormats = srvcount;
    751  memcpy(retp->formats, formats, sizeof(CLIPRDR_FORMAT) * srvcount);
    752  } else {
    753  retp = (struct retp_t *)malloc(sizeof(struct retp_t));
    754  retp->pFormatList.formats = NULL;
    755  retp->pFormatList.numFormats = 0;
    756  }
    757  free(formats);
    758  } else {
    759  retp = (struct retp_t *)malloc(sizeof(struct retp_t) + sizeof(CLIPRDR_FORMAT));
    760  retp->pFormatList.formats = NULL;
    761  retp->pFormatList.numFormats = 0;
    762  }
    763 
    764  if (result)
    765  g_free(targets);
    766 
    767  retp->pFormatList.msgType = CB_FORMAT_LIST;
    768  retp->pFormatList.msgFlags = 0;
    769 
    770  return (CLIPRDR_FORMAT_LIST *)retp;
    771 }
    772 
    774 {
    775  TRACE_CALL(__func__);
    777 }
    778 
    780 {
    781  TRACE_CALL(__func__);
    782  GtkClipboard *gtkClipboard;
    783  UINT8 *inbuf = NULL;
    784  UINT8 *outbuf = NULL;
    785  GdkPixbuf *image = NULL;
    786  int size = 0;
    787  rfContext *rfi = GET_PLUGIN_DATA(gp);
    788  RemminaPluginRdpEvent rdp_event = { 0 };
    789 
    790  gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    791  if (gtkClipboard) {
    792  switch (ui->clipboard.format) {
    793  case CF_TEXT:
    794  case CF_UNICODETEXT:
    795  case CB_FORMAT_HTML:
    796  {
    797  inbuf = (UINT8 *)gtk_clipboard_wait_for_text(gtkClipboard);
    798  break;
    799  }
    800 
    801  case CB_FORMAT_PNG:
    802  case CB_FORMAT_JPEG:
    803  case CF_DIB:
    804  case CF_DIBV5:
    805  {
    806  image = gtk_clipboard_wait_for_image(gtkClipboard);
    807  break;
    808  }
    809  }
    810  }
    811 
    812  /* No data received, send nothing */
    813  if (inbuf != NULL || image != NULL) {
    814  switch (ui->clipboard.format) {
    815  case CF_TEXT:
    816  case CB_FORMAT_HTML:
    817  {
    818  size = strlen((char *)inbuf);
    819  outbuf = lf2crlf(inbuf, &size);
    820  break;
    821  }
    822  case CF_UNICODETEXT:
    823  {
    824  size = strlen((char *)inbuf);
    825  inbuf = lf2crlf(inbuf, &size);
    826  size = (ConvertToUnicode(CP_UTF8, 0, (CHAR *)inbuf, -1, (WCHAR **)&outbuf, 0)) * sizeof(WCHAR);
    827  g_free(inbuf);
    828  break;
    829  }
    830  case CB_FORMAT_PNG:
    831  {
    832  gchar *data;
    833  gsize buffersize;
    834  gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "png", NULL, NULL);
    835  outbuf = (UINT8 *)malloc(buffersize);
    836  memcpy(outbuf, data, buffersize);
    837  size = buffersize;
    838  g_object_unref(image);
    839  break;
    840  }
    841  case CB_FORMAT_JPEG:
    842  {
    843  gchar *data;
    844  gsize buffersize;
    845  gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "jpeg", NULL, NULL);
    846  outbuf = (UINT8 *)malloc(buffersize);
    847  memcpy(outbuf, data, buffersize);
    848  size = buffersize;
    849  g_object_unref(image);
    850  break;
    851  }
    852  case CF_DIB:
    853  case CF_DIBV5:
    854  {
    855  gchar *data;
    856  gsize buffersize;
    857  gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "bmp", NULL, NULL);
    858  size = buffersize - 14;
    859  outbuf = (UINT8 *)malloc(size);
    860  memcpy(outbuf, data + 14, size);
    861  g_object_unref(image);
    862  break;
    863  }
    864  }
    865  }
    866 
    868  rdp_event.clipboard_formatdataresponse.data = outbuf;
    869  rdp_event.clipboard_formatdataresponse.size = size;
    870  remmina_rdp_event_event_push(gp, &rdp_event);
    871 }
    872 
    874 {
    875  TRACE_CALL(__func__);
    876  GtkClipboard *gtkClipboard;
    877  gint n_targets;
    878  rfContext *rfi = GET_PLUGIN_DATA(gp);
    879 
    880  gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    881  if (gtkClipboard) {
    882  GtkTargetEntry *targets = gtk_target_table_new_from_list(ui->clipboard.targetlist, &n_targets);
    883  if (!targets) {
    884  /* If no targets exists, this is an internal error, because
    885  * remmina_rdp_cliprdr_server_format_list() must have produced
    886  * at least one target before calling REMMINA_RDP_UI_CLIPBOARD_SET_DATA */
    887  g_warning("[RDP] internal error: no targets to insert into the local clipboard");
    888  }
    889 
    890  REMMINA_PLUGIN_DEBUG("setting clipboard with owner to me: %p", gp);
    891  gtk_clipboard_set_with_owner(gtkClipboard, targets, n_targets,
    892  (GtkClipboardGetFunc)remmina_rdp_cliprdr_request_data,
    893  (GtkClipboardClearFunc)remmina_rdp_cliprdr_empty_clipboard, G_OBJECT(gp));
    894  gtk_target_table_free(targets, n_targets);
    895  }
    896 }
    897 
    899 {
    900  /* When closing a rdp connection, we should check if gp is a clipboard owner.
    901  * If it’s an owner, detach it from the clipboard */
    902  TRACE_CALL(__func__);
    903  rfContext *rfi = GET_PLUGIN_DATA(gp);
    904  GtkClipboard *gtkClipboard;
    905 
    906  if (!rfi || !rfi->drawing_area) return;
    907 
    908  gtkClipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    909  if (gtkClipboard && gtk_clipboard_get_owner(gtkClipboard) == (GObject *)gp)
    910  gtk_clipboard_clear(gtkClipboard);
    911 
    912 }
    913 
    915 {
    916  TRACE_CALL(__func__);
    917 
    918  switch (ui->clipboard.type) {
    921  break;
    922 
    925  break;
    926 
    929  break;
    930 
    931  }
    932 }
    933 
    935 {
    936  TRACE_CALL(__func__);
    937  // Future: initialize rfi->clipboard
    938 }
    940 {
    941  TRACE_CALL(__func__);
    942 
    944 
    945 }
    946 
    948 {
    949  TRACE_CALL(__func__);
    950  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
    951  REMMINA_PLUGIN_DEBUG("requesting clipboard data transfer from server to be ignored and busywait loop to exit");
    952  /* Allow clipboard transfer from server to terminate */
    953  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
    954  usleep(100000);
    955  }
    956 }
    957 
    958 void remmina_rdp_cliprdr_init(rfContext *rfi, CliprdrClientContext *cliprdr)
    959 {
    960  TRACE_CALL(__func__);
    961 
    962  rfClipboard *clipboard;
    963  clipboard = &(rfi->clipboard);
    964 
    965  rfi->clipboard.rfi = rfi;
    966  cliprdr->custom = (void *)clipboard;
    967 
    968  clipboard->context = cliprdr;
    969  pthread_mutex_init(&clipboard->transfer_clip_mutex, NULL);
    970  pthread_cond_init(&clipboard->transfer_clip_cond, NULL);
    971  clipboard->srv_clip_data_wait = SCDW_NONE;
    972 
    973  pthread_mutex_init(&clipboard->srv_data_mutex, NULL);
    974 
    975  cliprdr->MonitorReady = remmina_rdp_cliprdr_monitor_ready;
    976  cliprdr->ServerCapabilities = remmina_rdp_cliprdr_server_capabilities;
    977  cliprdr->ServerFormatList = remmina_rdp_cliprdr_server_format_list;
    978  cliprdr->ServerFormatListResponse = remmina_rdp_cliprdr_server_format_list_response;
    979  cliprdr->ServerFormatDataRequest = remmina_rdp_cliprdr_server_format_data_request;
    980  cliprdr->ServerFormatDataResponse = remmina_rdp_cliprdr_server_format_data_response;
    981 
    982 // cliprdr->ServerFileContentsRequest = remmina_rdp_cliprdr_server_file_contents_request;
    983 // cliprdr->ServerFileContentsResponse = remmina_rdp_cliprdr_server_file_contents_response;
    984 }
    CliprdrClientContext * context
    Definition: rdp_plugin.h:135
    - -
    gboolean is_reconnecting
    Definition: rdp_plugin.h:344
    - + +
    gboolean is_reconnecting
    Definition: rdp_plugin.h:345
    +
    static UINT remmina_rdp_cliprdr_server_format_list_response(CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse)
    Definition: rdp_cliprdr.c:390
    int remmina_rdp_cliprdr_server_file_contents_response(CliprdrClientContext *context, CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse)
    Definition: rdp_cliprdr.c:153
    void remmina_rdp_cliprdr_send_client_format_list(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:159
    @@ -100,16 +100,16 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
    pthread_mutex_t transfer_clip_mutex
    Definition: rdp_plugin.h:142
    void remmina_rdp_cliprdr_detach_owner(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:898
    - +
    int timeval_diff(struct timeval *start, struct timeval *end)
    Definition: rdp_cliprdr.c:417
    pthread_mutex_t srv_data_mutex
    Definition: rdp_plugin.h:146
    void remmina_rdp_clipboard_abort_client_format_data_request(rfContext *rfi)
    Definition: rdp_cliprdr.c:947
    -
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1475
    +
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1483
    static UINT remmina_rdp_cliprdr_server_format_data_request(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
    Definition: rdp_cliprdr.c:396
    - +
    static void crlf2lf(UINT8 *data, size_t *size)
    Definition: rdp_cliprdr.c:124
    void remmina_rdp_clipboard_init(rfContext *rfi)
    Definition: rdp_cliprdr.c:934
    -
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:323
    +
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:324
    rfContext * rfi
    Definition: rdp_plugin.h:134
    void remmina_rdp_cliprdr_request_data(GtkClipboard *gtkClipboard, GtkSelectionData *selection_data, guint info, RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:594
    @@ -117,30 +117,30 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
    struct remmina_plugin_rdp_event::@42::@47 clipboard_formatdataresponse
    void remmina_rdp_event_process_clipboard(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_cliprdr.c:914
    - +
    RemminaPluginRdpEventType type
    Definition: rdp_plugin.h:191
    - +
    void remmina_rdp_cliprdr_set_clipboard_data(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_cliprdr.c:873
    static UINT remmina_rdp_cliprdr_monitor_ready(CliprdrClientContext *context, const CLIPRDR_MONITOR_READY *monitorReady)
    Definition: rdp_cliprdr.c:202
    pthread_cond_t transfer_clip_cond
    Definition: rdp_plugin.h:143
    static void remmina_rdp_cliprdr_mt_get_format_list(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_cliprdr.c:773
    - -
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:355
    -
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1463
    + +
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:356
    +
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1471
    int remmina_rdp_cliprdr_server_file_contents_request(CliprdrClientContext *context, CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest)
    Definition: rdp_cliprdr.c:146
    static void remmina_rdp_cliprdr_send_client_capabilities(rfClipboard *clipboard)
    Definition: rdp_cliprdr.c:184
    -
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1457
    - +
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1465
    +
    struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
    void remmina_rdp_cliprdr_empty_clipboard(GtkClipboard *gtkClipboard, rfClipboard *clipboard)
    Definition: rdp_cliprdr.c:703
    CLIPRDR_FORMAT_LIST * remmina_rdp_cliprdr_get_client_format_list(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:709
    -
    rfClipboard clipboard
    Definition: rdp_plugin.h:386
    +
    rfClipboard clipboard
    Definition: rdp_plugin.h:387
    void remmina_rdp_cliprdr_cached_clipboard_free(rfClipboard *clipboard)
    Definition: rdp_cliprdr.c:222
    struct remmina_plugin_rdp_event::@42::@48 clipboard_formatdatarequest
    void remmina_rdp_clipboard_free(rfContext *rfi)
    Definition: rdp_cliprdr.c:939
    -
    gboolean connected
    Definition: rdp_plugin.h:343
    +
    gboolean connected
    Definition: rdp_plugin.h:344
    void remmina_rdp_cliprdr_get_target_types(UINT32 **formats, UINT16 *size, GdkAtom *types, int count)
    Definition: rdp_cliprdr.c:73
    static UINT remmina_rdp_cliprdr_server_capabilities(CliprdrClientContext *context, const CLIPRDR_CAPABILITIES *capabilities)
    Definition: rdp_cliprdr.c:215
    @@ -154,7 +154,7 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
    UINT32 remmina_rdp_cliprdr_get_format_from_gdkatom(GdkAtom atom)
    Definition: rdp_cliprdr.c:48
    struct timeval clientformatdatarequest_tv
    Definition: rdp_plugin.h:151
    enum rf_clipboard::@41 srv_clip_data_wait
    -
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:266
    +
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:267
    diff --git a/public/rdp__cliprdr_8h_source.html b/public/rdp__cliprdr_8h_source.html index 25fa8f2ff..ca9a17112 100644 --- a/public/rdp__cliprdr_8h_source.html +++ b/public/rdp__cliprdr_8h_source.html @@ -87,9 +87,9 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8h_source.html','');});
    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) 2012-2012 Jean-Louis Dupond
    5  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    6  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    7  *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    16  * GNU General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    21  * Boston, MA 02110-1301, USA.
    22  *
    23  * In addition, as a special exception, the copyright holders give
    24  * permission to link the code of portions of this program with the
    25  * OpenSSL library under certain conditions as described in each
    26  * individual source file, and distribute linked combinations
    27  * including the two.
    28  * You must obey the GNU General Public License in all respects
    29  * for all of the code used other than OpenSSL. * If you modify
    30  * file(s) with this exception, you may extend this exception to your
    31  * version of the file(s), but you are not obligated to do so. * If you
    32  * do not wish to do so, delete this exception statement from your
    33  * version. * If you delete this exception statement from all source
    34  * files in the program, then also delete it here.
    35  *
    36  */
    37 
    38 #pragma once
    39 
    40 
    41 #include <freerdp/freerdp.h>
    42 #include "rdp_plugin.h"
    43 
    46 void remmina_rdp_cliprdr_init(rfContext *rfi, CliprdrClientContext *cliprdr);
    CLIPRDR_FORMAT_LIST * remmina_rdp_cliprdr_get_client_format_list(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:709
    - +
    void remmina_rdp_clipboard_free(rfContext *rfi)
    Definition: rdp_cliprdr.c:939
    - +
    void remmina_rdp_event_process_clipboard(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_cliprdr.c:914
    void remmina_rdp_cliprdr_detach_owner(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:898
    void remmina_rdp_clipboard_abort_client_format_data_request(rfContext *rfi)
    Definition: rdp_cliprdr.c:947
    diff --git a/public/rdp__event_8c.html b/public/rdp__event_8c.html index a5be2650d..678413bf6 100644 --- a/public/rdp__event_8c.html +++ b/public/rdp__event_8c.html @@ -219,7 +219,7 @@ Functions
    -

    Definition at line 221 of file rdp_event.c.

    +

    Definition at line 222 of file rdp_event.c.

    @@ -257,7 +257,7 @@ Functions
    -

    Definition at line 1164 of file rdp_event.c.

    +

    Definition at line 1172 of file rdp_event.c.

    @@ -285,7 +285,7 @@ Functions
    -

    Definition at line 1095 of file rdp_event.c.

    +

    Definition at line 1103 of file rdp_event.c.

    @@ -323,7 +323,7 @@ Functions
    -

    Definition at line 1193 of file rdp_event.c.

    +

    Definition at line 1201 of file rdp_event.c.

    @@ -361,7 +361,7 @@ Functions
    -

    Definition at line 1269 of file rdp_event.c.

    +

    Definition at line 1277 of file rdp_event.c.

    @@ -389,7 +389,7 @@ Functions
    -

    Definition at line 392 of file rdp_event.c.

    +

    Definition at line 393 of file rdp_event.c.

    @@ -457,7 +457,7 @@ Functions
    -

    Definition at line 1224 of file rdp_event.c.

    +

    Definition at line 1232 of file rdp_event.c.

    @@ -487,7 +487,7 @@ Functions
    -

    Definition at line 1028 of file rdp_event.c.

    +

    Definition at line 1036 of file rdp_event.c.

    @@ -508,7 +508,7 @@ Functions

    Fixme: This comment needed for TS_SUPPRESS_OUTPUT_PDU But it works only when we stay in the same window mode, if we switch to fullscreen, for instance, the object refernce is lost, so we loose these events.

    -

    Definition at line 912 of file rdp_event.c.

    +

    Definition at line 920 of file rdp_event.c.

    @@ -546,7 +546,7 @@ Functions
    -

    Definition at line 732 of file rdp_event.c.

    +

    Definition at line 733 of file rdp_event.c.

    @@ -590,7 +590,7 @@ Functions
    -

    Definition at line 605 of file rdp_event.c.

    +

    Definition at line 606 of file rdp_event.c.

    @@ -626,7 +626,7 @@ Functions
    -

    Definition at line 873 of file rdp_event.c.

    +

    Definition at line 881 of file rdp_event.c.

    @@ -670,7 +670,7 @@ Functions
    -

    Definition at line 498 of file rdp_event.c.

    +

    Definition at line 499 of file rdp_event.c.

    @@ -714,7 +714,7 @@ Functions
    -

    Definition at line 343 of file rdp_event.c.

    +

    Definition at line 344 of file rdp_event.c.

    @@ -802,7 +802,7 @@ Functions
    -

    Definition at line 766 of file rdp_event.c.

    +

    Definition at line 767 of file rdp_event.c.

    @@ -866,7 +866,7 @@ Functions
    -

    Definition at line 579 of file rdp_event.c.

    +

    Definition at line 580 of file rdp_event.c.

    @@ -910,7 +910,7 @@ Functions
    -

    Definition at line 676 of file rdp_event.c.

    +

    Definition at line 677 of file rdp_event.c.

    @@ -968,7 +968,7 @@ Functions
    -

    Definition at line 1332 of file rdp_event.c.

    +

    Definition at line 1340 of file rdp_event.c.

    @@ -1006,7 +1006,7 @@ Functions
    -

    Definition at line 1345 of file rdp_event.c.

    +

    Definition at line 1353 of file rdp_event.c.

    @@ -1034,7 +1034,7 @@ Functions
    -

    Definition at line 1378 of file rdp_event.c.

    +

    Definition at line 1386 of file rdp_event.c.

    @@ -1072,7 +1072,7 @@ Functions
    -

    Definition at line 1409 of file rdp_event.c.

    +

    Definition at line 1417 of file rdp_event.c.

    @@ -1102,7 +1102,7 @@ Functions
    -

    Definition at line 1457 of file rdp_event.c.

    +

    Definition at line 1465 of file rdp_event.c.

    @@ -1132,7 +1132,7 @@ Functions
    -

    Definition at line 1463 of file rdp_event.c.

    +

    Definition at line 1471 of file rdp_event.c.

    @@ -1162,7 +1162,7 @@ Functions
    -

    Definition at line 1475 of file rdp_event.c.

    +

    Definition at line 1483 of file rdp_event.c.

    @@ -1200,7 +1200,7 @@ Functions
    -

    Definition at line 1185 of file rdp_event.c.

    +

    Definition at line 1193 of file rdp_event.c.

    @@ -1322,7 +1322,7 @@ Functions
    -

    Definition at line 539 of file rdp_event.c.

    +

    Definition at line 540 of file rdp_event.c.

    @@ -1378,7 +1378,7 @@ Functions
    -

    Definition at line 236 of file rdp_event.c.

    +

    Definition at line 237 of file rdp_event.c.

    @@ -1398,7 +1398,7 @@ Functions
    -

    Definition at line 483 of file rdp_event.c.

    +

    Definition at line 484 of file rdp_event.c.

    @@ -1442,7 +1442,7 @@ Functions
    -

    Definition at line 1231 of file rdp_event.c.

    +

    Definition at line 1239 of file rdp_event.c.

    @@ -1498,7 +1498,7 @@ Functions
    -

    Definition at line 517 of file rdp_event.c.

    +

    Definition at line 518 of file rdp_event.c.

    @@ -1518,7 +1518,7 @@ Functions
    -

    Definition at line 1312 of file rdp_event.c.

    +

    Definition at line 1320 of file rdp_event.c.

    @@ -1538,7 +1538,7 @@ Functions
    -

    Definition at line 1044 of file rdp_event.c.

    +

    Definition at line 1052 of file rdp_event.c.

    @@ -1586,7 +1586,7 @@ Functions
    -

    Definition at line 301 of file rdp_event.c.

    +

    Definition at line 302 of file rdp_event.c.

    @@ -1616,7 +1616,7 @@ Functions
    -

    Definition at line 281 of file rdp_event.c.

    +

    Definition at line 282 of file rdp_event.c.

    @@ -1636,7 +1636,7 @@ Functions
    -

    Definition at line 1118 of file rdp_event.c.

    +

    Definition at line 1126 of file rdp_event.c.

    @@ -1664,7 +1664,7 @@ Functions
    -

    Definition at line 312 of file rdp_event.c.

    +

    Definition at line 313 of file rdp_event.c.

    @@ -1684,7 +1684,7 @@ Functions
    -

    Definition at line 561 of file rdp_event.c.

    +

    Definition at line 562 of file rdp_event.c.

    @@ -1722,7 +1722,7 @@ Functions
    -

    Definition at line 1322 of file rdp_event.c.

    +

    Definition at line 1330 of file rdp_event.c.

    @@ -1760,7 +1760,7 @@ Functions
    -

    Definition at line 1306 of file rdp_event.c.

    +

    Definition at line 1314 of file rdp_event.c.

    diff --git a/public/rdp__event_8c_source.html b/public/rdp__event_8c_source.html index c7b27677e..b466bb6cf 100644 --- a/public/rdp__event_8c_source.html +++ b/public/rdp__event_8c_source.html @@ -86,137 +86,137 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
    rdp_event.c
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK Remote Desktop Client
    3  * Copyright (C) 2010 Jay Sorg
    4  * Copyright (C) 2010-2011 Vic Lee
    5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
    6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    7  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
    8  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
    9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version.
    14  *
    15  * This program is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    18  * GNU General Public License for more details.
    19  *
    20  * You should have received a copy of the GNU General Public License
    21  * along with this program; if not, write to the Free Software
    22  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    23  * Boston, MA 02110-1301, USA.
    24  *
    25  * In addition, as a special exception, the copyright holders give
    26  * permission to link the code of portions of this program with the
    27  * OpenSSL library under certain conditions as described in each
    28  * individual source file, and distribute linked combinations
    29  * including the two.
    30  * You must obey the GNU General Public License in all respects
    31  * for all of the code used other than OpenSSL. * If you modify
    32  * file(s) with this exception, you may extend this exception to your
    33  * version of the file(s), but you are not obligated to do so. * If you
    34  * do not wish to do so, delete this exception statement from your
    35  * version. * If you delete this exception statement from all source
    36  * files in the program, then also delete it here.
    37  *
    38  */
    39 
    40 #include "rdp_cliprdr.h"
    41 #include "rdp_event.h"
    42 #include "rdp_monitor.h"
    43 #include "rdp_settings.h"
    44 #include <gdk/gdkkeysyms.h>
    45 #ifdef GDK_WINDOWING_X11
    46 #include <cairo/cairo-xlib.h>
    47 #else
    48 #include <cairo/cairo.h>
    49 #endif
    50 #include <freerdp/locale/keyboard.h>
    51 
    53 {
    54  TRACE_CALL(__func__);
    55  rfContext *rfi = GET_PLUGIN_DATA(gp);
    56  rdpGdi *gdi;
    57 
    58  if (rfi == NULL)
    59  return false;
    60 
    62  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
    63 
    64  if (do_suppress) {
    65  gdi = ((rdpContext *)rfi)->gdi;
    66 
    67  REMMINA_PLUGIN_DEBUG("Map event received, disabling TS_SUPPRESS_OUTPUT_PDU ");
    68  gdi_send_suppress_output(gdi, FALSE);
    69  }
    70 
    71  return FALSE;
    72 }
    73 
    75 {
    76  TRACE_CALL(__func__);
    77  rfContext *rfi = GET_PLUGIN_DATA(gp);
    78  rdpGdi *gdi;
    79 
    80  if (rfi == NULL)
    81  return false;
    82 
    83  GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(gp));
    84  GdkWindow *window = gtk_widget_get_window(toplevel);
    85 
    86  if (gdk_window_get_fullscreen_mode(window) == GDK_FULLSCREEN_ON_ALL_MONITORS) {
    87  REMMINA_PLUGIN_DEBUG("Unmap event received, but cannot enable TS_SUPPRESS_OUTPUT_PDU when in fullscreen");
    88  return FALSE;
    89  }
    90 
    92  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
    93 
    94  if (do_suppress) {
    95  gdi = ((rdpContext *)rfi)->gdi;
    96 
    97  REMMINA_PLUGIN_DEBUG("Unmap event received, enabling TS_SUPPRESS_OUTPUT_PDU ");
    98  gdi_send_suppress_output(gdi, TRUE);
    99  }
    100 
    101  return FALSE;
    102 }
    103 
    104 static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    105 {
    106  TRACE_CALL(__func__);
    107 
    108  rfContext *rfi = GET_PLUGIN_DATA(gp);
    109  rdpInput *input;
    110  GdkModifierType state;
    111 
    112 #if GTK_CHECK_VERSION(3, 20, 0)
    113  GdkSeat *seat;
    114 #else
    115  GdkDeviceManager *manager;
    116 #endif
    117  GdkDevice *keyboard = NULL;
    118 
    119  const gchar *wname = gtk_widget_get_name(gtk_widget_get_toplevel(widget));
    120  REMMINA_PLUGIN_DEBUG("Top level name is: %s", wname);
    121 
    122  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    123  return FALSE;
    124 
    125  input = rfi->instance->input;
    126  UINT32 toggle_keys_state = 0;
    127 
    128 #if GTK_CHECK_VERSION(3, 20, 0)
    129  seat = gdk_display_get_default_seat(gdk_display_get_default());
    130  keyboard = gdk_seat_get_pointer(seat);
    131 #else
    132  manager = gdk_display_get_device_manager(gdk_display_get_default());
    133  keyboard = gdk_device_manager_get_client_pointer(manager);
    134 #endif
    135  gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state);
    136 
    137  if (state & GDK_LOCK_MASK)
    138  toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
    139  if (state & GDK_MOD2_MASK)
    140  toggle_keys_state |= KBD_SYNC_NUM_LOCK;
    141  if (state & GDK_MOD5_MASK)
    142  toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
    143 
    144  input->SynchronizeEvent(input, toggle_keys_state);
    145  input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
    146 
    147  return FALSE;
    148 }
    149 
    151 {
    152  TRACE_CALL(__func__);
    153  rfContext *rfi = GET_PLUGIN_DATA(gp);
    154  RemminaPluginRdpEvent *event;
    155 
    156  /* Called by the main GTK thread to send an event to the libfreerdp thread */
    157 
    158  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    159  return;
    160 
    161  if (rfi->event_queue) {
    162 #if GLIB_CHECK_VERSION(2,67,3)
    163  event = g_memdup2(e, sizeof(RemminaPluginRdpEvent));
    164 #else
    165  event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
    166 #endif
    167  g_async_queue_push(rfi->event_queue, event);
    168 
    169  if (write(rfi->event_pipe[1], "\0", 1)) {
    170  }
    171  }
    172 }
    173 
    175 {
    176  TRACE_CALL(__func__);
    177  rfContext *rfi = GET_PLUGIN_DATA(gp);
    178  RemminaPluginRdpEvent rdp_event = { 0 };
    179  int i;
    180 
    181  /* Send all release key events for previously pressed keys */
    182  for (i = 0; i < rfi->pressed_keys->len; i++) {
    183  rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
    184  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
    186  rdp_event.key_event.up == false) {
    187  rdp_event.key_event.up = true;
    188  remmina_rdp_event_event_push(gp, &rdp_event);
    189  }
    190  }
    191 
    192  g_array_set_size(rfi->pressed_keys, 0);
    193 }
    194 
    196 {
    197  TRACE_CALL(__func__);
    198  gint i;
    199  rfContext *rfi = GET_PLUGIN_DATA(gp);
    200  RemminaPluginRdpEvent rdp_event_2 = { 0 };
    201 
    203 
    204  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
    206  rdp_event.key_event.up) {
    207  /* Unregister the keycode only */
    208  for (i = 0; i < rfi->pressed_keys->len; i++) {
    209  rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
    210 
    211  if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code &&
    212  rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code &&
    213  rdp_event_2.key_event.extended == rdp_event.key_event.extended) {
    214  g_array_remove_index_fast(rfi->pressed_keys, i);
    215  break;
    216  }
    217  }
    218  }
    219 }
    220 
    222 {
    223  TRACE_CALL(__func__);
    224  rfContext *rfi = GET_PLUGIN_DATA(gp);
    225 
    226  if (!rdp_event.key_event.key_code)
    227  return;
    228 
    229  if (rdp_event.key_event.up)
    230  remmina_rdp_event_release_key(gp, rdp_event);
    231  else
    232  g_array_append_val(rfi->pressed_keys, rdp_event);
    233 }
    234 
    235 
    236 static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
    237 {
    238  TRACE_CALL(__func__);
    239  gint width, height;
    240  gint sx, sy, sw, sh;
    241  rfContext *rfi = GET_PLUGIN_DATA(gp);
    242 
    243  if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface)
    244  return;
    245 
    248 
    249  if ((width == 0) || (height == 0))
    250  return;
    251 
    252  if ((rfi->scale_width == width) && (rfi->scale_height == height)) {
    253  /* Same size, just copy the pixels */
    254  *x = MIN(MAX(0, *x), width - 1);
    255  *y = MIN(MAX(0, *y), height - 1);
    256  *w = MIN(width - *x, *w);
    257  *h = MIN(height - *y, *h);
    258  return;
    259  }
    260 
    261  /* We have to extend the scaled region one scaled pixel, to avoid gaps */
    262 
    263  sx = MIN(MAX(0, (*x) * rfi->scale_width / width
    264  - rfi->scale_width / width - 2), rfi->scale_width - 1);
    265 
    266  sy = MIN(MAX(0, (*y) * rfi->scale_height / height
    267  - rfi->scale_height / height - 2), rfi->scale_height - 1);
    268 
    269  sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
    270  + rfi->scale_width / width + 4);
    271 
    272  sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
    273  + rfi->scale_height / height + 4);
    274 
    275  *x = sx;
    276  *y = sy;
    277  *w = sw;
    278  *h = sh;
    279 }
    280 
    282 {
    283  TRACE_CALL(__func__);
    284  rfContext *rfi = GET_PLUGIN_DATA(gp);
    285  gint x, y, w, h, i;
    286 
    287  for (i = 0; i < ui->reg.ninvalid; i++) {
    288  x = ui->reg.ureg[i].x;
    289  y = ui->reg.ureg[i].y;
    290  w = ui->reg.ureg[i].w;
    291  h = ui->reg.ureg[i].h;
    292 
    294  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
    295 
    296  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
    297  }
    298  g_free(ui->reg.ureg);
    299 }
    300 
    301 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    302 {
    303  TRACE_CALL(__func__);
    304  rfContext *rfi = GET_PLUGIN_DATA(gp);
    305 
    307  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
    308 
    309  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
    310 }
    311 
    313 {
    314  TRACE_CALL(__func__);
    315  GtkAllocation a;
    316  gint rdwidth, rdheight;
    317  gint gpwidth, gpheight;
    318  rfContext *rfi = GET_PLUGIN_DATA(gp);
    319 
    320  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
    321  gpwidth = a.width;
    322  gpheight = a.height;
    323 
    325  if ((gpwidth > 1) && (gpheight > 1)) {
    328 
    329  rfi->scale_width = gpwidth;
    330  rfi->scale_height = gpheight;
    331 
    332  rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth;
    333  rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight;
    334  }
    335  } else {
    336  rfi->scale_width = 0;
    337  rfi->scale_height = 0;
    338  rfi->scale_x = 0;
    339  rfi->scale_y = 0;
    340  }
    341 }
    342 
    343 static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
    344 {
    345  TRACE_CALL(__func__);
    346  rfContext *rfi = GET_PLUGIN_DATA(gp);
    347  guint width, height;
    348  gchar *msg;
    349  cairo_text_extents_t extents;
    350 
    351  if (!rfi || !rfi->connected)
    352  return FALSE;
    353 
    354 
    355  if (rfi->is_reconnecting) {
    356  /* FreeRDP is reconnecting, just show a message to the user */
    357 
    358  width = gtk_widget_get_allocated_width(widget);
    359  height = gtk_widget_get_allocated_height(widget);
    360 
    361  /* Draw text */
    362  msg = g_strdup_printf(_("Reconnection attempt %d of %d…"),
    364 
    365  cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
    366  cairo_set_font_size(context, 24);
    367  cairo_set_source_rgb(context, 0.9, 0.9, 0.9);
    368  cairo_text_extents(context, msg, &extents);
    369  cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2);
    370  cairo_show_text(context, msg);
    371  g_free(msg);
    372  } else {
    373  /* Standard drawing: We copy the surface from RDP */
    374 
    375  if (!rfi->surface)
    376  return FALSE;
    377 
    379  cairo_scale(context, rfi->scale_x, rfi->scale_y);
    380 
    381  cairo_surface_flush(rfi->surface);
    382  cairo_set_source_surface(context, rfi->surface, 0, 0);
    383  cairo_surface_mark_dirty(rfi->surface);
    384 
    385  cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); // Ignore alpha channel from FreeRDP
    386  cairo_paint(context);
    387  }
    388 
    389  return TRUE;
    390 }
    391 
    393 {
    394  TRACE_CALL(__func__);
    395  rfContext *rfi = GET_PLUGIN_DATA(gp);
    396 
    397  RemminaPluginRdpEvent rdp_event = { 0 };
    398  GtkAllocation a;
    399  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
    400 
    401  RemminaFile *remminafile;
    402 
    403  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    404  return FALSE;
    405 
    407 
    409  return FALSE;
    410 
    412  gint gpwidth, gpheight, prevwidth, prevheight;
    413 
    414  gchar *monitorids = NULL;
    415  guint32 maxwidth = 0;
    416  guint32 maxheight = 0;
    417 
    418  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
    419 
    420  REMMINA_PLUGIN_DEBUG("Sending preconfigured monitor layout");
    421  if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) {
    422  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
    423  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
    424  gpwidth = a.width;
    425  gpheight = a.height;
    428 
    429  if ((gpwidth != prevwidth || gpheight != prevheight) && gpwidth >= 200 && gpheight >= 200) {
    430  if (rfi->rdpgfxchan) {
    431  /* Workaround for FreeRDP issue #5417 */
    432  if (gpwidth < AVC_MIN_DESKTOP_WIDTH)
    433  gpwidth = AVC_MIN_DESKTOP_WIDTH;
    434  if (gpheight < AVC_MIN_DESKTOP_HEIGHT)
    435  gpheight = AVC_MIN_DESKTOP_HEIGHT;
    436  }
    438  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    439  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    440  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
    441  const rdpMonitor *current = &base[i];
    442  REMMINA_PLUGIN_DEBUG("Sending display layout n° %d", i);
    443  rdp_event.monitor_layout.Flags = current->is_primary;
    444  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags);
    445  rdp_event.monitor_layout.Left = current->x;
    446  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left);
    447  rdp_event.monitor_layout.Top = current->y;
    448  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top);
    449  rdp_event.monitor_layout.width = current->width;
    450  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width);
    451  rdp_event.monitor_layout.height = current->height;
    452  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height);
    453  rdp_event.monitor_layout.physicalWidth = current->attributes.physicalWidth;
    454  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth);
    455  rdp_event.monitor_layout.physicalHeight = current->attributes.physicalHeight;
    456  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight);
    457  if (current->attributes.orientation)
    458  rdp_event.monitor_layout.desktopOrientation = current->attributes.orientation;
    459  else
    460  rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation;
    461  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation);
    462  rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor;
    463  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor);
    464  rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor;
    465  }
    466  remmina_rdp_event_event_push(gp, &rdp_event);
    467  } else {
    468  rdp_event.monitor_layout.width = gpwidth;
    469  rdp_event.monitor_layout.height = gpheight;
    470  rdp_event.monitor_layout.desktopOrientation = desktopOrientation;
    471  rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor;
    472  rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor;
    473  remmina_rdp_event_event_push(gp, &rdp_event);
    474  }
    475  }
    476  }
    477 
    478  g_free(monitorids);
    479 
    480  return FALSE;
    481 }
    482 
    484 {
    485  TRACE_CALL(__func__);
    486  rfContext *rfi = GET_PLUGIN_DATA(gp);
    487 
    488  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    489  return;
    491  g_source_remove(rfi->delayed_monitor_layout_handler);
    493  }
    495  rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp);
    496 }
    497 
    498 static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
    499 {
    500  TRACE_CALL(__func__);
    501  /* Called when gp changes its size or position */
    502 
    503  rfContext *rfi = GET_PLUGIN_DATA(gp);
    504 
    505  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    506  return FALSE;
    507 
    509 
    510  /* If the scaler is not active, schedule a delayed remote resolution change */
    512 
    513 
    514  return FALSE;
    515 }
    516 
    517 static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
    518 {
    519  TRACE_CALL(__func__);
    520  rfContext *rfi = GET_PLUGIN_DATA(gp);
    521 
    522  /*
    523  * Translate a position from local window coordinates (ix,iy) to
    524  * RDP coordinates and put result on (*ox,*uy)
    525  * */
    526 
    527  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    528  return;
    529 
    530  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
    531  *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
    532  *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
    533  } else {
    534  *ox = (UINT16)ix;
    535  *oy = (UINT16)iy;
    536  }
    537 }
    538 
    539 static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
    540 {
    541  TRACE_CALL(__func__);
    542  rfContext *rfi = GET_PLUGIN_DATA(gp);
    543 
    544  /*
    545  * Translate a position from RDP coordinates (ix,iy) to
    546  * local window coordinates and put result on (*ox,*uy)
    547  * */
    548 
    549  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    550  return;
    551 
    552  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
    555  } else {
    556  *ox = ix;
    557  *oy = iy;
    558  }
    559 }
    560 
    562  TRACE_CALL(__func__);
    563  RemminaPluginRdpEvent rdp_event = { 0 };
    564  RemminaFile *remminafile;
    565  rfContext *rfi = GET_PLUGIN_DATA(gp);
    566 
    568  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    569  return;
    570 
    572  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
    573  rdp_event.mouse_event.extended = FALSE;
    574  rdp_event.mouse_event.x = rfi->last_x;
    575  rdp_event.mouse_event.y = rfi->last_y;
    576  remmina_rdp_event_event_push(gp, &rdp_event);
    577 }
    578 
    579 static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
    580 {
    581  TRACE_CALL(__func__);
    582  RemminaPluginRdpEvent rdp_event = { 0 };
    583  RemminaFile *remminafile;
    584  rfContext *rfi = GET_PLUGIN_DATA(gp);
    585 
    587  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    588  return FALSE;
    589 
    591  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
    592  rdp_event.mouse_event.extended = FALSE;
    593 
    594  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    595  if (rfi != NULL){
    596  rfi->last_x = rdp_event.mouse_event.x;
    597  rfi->last_y = rdp_event.mouse_event.y;
    598  }
    599 
    600  remmina_rdp_event_event_push(gp, &rdp_event);
    601 
    602  return TRUE;
    603 }
    604 
    605 static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
    606 {
    607  TRACE_CALL(__func__);
    608  gint flag;
    609  gboolean extended = FALSE;
    610  RemminaPluginRdpEvent rdp_event = { 0 };
    611  gint primary, secondary;
    612 
    613  RemminaFile *remminafile;
    614 
    616  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    617  return FALSE;
    618 
    619  /* We bypass 2button-press and 3button-press events */
    620  if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
    621  return TRUE;
    622 
    623  flag = 0;
    624 
    625  if (remmina_plugin_service->file_get_int(remminafile, "left-handed", FALSE)) {
    626  primary = PTR_FLAGS_BUTTON2;
    627  secondary = PTR_FLAGS_BUTTON1;
    628  } else {
    629  primary = PTR_FLAGS_BUTTON1;
    630  secondary = PTR_FLAGS_BUTTON2;
    631  }
    632 
    633  switch (event->button) {
    634  case 1:
    635  flag |= primary;
    636  break;
    637  case 2:
    638  flag |= PTR_FLAGS_BUTTON3;
    639  break;
    640  case 3:
    641  flag |= secondary;
    642  break;
    643  case 8: /* back */
    644  case 97: /* Xming */
    645  extended = TRUE;
    646  flag |= PTR_XFLAGS_BUTTON1;
    647  break;
    648  case 9: /* forward */
    649  case 112: /* Xming */
    650  extended = TRUE;
    651  flag |= PTR_XFLAGS_BUTTON2;
    652  break;
    653  default:
    654  return FALSE;
    655  }
    656 
    657  if (event->type == GDK_BUTTON_PRESS) {
    658  if (extended)
    659  flag |= PTR_XFLAGS_DOWN;
    660  else
    661  flag |= PTR_FLAGS_DOWN;
    662  }
    663 
    665  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    666 
    667  if (flag != 0) {
    668  rdp_event.mouse_event.flags = flag;
    669  rdp_event.mouse_event.extended = extended;
    670  remmina_rdp_event_event_push(gp, &rdp_event);
    671  }
    672 
    673  return TRUE;
    674 }
    675 
    676 static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
    677 {
    678  TRACE_CALL(__func__);
    679  gint flag;
    680  RemminaPluginRdpEvent rdp_event = { 0 };
    681  float windows_delta;
    682  RemminaFile *remminafile;
    683 
    685  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    686  return FALSE;
    687 
    688  flag = 0;
    690 
    691  /* See [MS-RDPBCGR] TS_POINTER_EVENT and WM_MOUSEWHEEL message */
    692 
    693  switch (event->direction) {
    694  case GDK_SCROLL_UP:
    695  flag = PTR_FLAGS_WHEEL | 0x0078; // 120 is one scroll unit defined in WM_MOUSEWHEEL
    696  break;
    697 
    698  case GDK_SCROLL_DOWN:
    699  flag = PTR_FLAGS_WHEEL | 0x0188; // -120 (one scroll unit) in 9 bits two's complement
    700  break;
    701 
    702 #if GTK_CHECK_VERSION(3, 4, 0)
    703  case GDK_SCROLL_SMOOTH:
    704 
    705  if (event->delta_y == 0.0)
    706  return FALSE;
    707 
    708  windows_delta = event->delta_y * -120;
    709 
    710  if (windows_delta > 255)
    711  windows_delta = 255;
    712  if (windows_delta < -256)
    713  windows_delta = -256;
    714 
    715  flag = PTR_FLAGS_WHEEL | ((short)windows_delta & WheelRotationMask);
    716 
    717  break;
    718 #endif
    719 
    720  default:
    721  return FALSE;
    722  }
    723 
    724  rdp_event.mouse_event.flags = flag;
    725  rdp_event.mouse_event.extended = FALSE;
    726  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    727  remmina_rdp_event_event_push(gp, &rdp_event);
    728 
    729  return TRUE;
    730 }
    731 
    732 static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
    733 {
    734  long int v1, v2;
    735  const char *s;
    736  char *endptr;
    738 
    739  if (strmap == NULL || strmap[0] == 0) {
    740  rfi->keymap = NULL;
    741  return;
    742  }
    743  s = strmap;
    744  rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry));
    745  while (1) {
    746  v1 = strtol(s, &endptr, 10);
    747  if (endptr == s) break;
    748  s = endptr;
    749  if (*s != ':') break;
    750  s++;
    751  v2 = strtol(s, &endptr, 10);
    752  if (endptr == s) break;
    753  s = endptr;
    754  ke.orig_keycode = v1 & 0x7fffffff;
    755  ke.translated_keycode = v2 & 0x7fffffff;
    756  g_array_append_val(rfi->keymap, ke);
    757  if (*s != ',') break;
    758  s++;
    759  }
    760  if (rfi->keymap->len == 0) {
    761  g_array_unref(rfi->keymap);
    762  rfi->keymap = NULL;
    763  }
    764 }
    765 
    766 static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    767 {
    768  TRACE_CALL(__func__);
    769  guint32 unicode_keyval;
    770  guint16 hardware_keycode;
    771  rfContext *rfi = GET_PLUGIN_DATA(gp);
    772  RemminaPluginRdpEvent rdp_event;
    774  RemminaFile *remminafile;
    775  DWORD scancode = 0;
    776  int ik;
    777 
    778  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    779  return FALSE;
    780 
    782  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    783  return FALSE;
    784 
    785 #ifdef ENABLE_GTK_INSPECTOR_KEY
    786  /* GTK inspector key is propagated up. Disabled by default.
    787  * enable it by defining ENABLE_GTK_INSPECTOR_KEY */
    788  if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D))
    789  return FALSE;
    790 
    791 #endif
    792 
    794  rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? false : true);
    795  rdp_event.key_event.extended = false;
    796 
    797  switch (event->keyval) {
    798  case GDK_KEY_Pause:
    799  /*
    800  * See https://msdn.microsoft.com/en-us/library/cc240584.aspx
    801  * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT)
    802  * for pause key management
    803  */
    804  rdp_event.key_event.key_code = 0x1D;
    805  rdp_event.key_event.up = false;
    806  remmina_rdp_event_event_push(gp, &rdp_event);
    807  rdp_event.key_event.key_code = 0x45;
    808  rdp_event.key_event.up = false;
    809  remmina_rdp_event_event_push(gp, &rdp_event);
    810  rdp_event.key_event.key_code = 0x1D;
    811  rdp_event.key_event.up = true;
    812  remmina_rdp_event_event_push(gp, &rdp_event);
    813  rdp_event.key_event.key_code = 0x45;
    814  rdp_event.key_event.up = true;
    815  remmina_rdp_event_event_push(gp, &rdp_event);
    816  break;
    817 
    818  default:
    819  if (!rfi->use_client_keymap) {
    820  hardware_keycode = event->hardware_keycode;
    821  if (rfi->keymap) {
    822  for (ik = 0; ik < rfi->keymap->len; ik++) {
    823  kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik);
    824  if (hardware_keycode == kep->orig_keycode) {
    825  hardware_keycode = kep->translated_keycode;
    826  break;
    827  }
    828  }
    829  }
    830  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(hardware_keycode);
    831  if (scancode) {
    832  rdp_event.key_event.key_code = scancode & 0xFF;
    833  rdp_event.key_event.extended = scancode & 0x100;
    834  remmina_rdp_event_event_push(gp, &rdp_event);
    835  keypress_list_add(gp, rdp_event);
    836  }
    837  } else {
    838  unicode_keyval = gdk_keyval_to_unicode(event->keyval);
    839  /* Decide when whe should send a keycode or a Unicode character.
    840  * - All non char keys (Shift, Alt, Super) should be sent as keycode
    841  * - Space should be sent as keycode (see issue #1364)
    842  * - All special keys (F1-F10, numeric pad, Home/End/Arrows/PgUp/PgDn/Insert/Delete) keycode
    843  * - All key pressed while Ctrl or Alt or Super is down are not decoded by gdk_keyval_to_unicode(), so send it as keycode
    844  * - All keycodes not translatable to unicode chars, as keycode
    845  * - The rest as Unicode char
    846  */
    847  if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad…
    848  event->hardware_keycode == 0x41 || // Spacebar
    849  unicode_keyval == 0 || // Impossible to translate
    850  (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode()
    851  ) {
    852  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode);
    853  rdp_event.key_event.key_code = scancode & 0xFF;
    854  rdp_event.key_event.extended = scancode & 0x100;
    855  if (rdp_event.key_event.key_code) {
    856  remmina_rdp_event_event_push(gp, &rdp_event);
    857  keypress_list_add(gp, rdp_event);
    858  }
    859  } else {
    861  rdp_event.key_event.unicode_code = unicode_keyval;
    862  rdp_event.key_event.extended = false;
    863  remmina_rdp_event_event_push(gp, &rdp_event);
    864  keypress_list_add(gp, rdp_event);
    865  }
    866  }
    867  break;
    868  }
    869 
    870  return TRUE;
    871 }
    872 
    873 gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
    874 {
    875  /* Signal handler for GTK clipboard owner-change */
    876  TRACE_CALL(__func__);
    877  RemminaPluginRdpEvent rdp_event = { 0 };
    878  CLIPRDR_FORMAT_LIST *pFormatList;
    879  GObject *new_owner;
    880 
    881  /* Usually "owner-change" is fired when a user presses "COPY" on the client
    882  * OR when this plugin calls gtk_clipboard_set_with_owner()
    883  * after receiving a RDP server format list in remmina_rdp_cliprdr_server_format_list()
    884  * In the latter case, we must ignore owner change */
    885 
    886  REMMINA_PLUGIN_DEBUG("gp=%p: owner-change event received", gp);
    887 
    888  rfContext *rfi = GET_PLUGIN_DATA(gp);
    889 
    890  if (rfi)
    892 
    893  new_owner = gtk_clipboard_get_owner(gtkClipboard);
    894  if (new_owner != (GObject *)gp) {
    895  /* To do: avoid this when the new owner is another remmina protocol widget of
    896  * the same remmina application */
    897  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is different than me: new=%p me=%p",
    898  gp, new_owner, gp);
    899 
    900  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is not me: Sending local clipboard format list to server.",
    901  gp, new_owner, gp);
    904  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
    905  remmina_rdp_event_event_push(gp, &rdp_event);
    906  } else {
    907  REMMINA_PLUGIN_DEBUG(" ... but I'm the owner!");
    908  }
    909  return TRUE;
    910 }
    911 
    913 {
    914  TRACE_CALL(__func__);
    915  gchar *s;
    916  gint flags;
    917  rfContext *rfi = GET_PLUGIN_DATA(gp);
    918  GtkClipboard *clipboard;
    919  RemminaFile *remminafile;
    920 
    921  gboolean disable_smooth_scrolling = FALSE;
    922 
    923  if (!rfi) return;
    925 
    926  /* we get first the global preferences */
    927  s = remmina_plugin_service->pref_get_value("rdp_disable_smooth_scrolling");
    928  disable_smooth_scrolling = (s && s[0] == '1' ? TRUE : FALSE);
    929  g_free(s), s = NULL;
    930  /* Otherwise we use the connection profile specific setting */
    931  disable_smooth_scrolling = remmina_plugin_service->file_get_int(remminafile, "disable-smooth-scrolling", disable_smooth_scrolling);
    932 
    933  REMMINA_PLUGIN_DEBUG("Disable smooth scrolling is set to %d", disable_smooth_scrolling);
    934 
    935  rfi->drawing_area = gtk_drawing_area_new();
    936  gtk_widget_show(rfi->drawing_area);
    937  gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
    938 
    939  gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK
    940  | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
    941  | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
    942  | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
    943 
    944  if (!disable_smooth_scrolling) {
    945  REMMINA_PLUGIN_DEBUG("Adding GDK_SMOOTH_SCROLL_MASK");
    946  gtk_widget_add_events(rfi->drawing_area, GDK_SMOOTH_SCROLL_MASK);
    947  }
    948 
    949  gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
    950 
    952 
    953  s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
    954  rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
    955  g_free(s), s = NULL;
    956 
    957  /* Read special keymap from profile file, if exists */
    959 
    960  if (rfi->use_client_keymap && rfi->keymap)
    961  fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keyboard mapping' enabled\n");
    962 
    963  g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
    964  G_CALLBACK(remmina_rdp_event_on_draw), gp);
    965  g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
    966  G_CALLBACK(remmina_rdp_event_on_configure), gp);
    967  g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
    968  G_CALLBACK(remmina_rdp_event_on_motion), gp);
    969  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
    970  G_CALLBACK(remmina_rdp_event_on_button), gp);
    971  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
    972  G_CALLBACK(remmina_rdp_event_on_button), gp);
    973  g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
    974  G_CALLBACK(remmina_rdp_event_on_scroll), gp);
    975  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
    976  G_CALLBACK(remmina_rdp_event_on_key), gp);
    977  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
    978  G_CALLBACK(remmina_rdp_event_on_key), gp);
    979  g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event",
    980  G_CALLBACK(remmina_rdp_event_on_focus_in), gp);
    987  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "map-event",
    988  // G_CALLBACK(remmina_rdp_event_on_map), gp);
    989  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "unmap-event",
    990  // G_CALLBACK(remmina_rdp_event_on_unmap), gp);
    991 
    992  if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) {
    993  clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    994  rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
    995  }
    996 
    997  rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpEvent));
    998  rfi->event_queue = g_async_queue_new_full(g_free);
    999  rfi->ui_queue = g_async_queue_new();
    1000  pthread_mutex_init(&rfi->ui_queue_mutex, NULL);
    1001 
    1002  if (pipe(rfi->event_pipe)) {
    1003  g_print("Error creating pipes.\n");
    1004  rfi->event_pipe[0] = -1;
    1005  rfi->event_pipe[1] = -1;
    1006  rfi->event_handle = NULL;
    1007  } else {
    1008  flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
    1009  fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
    1010  rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ);
    1011  if (!rfi->event_handle)
    1012  g_print("CreateFileDescriptorEvent() failed\n");
    1013  }
    1014 
    1015  rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
    1016 
    1017  rfi->display = gdk_display_get_default();
    1018 
    1019 #if GTK_CHECK_VERSION(3, 22, 0)
    1020  GdkVisual *visual = gdk_screen_get_system_visual(
    1021  gdk_display_get_default_screen(rfi->display));
    1022  rfi->bpp = gdk_visual_get_depth(visual);
    1023 #else
    1024  rfi->bpp = gdk_visual_get_best_depth();
    1025 #endif
    1026 }
    1027 
    1029 {
    1030  TRACE_CALL(__func__);
    1031 
    1032  switch (obj->type) {
    1034  free(obj->nocodec.bitmap);
    1035  break;
    1036 
    1037  default:
    1038  break;
    1039  }
    1040 
    1041  g_free(obj);
    1042 }
    1043 
    1045 {
    1046  TRACE_CALL(__func__);
    1047  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1049 
    1050  if (!rfi) return;
    1051 
    1052  /* unregister the clipboard monitor */
    1053  if (rfi->clipboard.clipboard_handler) {
    1054  g_signal_handler_disconnect(G_OBJECT(gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD)), rfi->clipboard.clipboard_handler);
    1055  rfi->clipboard.clipboard_handler = 0;
    1056  }
    1057  if (rfi->delayed_monitor_layout_handler) {
    1058  g_source_remove(rfi->delayed_monitor_layout_handler);
    1060  }
    1061  if (rfi->ui_handler) {
    1062  g_source_remove(rfi->ui_handler);
    1063  rfi->ui_handler = 0;
    1064  }
    1065  while ((ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue)) != NULL)
    1067  if (rfi->surface) {
    1068  cairo_surface_mark_dirty(rfi->surface);
    1069  cairo_surface_destroy(rfi->surface);
    1070  rfi->surface = NULL;
    1071  }
    1072 
    1073  g_hash_table_destroy(rfi->object_table);
    1074 
    1075  g_array_free(rfi->pressed_keys, TRUE);
    1076  if (rfi->keymap) {
    1077  g_array_free(rfi->keymap, TRUE);
    1078  rfi->keymap = NULL;
    1079  }
    1080  g_async_queue_unref(rfi->event_queue);
    1081  rfi->event_queue = NULL;
    1082  g_async_queue_unref(rfi->ui_queue);
    1083  rfi->ui_queue = NULL;
    1084  pthread_mutex_destroy(&rfi->ui_queue_mutex);
    1085 
    1086  if (rfi->event_handle) {
    1087  CloseHandle(rfi->event_handle);
    1088  rfi->event_handle = NULL;
    1089  }
    1090 
    1091  close(rfi->event_pipe[0]);
    1092  close(rfi->event_pipe[1]);
    1093 }
    1094 
    1096 {
    1097  int stride;
    1098  rdpGdi *gdi;
    1099 
    1100  if (!rfi)
    1101  return;
    1102 
    1103  gdi = ((rdpContext *)rfi)->gdi;
    1104 
    1105  if (!gdi)
    1106  return;
    1107 
    1108  if (rfi->surface) {
    1109  cairo_surface_mark_dirty(rfi->surface);
    1110  cairo_surface_destroy(rfi->surface);
    1111  rfi->surface = NULL;
    1112  }
    1113  stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width);
    1114  rfi->surface = cairo_image_surface_create_for_data((unsigned char *)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride);
    1115  cairo_surface_flush(rfi->surface);
    1116 }
    1117 
    1119 {
    1120  TRACE_CALL(__func__);
    1121  gint width, height;
    1122  rdpGdi *gdi;
    1123  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1124 
    1127 
    1128  gdi = ((rdpContext *)rfi)->gdi;
    1129 
    1131 
    1132  /* See if we also must rellocate rfi->surface with different width and height,
    1133  * this usually happens after a DesktopResize RDP event*/
    1134 
    1135  if (rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width ||
    1136  cairo_image_surface_get_height(rfi->surface) != gdi->height)) {
    1137  /* Destroys and recreate rfi->surface with new width and height */
    1138  cairo_surface_mark_dirty(rfi->surface);
    1139  cairo_surface_destroy(rfi->surface);
    1140  rfi->surface = NULL;
    1142  } else if (rfi->surface == NULL) {
    1144  }
    1145 
    1146  /* Send gdi->width and gdi->height obtained from remote server to gp plugin,
    1147  * so they will be saved when closing connection */
    1148  if (width != gdi->width)
    1150  if (height != gdi->height)
    1152 
    1154 
    1156  /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */
    1157  gtk_widget_set_size_request(rfi->drawing_area, -1, -1);
    1158  else
    1159  /* In non scaled mode, the plugins forces dimensions of drawing area */
    1160  gtk_widget_set_size_request(rfi->drawing_area, width, height);
    1162 }
    1163 
    1165 {
    1166  TRACE_CALL(__func__);
    1167  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1168  rdpGdi *gdi;
    1169 
    1170  gdi = ((rdpContext *)rfi)->gdi;
    1171 
    1172  gtk_widget_realize(rfi->drawing_area);
    1173 
    1175  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height);
    1176 
    1178 
    1180  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
    1181  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    1182  REMMINA_PLUGIN_AUDIT(_("Connected to %s via RDP"), host);
    1183 }
    1184 
    1186 {
    1187  TRACE_CALL(__func__);
    1188  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1189 
    1190  gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE);
    1191 }
    1192 
    1194 {
    1195  TRACE_CALL(__func__);
    1196  GdkPixbuf *pixbuf;
    1197  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1198  rdpPointer *pointer = (rdpPointer *)ui->cursor.pointer;
    1199  cairo_surface_t *surface;
    1200  UINT8 *data = malloc(pointer->width * pointer->height * 4);
    1201 
    1202  if (!freerdp_image_copy_from_pointer_data(
    1203  (BYTE *)data, PIXEL_FORMAT_BGRA32,
    1204  pointer->width * 4, 0, 0, pointer->width, pointer->height,
    1205  pointer->xorMaskData, pointer->lengthXorMask,
    1206  pointer->andMaskData, pointer->lengthAndMask,
    1207  pointer->xorBpp, &(ui->cursor.context->gdi->palette))) {
    1208  free(data);
    1209  return FALSE;
    1210  }
    1211 
    1212  surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, pointer->width, pointer->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pointer->width));
    1213  cairo_surface_flush(surface);
    1214  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height);
    1215  cairo_surface_mark_dirty(surface);
    1216  cairo_surface_destroy(surface);
    1217  free(data);
    1218  ((rfPointer *)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos);
    1219  g_object_unref(pixbuf);
    1220 
    1221  return TRUE;
    1222 }
    1223 
    1225 {
    1226  TRACE_CALL(__func__);
    1227  g_object_unref(ui->cursor.pointer->cursor);
    1228  ui->cursor.pointer->cursor = NULL;
    1229 }
    1230 
    1232 {
    1233  TRACE_CALL(__func__);
    1234  GdkWindow *w, *nw;
    1235  gint nx, ny, wx, wy;
    1236 
    1237 #if GTK_CHECK_VERSION(3, 20, 0)
    1238  GdkSeat *seat;
    1239 #else
    1240  GdkDeviceManager *manager;
    1241 #endif
    1242  GdkDevice *dev;
    1243  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1244 
    1245  if (rfi == NULL)
    1246  return FALSE;
    1247 
    1248  w = gtk_widget_get_window(rfi->drawing_area);
    1249 #if GTK_CHECK_VERSION(3, 20, 0)
    1250  seat = gdk_display_get_default_seat(gdk_display_get_default());
    1251  dev = gdk_seat_get_pointer(seat);
    1252 #else
    1253  manager = gdk_display_get_device_manager(gdk_display_get_default());
    1254  dev = gdk_device_manager_get_client_pointer(manager);
    1255 #endif
    1256 
    1257  nw = gdk_device_get_window_at_position(dev, NULL, NULL);
    1258 
    1259  if (nw == w) {
    1260  nx = 0;
    1261  ny = 0;
    1263  gdk_window_get_root_coords(w, nx, ny, &wx, &wy);
    1264  gdk_device_warp(dev, gdk_window_get_screen(w), wx, wy);
    1265  }
    1266  return TRUE;
    1267 }
    1268 
    1270 {
    1271  TRACE_CALL(__func__);
    1272  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1273 
    1274  switch (ui->cursor.type) {
    1276  ui->retval = remmina_rdp_event_create_cursor(gp, ui) ? 1 : 0;
    1277  break;
    1278 
    1281  break;
    1282 
    1284  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), ui->cursor.pointer->cursor);
    1285  ui->retval = 1;
    1286  break;
    1287 
    1289  ui->retval = remmina_rdp_event_set_pointer_position(gp, ui->pos.x, ui->pos.y) ? 1 : 0;
    1290  break;
    1291 
    1293  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area),
    1294  gdk_cursor_new_for_display(gdk_display_get_default(),
    1295  GDK_BLANK_CURSOR));
    1296  ui->retval = 1;
    1297  break;
    1298 
    1300  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), NULL);
    1301  ui->retval = 1;
    1302  break;
    1303  }
    1304 }
    1305 
    1307 {
    1308  TRACE_CALL(__func__);
    1310 }
    1311 
    1313 {
    1314  TRACE_CALL(__func__);
    1315  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1316 
    1317  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    1318  return;
    1320 }
    1321 
    1323 {
    1324  TRACE_CALL(__func__);
    1325  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1326 
    1327  cairo_surface_mark_dirty(rfi->surface);
    1328  cairo_surface_destroy(rfi->surface);
    1329  rfi->surface = NULL;
    1330 }
    1331 
    1333 {
    1334  TRACE_CALL(__func__);
    1335  switch (ui->event.type) {
    1338  break;
    1341  break;
    1342  }
    1343 }
    1344 
    1346 {
    1347  TRACE_CALL(__func__);
    1348  switch (ui->type) {
    1351  break;
    1352 
    1355  break;
    1356 
    1359  break;
    1360 
    1361  case REMMINA_RDP_UI_CURSOR:
    1362  remmina_rdp_event_cursor(gp, ui);
    1363  break;
    1364 
    1367  break;
    1368 
    1369  case REMMINA_RDP_UI_EVENT:
    1371  break;
    1372 
    1373  default:
    1374  break;
    1375  }
    1376 }
    1377 
    1379 {
    1380  TRACE_CALL(__func__);
    1381 
    1382  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1384 
    1385  pthread_mutex_lock(&rfi->ui_queue_mutex);
    1386  ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue);
    1387  if (ui) {
    1388  pthread_mutex_lock(&ui->sync_wait_mutex);
    1389  if (!rfi->thread_cancelled)
    1391  // Should we signal the caller thread to unlock ?
    1392  if (ui->sync) {
    1393  ui->complete = TRUE;
    1394  pthread_cond_signal(&ui->sync_wait_cond);
    1395  pthread_mutex_unlock(&ui->sync_wait_mutex);
    1396  } else {
    1398  }
    1399 
    1400  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1401  return TRUE;
    1402  } else {
    1403  rfi->ui_handler = 0;
    1404  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1405  return FALSE;
    1406  }
    1407 }
    1408 
    1410 {
    1411  TRACE_CALL(__func__);
    1412  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1413  gboolean ui_sync_save;
    1414  int oldcanceltype;
    1415 
    1416  if (!rfi || rfi->thread_cancelled)
    1417  return;
    1418 
    1421  return;
    1422  }
    1423 
    1424  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldcanceltype);
    1425 
    1426  pthread_mutex_lock(&rfi->ui_queue_mutex);
    1427 
    1428  ui_sync_save = ui->sync;
    1429  ui->complete = FALSE;
    1430 
    1431  if (ui_sync_save) {
    1432  pthread_mutex_init(&ui->sync_wait_mutex, NULL);
    1433  pthread_cond_init(&ui->sync_wait_cond, NULL);
    1434  }
    1435 
    1436  ui->complete = FALSE;
    1437 
    1438  g_async_queue_push(rfi->ui_queue, ui);
    1439 
    1440  if (!rfi->ui_handler)
    1441  rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp);
    1442 
    1443  if (ui_sync_save) {
    1444  /* Wait for main thread function completion before returning */
    1445  pthread_mutex_lock(&ui->sync_wait_mutex);
    1446  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1447  while (!ui->complete)
    1448  pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex);
    1449  pthread_cond_destroy(&ui->sync_wait_cond);
    1450  pthread_mutex_destroy(&ui->sync_wait_mutex);
    1451  } else {
    1452  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1453  }
    1454  pthread_setcanceltype(oldcanceltype, NULL);
    1455 }
    1456 
    1458 {
    1459  ui->sync = FALSE;
    1461 }
    1462 
    1464 {
    1465  TRACE_CALL(__func__);
    1466  int retval;
    1467 
    1468  ui->sync = TRUE;
    1470  retval = ui->retval;
    1472  return retval;
    1473 }
    1474 
    1476 {
    1477  TRACE_CALL(__func__);
    1478  void *rp;
    1479 
    1480  ui->sync = TRUE;
    1482  rp = ui->retptr;
    1484  return rp;
    1485 }
    +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK Remote Desktop Client
    3  * Copyright (C) 2010 Jay Sorg
    4  * Copyright (C) 2010-2011 Vic Lee
    5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
    6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    7  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
    8  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
    9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version.
    14  *
    15  * This program is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    18  * GNU General Public License for more details.
    19  *
    20  * You should have received a copy of the GNU General Public License
    21  * along with this program; if not, write to the Free Software
    22  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    23  * Boston, MA 02110-1301, USA.
    24  *
    25  * In addition, as a special exception, the copyright holders give
    26  * permission to link the code of portions of this program with the
    27  * OpenSSL library under certain conditions as described in each
    28  * individual source file, and distribute linked combinations
    29  * including the two.
    30  * You must obey the GNU General Public License in all respects
    31  * for all of the code used other than OpenSSL. * If you modify
    32  * file(s) with this exception, you may extend this exception to your
    33  * version of the file(s), but you are not obligated to do so. * If you
    34  * do not wish to do so, delete this exception statement from your
    35  * version. * If you delete this exception statement from all source
    36  * files in the program, then also delete it here.
    37  *
    38  */
    39 
    40 #include "rdp_cliprdr.h"
    41 #include "rdp_event.h"
    42 #include "rdp_monitor.h"
    43 #include "rdp_settings.h"
    44 #include <gdk/gdkkeysyms.h>
    45 #ifdef GDK_WINDOWING_X11
    46 #include <cairo/cairo-xlib.h>
    47 #else
    48 #include <cairo/cairo.h>
    49 #endif
    50 #include <freerdp/locale/keyboard.h>
    51 
    53 {
    54  TRACE_CALL(__func__);
    55  rfContext *rfi = GET_PLUGIN_DATA(gp);
    56  rdpGdi *gdi;
    57 
    58  if (rfi == NULL)
    59  return false;
    60 
    62  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
    63 
    64  if (do_suppress) {
    65  gdi = ((rdpContext *)rfi)->gdi;
    66 
    67  REMMINA_PLUGIN_DEBUG("Map event received, disabling TS_SUPPRESS_OUTPUT_PDU ");
    68  gdi_send_suppress_output(gdi, FALSE);
    69  }
    70 
    71  return FALSE;
    72 }
    73 
    75 {
    76  TRACE_CALL(__func__);
    77  rfContext *rfi = GET_PLUGIN_DATA(gp);
    78  rdpGdi *gdi;
    79 
    80  if (rfi == NULL)
    81  return false;
    82 
    83  GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(gp));
    84  GdkWindow *window = gtk_widget_get_window(toplevel);
    85 
    86  if (gdk_window_get_fullscreen_mode(window) == GDK_FULLSCREEN_ON_ALL_MONITORS) {
    87  REMMINA_PLUGIN_DEBUG("Unmap event received, but cannot enable TS_SUPPRESS_OUTPUT_PDU when in fullscreen");
    88  return FALSE;
    89  }
    90 
    92  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
    93 
    94  if (do_suppress) {
    95  gdi = ((rdpContext *)rfi)->gdi;
    96 
    97  REMMINA_PLUGIN_DEBUG("Unmap event received, enabling TS_SUPPRESS_OUTPUT_PDU ");
    98  gdi_send_suppress_output(gdi, TRUE);
    99  }
    100 
    101  return FALSE;
    102 }
    103 
    104 static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    105 {
    106  TRACE_CALL(__func__);
    107 
    108  rfContext *rfi = GET_PLUGIN_DATA(gp);
    109  rdpInput *input;
    110  GdkModifierType state;
    111 
    112 #if GTK_CHECK_VERSION(3, 20, 0)
    113  GdkSeat *seat;
    114 #else
    115  GdkDeviceManager *manager;
    116 #endif
    117  GdkDevice *keyboard = NULL;
    118 
    119  const gchar *wname = gtk_widget_get_name(gtk_widget_get_toplevel(widget));
    120  REMMINA_PLUGIN_DEBUG("Top level name is: %s", wname);
    121 
    122  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    123  return FALSE;
    124 
    125  input = rfi->instance->input;
    126  UINT32 toggle_keys_state = 0;
    127 
    128 #if GTK_CHECK_VERSION(3, 20, 0)
    129  seat = gdk_display_get_default_seat(gdk_display_get_default());
    130  keyboard = gdk_seat_get_pointer(seat);
    131 #else
    132  manager = gdk_display_get_device_manager(gdk_display_get_default());
    133  keyboard = gdk_device_manager_get_client_pointer(manager);
    134 #endif
    135  gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state);
    136 
    137  if (state & GDK_LOCK_MASK)
    138  toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
    139  if (state & GDK_MOD2_MASK)
    140  toggle_keys_state |= KBD_SYNC_NUM_LOCK;
    141  if (state & GDK_MOD5_MASK)
    142  toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
    143 
    144  input->SynchronizeEvent(input, toggle_keys_state);
    145  input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
    146 
    147  return FALSE;
    148 }
    149 
    151 {
    152  TRACE_CALL(__func__);
    153  rfContext *rfi = GET_PLUGIN_DATA(gp);
    154  RemminaPluginRdpEvent *event;
    155 
    156  /* Called by the main GTK thread to send an event to the libfreerdp thread */
    157 
    158  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    159  return;
    160 
    161  if (rfi->event_queue) {
    162 #if GLIB_CHECK_VERSION(2,67,3)
    163  event = g_memdup2(e, sizeof(RemminaPluginRdpEvent));
    164 #else
    165  event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
    166 #endif
    167  g_async_queue_push(rfi->event_queue, event);
    168 
    169  if (write(rfi->event_pipe[1], "\0", 1)) {
    170  }
    171  }
    172 }
    173 
    175 {
    176  TRACE_CALL(__func__);
    177  rfContext *rfi = GET_PLUGIN_DATA(gp);
    178  RemminaPluginRdpEvent rdp_event = { 0 };
    179  int i;
    180 
    181  /* Send all release key events for previously pressed keys */
    182  for (i = 0; i < rfi->pressed_keys->len; i++) {
    183  rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
    184  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
    186  rdp_event.key_event.up == false) {
    187  rdp_event.key_event.up = true;
    188  remmina_rdp_event_event_push(gp, &rdp_event);
    189  }
    190  }
    191 
    192  g_array_set_size(rfi->pressed_keys, 0);
    193 }
    194 
    196 {
    197  TRACE_CALL(__func__);
    198  gint i;
    199  rfContext *rfi = GET_PLUGIN_DATA(gp);
    200  RemminaPluginRdpEvent rdp_event_2 = { 0 };
    201 
    203 
    204  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
    206  rdp_event.key_event.up) {
    207  /* Unregister the keycode only */
    208  for (i = 0; i < rfi->pressed_keys->len; i++) {
    209  rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
    210 
    211  if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code &&
    212  rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code &&
    213  rdp_event_2.key_event.extended == rdp_event.key_event.extended &&
    214  rdp_event_2.key_event.extended1 == rdp_event.key_event.extended1) {
    215  g_array_remove_index_fast(rfi->pressed_keys, i);
    216  break;
    217  }
    218  }
    219  }
    220 }
    221 
    223 {
    224  TRACE_CALL(__func__);
    225  rfContext *rfi = GET_PLUGIN_DATA(gp);
    226 
    227  if (!rdp_event.key_event.key_code)
    228  return;
    229 
    230  if (rdp_event.key_event.up)
    231  remmina_rdp_event_release_key(gp, rdp_event);
    232  else
    233  g_array_append_val(rfi->pressed_keys, rdp_event);
    234 }
    235 
    236 
    237 static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
    238 {
    239  TRACE_CALL(__func__);
    240  gint width, height;
    241  gint sx, sy, sw, sh;
    242  rfContext *rfi = GET_PLUGIN_DATA(gp);
    243 
    244  if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface)
    245  return;
    246 
    249 
    250  if ((width == 0) || (height == 0))
    251  return;
    252 
    253  if ((rfi->scale_width == width) && (rfi->scale_height == height)) {
    254  /* Same size, just copy the pixels */
    255  *x = MIN(MAX(0, *x), width - 1);
    256  *y = MIN(MAX(0, *y), height - 1);
    257  *w = MIN(width - *x, *w);
    258  *h = MIN(height - *y, *h);
    259  return;
    260  }
    261 
    262  /* We have to extend the scaled region one scaled pixel, to avoid gaps */
    263 
    264  sx = MIN(MAX(0, (*x) * rfi->scale_width / width
    265  - rfi->scale_width / width - 2), rfi->scale_width - 1);
    266 
    267  sy = MIN(MAX(0, (*y) * rfi->scale_height / height
    268  - rfi->scale_height / height - 2), rfi->scale_height - 1);
    269 
    270  sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
    271  + rfi->scale_width / width + 4);
    272 
    273  sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
    274  + rfi->scale_height / height + 4);
    275 
    276  *x = sx;
    277  *y = sy;
    278  *w = sw;
    279  *h = sh;
    280 }
    281 
    283 {
    284  TRACE_CALL(__func__);
    285  rfContext *rfi = GET_PLUGIN_DATA(gp);
    286  gint x, y, w, h, i;
    287 
    288  for (i = 0; i < ui->reg.ninvalid; i++) {
    289  x = ui->reg.ureg[i].x;
    290  y = ui->reg.ureg[i].y;
    291  w = ui->reg.ureg[i].w;
    292  h = ui->reg.ureg[i].h;
    293 
    295  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
    296 
    297  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
    298  }
    299  g_free(ui->reg.ureg);
    300 }
    301 
    302 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    303 {
    304  TRACE_CALL(__func__);
    305  rfContext *rfi = GET_PLUGIN_DATA(gp);
    306 
    308  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
    309 
    310  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
    311 }
    312 
    314 {
    315  TRACE_CALL(__func__);
    316  GtkAllocation a;
    317  gint rdwidth, rdheight;
    318  gint gpwidth, gpheight;
    319  rfContext *rfi = GET_PLUGIN_DATA(gp);
    320 
    321  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
    322  gpwidth = a.width;
    323  gpheight = a.height;
    324 
    326  if ((gpwidth > 1) && (gpheight > 1)) {
    329 
    330  rfi->scale_width = gpwidth;
    331  rfi->scale_height = gpheight;
    332 
    333  rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth;
    334  rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight;
    335  }
    336  } else {
    337  rfi->scale_width = 0;
    338  rfi->scale_height = 0;
    339  rfi->scale_x = 0;
    340  rfi->scale_y = 0;
    341  }
    342 }
    343 
    344 static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
    345 {
    346  TRACE_CALL(__func__);
    347  rfContext *rfi = GET_PLUGIN_DATA(gp);
    348  guint width, height;
    349  gchar *msg;
    350  cairo_text_extents_t extents;
    351 
    352  if (!rfi || !rfi->connected)
    353  return FALSE;
    354 
    355 
    356  if (rfi->is_reconnecting) {
    357  /* FreeRDP is reconnecting, just show a message to the user */
    358 
    359  width = gtk_widget_get_allocated_width(widget);
    360  height = gtk_widget_get_allocated_height(widget);
    361 
    362  /* Draw text */
    363  msg = g_strdup_printf(_("Reconnection attempt %d of %d…"),
    365 
    366  cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
    367  cairo_set_font_size(context, 24);
    368  cairo_set_source_rgb(context, 0.9, 0.9, 0.9);
    369  cairo_text_extents(context, msg, &extents);
    370  cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2);
    371  cairo_show_text(context, msg);
    372  g_free(msg);
    373  } else {
    374  /* Standard drawing: We copy the surface from RDP */
    375 
    376  if (!rfi->surface)
    377  return FALSE;
    378 
    380  cairo_scale(context, rfi->scale_x, rfi->scale_y);
    381 
    382  cairo_surface_flush(rfi->surface);
    383  cairo_set_source_surface(context, rfi->surface, 0, 0);
    384  cairo_surface_mark_dirty(rfi->surface);
    385 
    386  cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); // Ignore alpha channel from FreeRDP
    387  cairo_paint(context);
    388  }
    389 
    390  return TRUE;
    391 }
    392 
    394 {
    395  TRACE_CALL(__func__);
    396  rfContext *rfi = GET_PLUGIN_DATA(gp);
    397 
    398  RemminaPluginRdpEvent rdp_event = { 0 };
    399  GtkAllocation a;
    400  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
    401 
    402  RemminaFile *remminafile;
    403 
    404  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    405  return FALSE;
    406 
    408 
    410  return FALSE;
    411 
    413  gint gpwidth, gpheight, prevwidth, prevheight;
    414 
    415  gchar *monitorids = NULL;
    416  guint32 maxwidth = 0;
    417  guint32 maxheight = 0;
    418 
    419  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
    420 
    421  REMMINA_PLUGIN_DEBUG("Sending preconfigured monitor layout");
    422  if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) {
    423  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
    424  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
    425  gpwidth = a.width;
    426  gpheight = a.height;
    429 
    430  if ((gpwidth != prevwidth || gpheight != prevheight) && gpwidth >= 200 && gpheight >= 200) {
    431  if (rfi->rdpgfxchan) {
    432  /* Workaround for FreeRDP issue #5417 */
    433  if (gpwidth < AVC_MIN_DESKTOP_WIDTH)
    434  gpwidth = AVC_MIN_DESKTOP_WIDTH;
    435  if (gpheight < AVC_MIN_DESKTOP_HEIGHT)
    436  gpheight = AVC_MIN_DESKTOP_HEIGHT;
    437  }
    439  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    440  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    441  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
    442  const rdpMonitor *current = &base[i];
    443  REMMINA_PLUGIN_DEBUG("Sending display layout n° %d", i);
    444  rdp_event.monitor_layout.Flags = current->is_primary;
    445  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags);
    446  rdp_event.monitor_layout.Left = current->x;
    447  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left);
    448  rdp_event.monitor_layout.Top = current->y;
    449  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top);
    450  rdp_event.monitor_layout.width = current->width;
    451  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width);
    452  rdp_event.monitor_layout.height = current->height;
    453  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height);
    454  rdp_event.monitor_layout.physicalWidth = current->attributes.physicalWidth;
    455  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth);
    456  rdp_event.monitor_layout.physicalHeight = current->attributes.physicalHeight;
    457  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight);
    458  if (current->attributes.orientation)
    459  rdp_event.monitor_layout.desktopOrientation = current->attributes.orientation;
    460  else
    461  rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation;
    462  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation);
    463  rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor;
    464  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor);
    465  rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor;
    466  }
    467  remmina_rdp_event_event_push(gp, &rdp_event);
    468  } else {
    469  rdp_event.monitor_layout.width = gpwidth;
    470  rdp_event.monitor_layout.height = gpheight;
    471  rdp_event.monitor_layout.desktopOrientation = desktopOrientation;
    472  rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor;
    473  rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor;
    474  remmina_rdp_event_event_push(gp, &rdp_event);
    475  }
    476  }
    477  }
    478 
    479  g_free(monitorids);
    480 
    481  return FALSE;
    482 }
    483 
    485 {
    486  TRACE_CALL(__func__);
    487  rfContext *rfi = GET_PLUGIN_DATA(gp);
    488 
    489  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    490  return;
    492  g_source_remove(rfi->delayed_monitor_layout_handler);
    494  }
    496  rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp);
    497 }
    498 
    499 static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
    500 {
    501  TRACE_CALL(__func__);
    502  /* Called when gp changes its size or position */
    503 
    504  rfContext *rfi = GET_PLUGIN_DATA(gp);
    505 
    506  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    507  return FALSE;
    508 
    510 
    511  /* If the scaler is not active, schedule a delayed remote resolution change */
    513 
    514 
    515  return FALSE;
    516 }
    517 
    518 static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
    519 {
    520  TRACE_CALL(__func__);
    521  rfContext *rfi = GET_PLUGIN_DATA(gp);
    522 
    523  /*
    524  * Translate a position from local window coordinates (ix,iy) to
    525  * RDP coordinates and put result on (*ox,*uy)
    526  * */
    527 
    528  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    529  return;
    530 
    531  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
    532  *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
    533  *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
    534  } else {
    535  *ox = (UINT16)ix;
    536  *oy = (UINT16)iy;
    537  }
    538 }
    539 
    540 static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
    541 {
    542  TRACE_CALL(__func__);
    543  rfContext *rfi = GET_PLUGIN_DATA(gp);
    544 
    545  /*
    546  * Translate a position from RDP coordinates (ix,iy) to
    547  * local window coordinates and put result on (*ox,*uy)
    548  * */
    549 
    550  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    551  return;
    552 
    553  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
    556  } else {
    557  *ox = ix;
    558  *oy = iy;
    559  }
    560 }
    561 
    563  TRACE_CALL(__func__);
    564  RemminaPluginRdpEvent rdp_event = { 0 };
    565  RemminaFile *remminafile;
    566  rfContext *rfi = GET_PLUGIN_DATA(gp);
    567 
    569  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    570  return;
    571 
    573  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
    574  rdp_event.mouse_event.extended = FALSE;
    575  rdp_event.mouse_event.x = rfi->last_x;
    576  rdp_event.mouse_event.y = rfi->last_y;
    577  remmina_rdp_event_event_push(gp, &rdp_event);
    578 }
    579 
    580 static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
    581 {
    582  TRACE_CALL(__func__);
    583  RemminaPluginRdpEvent rdp_event = { 0 };
    584  RemminaFile *remminafile;
    585  rfContext *rfi = GET_PLUGIN_DATA(gp);
    586 
    588  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    589  return FALSE;
    590 
    592  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
    593  rdp_event.mouse_event.extended = FALSE;
    594 
    595  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    596  if (rfi != NULL){
    597  rfi->last_x = rdp_event.mouse_event.x;
    598  rfi->last_y = rdp_event.mouse_event.y;
    599  }
    600 
    601  remmina_rdp_event_event_push(gp, &rdp_event);
    602 
    603  return TRUE;
    604 }
    605 
    606 static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
    607 {
    608  TRACE_CALL(__func__);
    609  gint flag;
    610  gboolean extended = FALSE;
    611  RemminaPluginRdpEvent rdp_event = { 0 };
    612  gint primary, secondary;
    613 
    614  RemminaFile *remminafile;
    615 
    617  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    618  return FALSE;
    619 
    620  /* We bypass 2button-press and 3button-press events */
    621  if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
    622  return TRUE;
    623 
    624  flag = 0;
    625 
    626  if (remmina_plugin_service->file_get_int(remminafile, "left-handed", FALSE)) {
    627  primary = PTR_FLAGS_BUTTON2;
    628  secondary = PTR_FLAGS_BUTTON1;
    629  } else {
    630  primary = PTR_FLAGS_BUTTON1;
    631  secondary = PTR_FLAGS_BUTTON2;
    632  }
    633 
    634  switch (event->button) {
    635  case 1:
    636  flag |= primary;
    637  break;
    638  case 2:
    639  flag |= PTR_FLAGS_BUTTON3;
    640  break;
    641  case 3:
    642  flag |= secondary;
    643  break;
    644  case 8: /* back */
    645  case 97: /* Xming */
    646  extended = TRUE;
    647  flag |= PTR_XFLAGS_BUTTON1;
    648  break;
    649  case 9: /* forward */
    650  case 112: /* Xming */
    651  extended = TRUE;
    652  flag |= PTR_XFLAGS_BUTTON2;
    653  break;
    654  default:
    655  return FALSE;
    656  }
    657 
    658  if (event->type == GDK_BUTTON_PRESS) {
    659  if (extended)
    660  flag |= PTR_XFLAGS_DOWN;
    661  else
    662  flag |= PTR_FLAGS_DOWN;
    663  }
    664 
    666  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    667 
    668  if (flag != 0) {
    669  rdp_event.mouse_event.flags = flag;
    670  rdp_event.mouse_event.extended = extended;
    671  remmina_rdp_event_event_push(gp, &rdp_event);
    672  }
    673 
    674  return TRUE;
    675 }
    676 
    677 static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
    678 {
    679  TRACE_CALL(__func__);
    680  gint flag;
    681  RemminaPluginRdpEvent rdp_event = { 0 };
    682  float windows_delta;
    683  RemminaFile *remminafile;
    684 
    686  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    687  return FALSE;
    688 
    689  flag = 0;
    691 
    692  /* See [MS-RDPBCGR] TS_POINTER_EVENT and WM_MOUSEWHEEL message */
    693 
    694  switch (event->direction) {
    695  case GDK_SCROLL_UP:
    696  flag = PTR_FLAGS_WHEEL | 0x0078; // 120 is one scroll unit defined in WM_MOUSEWHEEL
    697  break;
    698 
    699  case GDK_SCROLL_DOWN:
    700  flag = PTR_FLAGS_WHEEL | 0x0188; // -120 (one scroll unit) in 9 bits two's complement
    701  break;
    702 
    703 #if GTK_CHECK_VERSION(3, 4, 0)
    704  case GDK_SCROLL_SMOOTH:
    705 
    706  if (event->delta_y == 0.0)
    707  return FALSE;
    708 
    709  windows_delta = event->delta_y * -120;
    710 
    711  if (windows_delta > 255)
    712  windows_delta = 255;
    713  if (windows_delta < -256)
    714  windows_delta = -256;
    715 
    716  flag = PTR_FLAGS_WHEEL | ((short)windows_delta & WheelRotationMask);
    717 
    718  break;
    719 #endif
    720 
    721  default:
    722  return FALSE;
    723  }
    724 
    725  rdp_event.mouse_event.flags = flag;
    726  rdp_event.mouse_event.extended = FALSE;
    727  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
    728  remmina_rdp_event_event_push(gp, &rdp_event);
    729 
    730  return TRUE;
    731 }
    732 
    733 static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
    734 {
    735  long int v1, v2;
    736  const char *s;
    737  char *endptr;
    739 
    740  if (strmap == NULL || strmap[0] == 0) {
    741  rfi->keymap = NULL;
    742  return;
    743  }
    744  s = strmap;
    745  rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry));
    746  while (1) {
    747  v1 = strtol(s, &endptr, 10);
    748  if (endptr == s) break;
    749  s = endptr;
    750  if (*s != ':') break;
    751  s++;
    752  v2 = strtol(s, &endptr, 10);
    753  if (endptr == s) break;
    754  s = endptr;
    755  ke.orig_keycode = v1 & 0x7fffffff;
    756  ke.translated_keycode = v2 & 0x7fffffff;
    757  g_array_append_val(rfi->keymap, ke);
    758  if (*s != ',') break;
    759  s++;
    760  }
    761  if (rfi->keymap->len == 0) {
    762  g_array_unref(rfi->keymap);
    763  rfi->keymap = NULL;
    764  }
    765 }
    766 
    767 static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    768 {
    769  TRACE_CALL(__func__);
    770  guint32 unicode_keyval;
    771  guint16 hardware_keycode;
    772  rfContext *rfi = GET_PLUGIN_DATA(gp);
    773  RemminaPluginRdpEvent rdp_event;
    775  RemminaFile *remminafile;
    776  DWORD scancode = 0;
    777  int ik;
    778 
    779  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    780  return FALSE;
    781 
    783  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
    784  return FALSE;
    785 
    786 #ifdef ENABLE_GTK_INSPECTOR_KEY
    787  /* GTK inspector key is propagated up. Disabled by default.
    788  * enable it by defining ENABLE_GTK_INSPECTOR_KEY */
    789  if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D))
    790  return FALSE;
    791 
    792 #endif
    793 
    795  rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? false : true);
    796  rdp_event.key_event.extended = false;
    797  rdp_event.key_event.extended1 = false;
    798 
    799  switch (event->keyval) {
    800  case GDK_KEY_Pause:
    801  /*
    802  * See https://msdn.microsoft.com/en-us/library/cc240584.aspx
    803  * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT)
    804  * for pause key management
    805  */
    806  rdp_event.key_event.key_code = 0x1D;
    807  rdp_event.key_event.up = false;
    808  rdp_event.key_event.extended1 = TRUE;
    809  remmina_rdp_event_event_push(gp, &rdp_event);
    810  rdp_event.key_event.key_code = 0x45;
    811  rdp_event.key_event.up = false;
    812  rdp_event.key_event.extended1 = FALSE;
    813  remmina_rdp_event_event_push(gp, &rdp_event);
    814  rdp_event.key_event.key_code = 0x1D;
    815  rdp_event.key_event.up = true;
    816  rdp_event.key_event.extended1 = TRUE;
    817  remmina_rdp_event_event_push(gp, &rdp_event);
    818  rdp_event.key_event.key_code = 0x45;
    819  rdp_event.key_event.up = true;
    820  rdp_event.key_event.extended1 = FALSE;
    821  remmina_rdp_event_event_push(gp, &rdp_event);
    822  break;
    823 
    824  default:
    825  if (!rfi->use_client_keymap) {
    826  hardware_keycode = event->hardware_keycode;
    827  if (rfi->keymap) {
    828  for (ik = 0; ik < rfi->keymap->len; ik++) {
    829  kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik);
    830  if (hardware_keycode == kep->orig_keycode) {
    831  hardware_keycode = kep->translated_keycode;
    832  break;
    833  }
    834  }
    835  }
    836  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(hardware_keycode);
    837  if (scancode) {
    838  rdp_event.key_event.key_code = scancode & 0xFF;
    839  rdp_event.key_event.extended = scancode & 0x100;
    840  rdp_event.key_event.extended1 = FALSE;
    841  remmina_rdp_event_event_push(gp, &rdp_event);
    842  keypress_list_add(gp, rdp_event);
    843  }
    844  } else {
    845  unicode_keyval = gdk_keyval_to_unicode(event->keyval);
    846  /* Decide when whe should send a keycode or a Unicode character.
    847  * - All non char keys (Shift, Alt, Super) should be sent as keycode
    848  * - Space should be sent as keycode (see issue #1364)
    849  * - All special keys (F1-F10, numeric pad, Home/End/Arrows/PgUp/PgDn/Insert/Delete) keycode
    850  * - All key pressed while Ctrl or Alt or Super is down are not decoded by gdk_keyval_to_unicode(), so send it as keycode
    851  * - All keycodes not translatable to unicode chars, as keycode
    852  * - The rest as Unicode char
    853  */
    854  if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad…
    855  event->hardware_keycode == 0x41 || // Spacebar
    856  unicode_keyval == 0 || // Impossible to translate
    857  (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode()
    858  ) {
    859  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode);
    860  rdp_event.key_event.key_code = scancode & 0xFF;
    861  rdp_event.key_event.extended1 = FALSE;
    862  if (rdp_event.key_event.key_code) {
    863  remmina_rdp_event_event_push(gp, &rdp_event);
    864  keypress_list_add(gp, rdp_event);
    865  }
    866  } else {
    868  rdp_event.key_event.unicode_code = unicode_keyval;
    869  rdp_event.key_event.extended = false;
    870  rdp_event.key_event.extended1 = FALSE;
    871  remmina_rdp_event_event_push(gp, &rdp_event);
    872  keypress_list_add(gp, rdp_event);
    873  }
    874  }
    875  break;
    876  }
    877 
    878  return TRUE;
    879 }
    880 
    881 gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
    882 {
    883  /* Signal handler for GTK clipboard owner-change */
    884  TRACE_CALL(__func__);
    885  RemminaPluginRdpEvent rdp_event = { 0 };
    886  CLIPRDR_FORMAT_LIST *pFormatList;
    887  GObject *new_owner;
    888 
    889  /* Usually "owner-change" is fired when a user presses "COPY" on the client
    890  * OR when this plugin calls gtk_clipboard_set_with_owner()
    891  * after receiving a RDP server format list in remmina_rdp_cliprdr_server_format_list()
    892  * In the latter case, we must ignore owner change */
    893 
    894  REMMINA_PLUGIN_DEBUG("gp=%p: owner-change event received", gp);
    895 
    896  rfContext *rfi = GET_PLUGIN_DATA(gp);
    897 
    898  if (rfi)
    900 
    901  new_owner = gtk_clipboard_get_owner(gtkClipboard);
    902  if (new_owner != (GObject *)gp) {
    903  /* To do: avoid this when the new owner is another remmina protocol widget of
    904  * the same remmina application */
    905  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is different than me: new=%p me=%p",
    906  gp, new_owner, gp);
    907 
    908  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is not me: Sending local clipboard format list to server.",
    909  gp, new_owner, gp);
    912  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
    913  remmina_rdp_event_event_push(gp, &rdp_event);
    914  } else {
    915  REMMINA_PLUGIN_DEBUG(" ... but I'm the owner!");
    916  }
    917  return TRUE;
    918 }
    919 
    921 {
    922  TRACE_CALL(__func__);
    923  gchar *s;
    924  gint flags;
    925  rfContext *rfi = GET_PLUGIN_DATA(gp);
    926  GtkClipboard *clipboard;
    927  RemminaFile *remminafile;
    928 
    929  gboolean disable_smooth_scrolling = FALSE;
    930 
    931  if (!rfi) return;
    933 
    934  /* we get first the global preferences */
    935  s = remmina_plugin_service->pref_get_value("rdp_disable_smooth_scrolling");
    936  disable_smooth_scrolling = (s && s[0] == '1' ? TRUE : FALSE);
    937  g_free(s), s = NULL;
    938  /* Otherwise we use the connection profile specific setting */
    939  disable_smooth_scrolling = remmina_plugin_service->file_get_int(remminafile, "disable-smooth-scrolling", disable_smooth_scrolling);
    940 
    941  REMMINA_PLUGIN_DEBUG("Disable smooth scrolling is set to %d", disable_smooth_scrolling);
    942 
    943  rfi->drawing_area = gtk_drawing_area_new();
    944  gtk_widget_show(rfi->drawing_area);
    945  gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
    946 
    947  gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK
    948  | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
    949  | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
    950  | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
    951 
    952  if (!disable_smooth_scrolling) {
    953  REMMINA_PLUGIN_DEBUG("Adding GDK_SMOOTH_SCROLL_MASK");
    954  gtk_widget_add_events(rfi->drawing_area, GDK_SMOOTH_SCROLL_MASK);
    955  }
    956 
    957  gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
    958 
    960 
    961  s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
    962  rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
    963  g_free(s), s = NULL;
    964 
    965  /* Read special keymap from profile file, if exists */
    967 
    968  if (rfi->use_client_keymap && rfi->keymap)
    969  fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keyboard mapping' enabled\n");
    970 
    971  g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
    972  G_CALLBACK(remmina_rdp_event_on_draw), gp);
    973  g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
    974  G_CALLBACK(remmina_rdp_event_on_configure), gp);
    975  g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
    976  G_CALLBACK(remmina_rdp_event_on_motion), gp);
    977  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
    978  G_CALLBACK(remmina_rdp_event_on_button), gp);
    979  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
    980  G_CALLBACK(remmina_rdp_event_on_button), gp);
    981  g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
    982  G_CALLBACK(remmina_rdp_event_on_scroll), gp);
    983  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
    984  G_CALLBACK(remmina_rdp_event_on_key), gp);
    985  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
    986  G_CALLBACK(remmina_rdp_event_on_key), gp);
    987  g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event",
    988  G_CALLBACK(remmina_rdp_event_on_focus_in), gp);
    995  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "map-event",
    996  // G_CALLBACK(remmina_rdp_event_on_map), gp);
    997  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "unmap-event",
    998  // G_CALLBACK(remmina_rdp_event_on_unmap), gp);
    999 
    1000  if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) {
    1001  clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
    1002  rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
    1003  }
    1004 
    1005  rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpEvent));
    1006  rfi->event_queue = g_async_queue_new_full(g_free);
    1007  rfi->ui_queue = g_async_queue_new();
    1008  pthread_mutex_init(&rfi->ui_queue_mutex, NULL);
    1009 
    1010  if (pipe(rfi->event_pipe)) {
    1011  g_print("Error creating pipes.\n");
    1012  rfi->event_pipe[0] = -1;
    1013  rfi->event_pipe[1] = -1;
    1014  rfi->event_handle = NULL;
    1015  } else {
    1016  flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
    1017  fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
    1018  rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ);
    1019  if (!rfi->event_handle)
    1020  g_print("CreateFileDescriptorEvent() failed\n");
    1021  }
    1022 
    1023  rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
    1024 
    1025  rfi->display = gdk_display_get_default();
    1026 
    1027 #if GTK_CHECK_VERSION(3, 22, 0)
    1028  GdkVisual *visual = gdk_screen_get_system_visual(
    1029  gdk_display_get_default_screen(rfi->display));
    1030  rfi->bpp = gdk_visual_get_depth(visual);
    1031 #else
    1032  rfi->bpp = gdk_visual_get_best_depth();
    1033 #endif
    1034 }
    1035 
    1037 {
    1038  TRACE_CALL(__func__);
    1039 
    1040  switch (obj->type) {
    1042  free(obj->nocodec.bitmap);
    1043  break;
    1044 
    1045  default:
    1046  break;
    1047  }
    1048 
    1049  g_free(obj);
    1050 }
    1051 
    1053 {
    1054  TRACE_CALL(__func__);
    1055  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1057 
    1058  if (!rfi) return;
    1059 
    1060  /* unregister the clipboard monitor */
    1061  if (rfi->clipboard.clipboard_handler) {
    1062  g_signal_handler_disconnect(G_OBJECT(gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD)), rfi->clipboard.clipboard_handler);
    1063  rfi->clipboard.clipboard_handler = 0;
    1064  }
    1065  if (rfi->delayed_monitor_layout_handler) {
    1066  g_source_remove(rfi->delayed_monitor_layout_handler);
    1068  }
    1069  if (rfi->ui_handler) {
    1070  g_source_remove(rfi->ui_handler);
    1071  rfi->ui_handler = 0;
    1072  }
    1073  while ((ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue)) != NULL)
    1075  if (rfi->surface) {
    1076  cairo_surface_mark_dirty(rfi->surface);
    1077  cairo_surface_destroy(rfi->surface);
    1078  rfi->surface = NULL;
    1079  }
    1080 
    1081  g_hash_table_destroy(rfi->object_table);
    1082 
    1083  g_array_free(rfi->pressed_keys, TRUE);
    1084  if (rfi->keymap) {
    1085  g_array_free(rfi->keymap, TRUE);
    1086  rfi->keymap = NULL;
    1087  }
    1088  g_async_queue_unref(rfi->event_queue);
    1089  rfi->event_queue = NULL;
    1090  g_async_queue_unref(rfi->ui_queue);
    1091  rfi->ui_queue = NULL;
    1092  pthread_mutex_destroy(&rfi->ui_queue_mutex);
    1093 
    1094  if (rfi->event_handle) {
    1095  CloseHandle(rfi->event_handle);
    1096  rfi->event_handle = NULL;
    1097  }
    1098 
    1099  close(rfi->event_pipe[0]);
    1100  close(rfi->event_pipe[1]);
    1101 }
    1102 
    1104 {
    1105  int stride;
    1106  rdpGdi *gdi;
    1107 
    1108  if (!rfi)
    1109  return;
    1110 
    1111  gdi = ((rdpContext *)rfi)->gdi;
    1112 
    1113  if (!gdi)
    1114  return;
    1115 
    1116  if (rfi->surface) {
    1117  cairo_surface_mark_dirty(rfi->surface);
    1118  cairo_surface_destroy(rfi->surface);
    1119  rfi->surface = NULL;
    1120  }
    1121  stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width);
    1122  rfi->surface = cairo_image_surface_create_for_data((unsigned char *)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride);
    1123  cairo_surface_flush(rfi->surface);
    1124 }
    1125 
    1127 {
    1128  TRACE_CALL(__func__);
    1129  gint width, height;
    1130  rdpGdi *gdi;
    1131  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1132 
    1135 
    1136  gdi = ((rdpContext *)rfi)->gdi;
    1137 
    1139 
    1140  /* See if we also must rellocate rfi->surface with different width and height,
    1141  * this usually happens after a DesktopResize RDP event*/
    1142 
    1143  if (rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width ||
    1144  cairo_image_surface_get_height(rfi->surface) != gdi->height)) {
    1145  /* Destroys and recreate rfi->surface with new width and height */
    1146  cairo_surface_mark_dirty(rfi->surface);
    1147  cairo_surface_destroy(rfi->surface);
    1148  rfi->surface = NULL;
    1150  } else if (rfi->surface == NULL) {
    1152  }
    1153 
    1154  /* Send gdi->width and gdi->height obtained from remote server to gp plugin,
    1155  * so they will be saved when closing connection */
    1156  if (width != gdi->width)
    1158  if (height != gdi->height)
    1160 
    1162 
    1164  /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */
    1165  gtk_widget_set_size_request(rfi->drawing_area, -1, -1);
    1166  else
    1167  /* In non scaled mode, the plugins forces dimensions of drawing area */
    1168  gtk_widget_set_size_request(rfi->drawing_area, width, height);
    1170 }
    1171 
    1173 {
    1174  TRACE_CALL(__func__);
    1175  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1176  rdpGdi *gdi;
    1177 
    1178  gdi = ((rdpContext *)rfi)->gdi;
    1179 
    1180  gtk_widget_realize(rfi->drawing_area);
    1181 
    1183  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height);
    1184 
    1186 
    1188  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
    1189  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    1190  REMMINA_PLUGIN_AUDIT(_("Connected to %s via RDP"), host);
    1191 }
    1192 
    1194 {
    1195  TRACE_CALL(__func__);
    1196  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1197 
    1198  gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE);
    1199 }
    1200 
    1202 {
    1203  TRACE_CALL(__func__);
    1204  GdkPixbuf *pixbuf;
    1205  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1206  rdpPointer *pointer = (rdpPointer *)ui->cursor.pointer;
    1207  cairo_surface_t *surface;
    1208  UINT8 *data = malloc(pointer->width * pointer->height * 4);
    1209 
    1210  if (!freerdp_image_copy_from_pointer_data(
    1211  (BYTE *)data, PIXEL_FORMAT_BGRA32,
    1212  pointer->width * 4, 0, 0, pointer->width, pointer->height,
    1213  pointer->xorMaskData, pointer->lengthXorMask,
    1214  pointer->andMaskData, pointer->lengthAndMask,
    1215  pointer->xorBpp, &(ui->cursor.context->gdi->palette))) {
    1216  free(data);
    1217  return FALSE;
    1218  }
    1219 
    1220  surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, pointer->width, pointer->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pointer->width));
    1221  cairo_surface_flush(surface);
    1222  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height);
    1223  cairo_surface_mark_dirty(surface);
    1224  cairo_surface_destroy(surface);
    1225  free(data);
    1226  ((rfPointer *)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos);
    1227  g_object_unref(pixbuf);
    1228 
    1229  return TRUE;
    1230 }
    1231 
    1233 {
    1234  TRACE_CALL(__func__);
    1235  g_object_unref(ui->cursor.pointer->cursor);
    1236  ui->cursor.pointer->cursor = NULL;
    1237 }
    1238 
    1240 {
    1241  TRACE_CALL(__func__);
    1242  GdkWindow *w, *nw;
    1243  gint nx, ny, wx, wy;
    1244 
    1245 #if GTK_CHECK_VERSION(3, 20, 0)
    1246  GdkSeat *seat;
    1247 #else
    1248  GdkDeviceManager *manager;
    1249 #endif
    1250  GdkDevice *dev;
    1251  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1252 
    1253  if (rfi == NULL)
    1254  return FALSE;
    1255 
    1256  w = gtk_widget_get_window(rfi->drawing_area);
    1257 #if GTK_CHECK_VERSION(3, 20, 0)
    1258  seat = gdk_display_get_default_seat(gdk_display_get_default());
    1259  dev = gdk_seat_get_pointer(seat);
    1260 #else
    1261  manager = gdk_display_get_device_manager(gdk_display_get_default());
    1262  dev = gdk_device_manager_get_client_pointer(manager);
    1263 #endif
    1264 
    1265  nw = gdk_device_get_window_at_position(dev, NULL, NULL);
    1266 
    1267  if (nw == w) {
    1268  nx = 0;
    1269  ny = 0;
    1271  gdk_window_get_root_coords(w, nx, ny, &wx, &wy);
    1272  gdk_device_warp(dev, gdk_window_get_screen(w), wx, wy);
    1273  }
    1274  return TRUE;
    1275 }
    1276 
    1278 {
    1279  TRACE_CALL(__func__);
    1280  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1281 
    1282  switch (ui->cursor.type) {
    1284  ui->retval = remmina_rdp_event_create_cursor(gp, ui) ? 1 : 0;
    1285  break;
    1286 
    1289  break;
    1290 
    1292  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), ui->cursor.pointer->cursor);
    1293  ui->retval = 1;
    1294  break;
    1295 
    1297  ui->retval = remmina_rdp_event_set_pointer_position(gp, ui->pos.x, ui->pos.y) ? 1 : 0;
    1298  break;
    1299 
    1301  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area),
    1302  gdk_cursor_new_for_display(gdk_display_get_default(),
    1303  GDK_BLANK_CURSOR));
    1304  ui->retval = 1;
    1305  break;
    1306 
    1308  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), NULL);
    1309  ui->retval = 1;
    1310  break;
    1311  }
    1312 }
    1313 
    1315 {
    1316  TRACE_CALL(__func__);
    1318 }
    1319 
    1321 {
    1322  TRACE_CALL(__func__);
    1323  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1324 
    1325  if (!rfi || !rfi->connected || rfi->is_reconnecting)
    1326  return;
    1328 }
    1329 
    1331 {
    1332  TRACE_CALL(__func__);
    1333  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1334 
    1335  cairo_surface_mark_dirty(rfi->surface);
    1336  cairo_surface_destroy(rfi->surface);
    1337  rfi->surface = NULL;
    1338 }
    1339 
    1341 {
    1342  TRACE_CALL(__func__);
    1343  switch (ui->event.type) {
    1346  break;
    1349  break;
    1350  }
    1351 }
    1352 
    1354 {
    1355  TRACE_CALL(__func__);
    1356  switch (ui->type) {
    1359  break;
    1360 
    1363  break;
    1364 
    1367  break;
    1368 
    1369  case REMMINA_RDP_UI_CURSOR:
    1370  remmina_rdp_event_cursor(gp, ui);
    1371  break;
    1372 
    1375  break;
    1376 
    1377  case REMMINA_RDP_UI_EVENT:
    1379  break;
    1380 
    1381  default:
    1382  break;
    1383  }
    1384 }
    1385 
    1387 {
    1388  TRACE_CALL(__func__);
    1389 
    1390  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1392 
    1393  pthread_mutex_lock(&rfi->ui_queue_mutex);
    1394  ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue);
    1395  if (ui) {
    1396  pthread_mutex_lock(&ui->sync_wait_mutex);
    1397  if (!rfi->thread_cancelled)
    1399  // Should we signal the caller thread to unlock ?
    1400  if (ui->sync) {
    1401  ui->complete = TRUE;
    1402  pthread_cond_signal(&ui->sync_wait_cond);
    1403  pthread_mutex_unlock(&ui->sync_wait_mutex);
    1404  } else {
    1406  }
    1407 
    1408  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1409  return TRUE;
    1410  } else {
    1411  rfi->ui_handler = 0;
    1412  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1413  return FALSE;
    1414  }
    1415 }
    1416 
    1418 {
    1419  TRACE_CALL(__func__);
    1420  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1421  gboolean ui_sync_save;
    1422  int oldcanceltype;
    1423 
    1424  if (!rfi || rfi->thread_cancelled)
    1425  return;
    1426 
    1429  return;
    1430  }
    1431 
    1432  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldcanceltype);
    1433 
    1434  pthread_mutex_lock(&rfi->ui_queue_mutex);
    1435 
    1436  ui_sync_save = ui->sync;
    1437  ui->complete = FALSE;
    1438 
    1439  if (ui_sync_save) {
    1440  pthread_mutex_init(&ui->sync_wait_mutex, NULL);
    1441  pthread_cond_init(&ui->sync_wait_cond, NULL);
    1442  }
    1443 
    1444  ui->complete = FALSE;
    1445 
    1446  g_async_queue_push(rfi->ui_queue, ui);
    1447 
    1448  if (!rfi->ui_handler)
    1449  rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp);
    1450 
    1451  if (ui_sync_save) {
    1452  /* Wait for main thread function completion before returning */
    1453  pthread_mutex_lock(&ui->sync_wait_mutex);
    1454  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1455  while (!ui->complete)
    1456  pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex);
    1457  pthread_cond_destroy(&ui->sync_wait_cond);
    1458  pthread_mutex_destroy(&ui->sync_wait_mutex);
    1459  } else {
    1460  pthread_mutex_unlock(&rfi->ui_queue_mutex);
    1461  }
    1462  pthread_setcanceltype(oldcanceltype, NULL);
    1463 }
    1464 
    1466 {
    1467  ui->sync = FALSE;
    1469 }
    1470 
    1472 {
    1473  TRACE_CALL(__func__);
    1474  int retval;
    1475 
    1476  ui->sync = TRUE;
    1478  retval = ui->retval;
    1480  return retval;
    1481 }
    1482 
    1484 {
    1485  TRACE_CALL(__func__);
    1486  void *rp;
    1487 
    1488  ui->sync = TRUE;
    1490  rp = ui->retptr;
    1492  return rp;
    1493 }
    struct remmina_plugin_rdp_event::@42::@45 mouse_event
    - - -
    gboolean thread_cancelled
    Definition: rdp_plugin.h:332
    - -
    static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1224
    -
    gboolean is_reconnecting
    Definition: rdp_plugin.h:344
    + + +
    gboolean thread_cancelled
    Definition: rdp_plugin.h:333
    + +
    static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1232
    +
    gboolean is_reconnecting
    Definition: rdp_plugin.h:345
    gulong clipboard_handler
    Definition: rdp_plugin.h:140
    -
    static void remmina_rdp_event_create_cairo_surface(rfContext *rfi)
    Definition: rdp_event.c:1095
    +
    static void remmina_rdp_event_create_cairo_surface(rfContext *rfi)
    Definition: rdp_event.c:1103
    RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
    Definition: plugin.h:172
    -
    static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1332
    -
    guint delayed_monitor_layout_handler
    Definition: rdp_plugin.h:360
    +
    static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1340
    +
    guint delayed_monitor_layout_handler
    Definition: rdp_plugin.h:361
    struct remmina_plugin_rdp_ui_object::@50::@53 cursor
    -
    static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:312
    - - -
    gint event_pipe[2]
    Definition: rdp_plugin.h:381
    -
    gdouble scale_y
    Definition: rdp_plugin.h:359
    - +
    static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:313
    + + +
    gint event_pipe[2]
    Definition: rdp_plugin.h:382
    +
    gdouble scale_y
    Definition: rdp_plugin.h:360
    +
    gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:74
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    -
    cairo_surface_t * surface
    Definition: rdp_plugin.h:366
    -
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:341
    +
    cairo_surface_t * surface
    Definition: rdp_plugin.h:367
    +
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:342
    struct remmina_plugin_rdp_ui_object::@50::@52 reg
    void(* protocol_plugin_set_width)(RemminaProtocolWidget *gp, gint width)
    Definition: plugin.h:169
    - -
    guint ui_handler
    Definition: rdp_plugin.h:377
    + +
    guint ui_handler
    Definition: rdp_plugin.h:378
    void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
    Definition: rdp_settings.c:707
    - +
    void remmina_rdp_clipboard_abort_client_format_data_request(rfContext *rfi)
    Definition: rdp_cliprdr.c:947
    - -
    GdkDisplay * display
    Definition: rdp_plugin.h:364
    -
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1475
    + +
    GdkDisplay * display
    Definition: rdp_plugin.h:365
    +
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1483
    struct remmina_plugin_rdp_event::@42::@49 monitor_layout
    -
    GAsyncQueue * ui_queue
    Definition: rdp_plugin.h:375
    -
    void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    Definition: rdp_event.c:301
    -
    pthread_mutex_t sync_wait_mutex
    Definition: rdp_plugin.h:269
    - -
    int reconnect_nattempt
    Definition: rdp_plugin.h:352
    -
    static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1378
    -
    static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1193
    +
    GAsyncQueue * ui_queue
    Definition: rdp_plugin.h:376
    +
    void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    Definition: rdp_event.c:302
    +
    pthread_mutex_t sync_wait_mutex
    Definition: rdp_plugin.h:270
    + +
    int reconnect_nattempt
    Definition: rdp_plugin.h:353
    +
    static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1386
    +
    static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1201
    static void remmina_rdp_event_release_key(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
    Definition: rdp_event.c:195
    -
    static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1409
    - +
    static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1417
    +
    gint(* protocol_plugin_get_width)(RemminaProtocolWidget *gp)
    Definition: plugin.h:168
    - -
    gdouble scale_x
    Definition: rdp_plugin.h:358
    + +
    gdouble scale_x
    Definition: rdp_plugin.h:359
    gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
    Definition: plugin.h:222
    -
    static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:766
    -
    void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
    Definition: rdp_event.c:1028
    -
    static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:579
    +
    static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:767
    +
    void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
    Definition: rdp_event.c:1036
    +
    static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:580
    void(* protocol_plugin_update_align)(RemminaProtocolWidget *gp)
    Definition: plugin.h:187
    void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
    Definition: plugin.h:186
    void remmina_rdp_event_process_clipboard(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_cliprdr.c:914
    -
    int reconnect_maxattempts
    Definition: rdp_plugin.h:351
    -
    static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1306
    +
    int reconnect_maxattempts
    Definition: rdp_plugin.h:352
    +
    static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1314
    static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:104
    RemminaPluginRdpEventType type
    Definition: rdp_plugin.h:191
    -
    UINT16 last_x
    Definition: rdp_plugin.h:383
    +
    UINT16 last_x
    Definition: rdp_plugin.h:384
    -
    void remmina_rdp_event_update_regions(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:281
    -
    static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:392
    - - +
    void remmina_rdp_event_update_regions(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:282
    +
    static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:393
    + +
    static RemminaPluginService * remmina_plugin_service
    -
    unsigned translated_keycode
    Definition: rdp_plugin.h:316
    -
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:355
    -
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:367
    -
    static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:498
    -
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1463
    -
    void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:912
    -
    gboolean use_client_keymap
    Definition: rdp_plugin.h:361
    -
    static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:676
    +
    unsigned translated_keycode
    Definition: rdp_plugin.h:317
    +
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:356
    +
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:368
    +
    static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:499
    +
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1471
    +
    void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:920
    +
    gboolean use_client_keymap
    Definition: rdp_plugin.h:362
    +
    static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:677
    gchar *(* pref_get_value)(const gchar *key)
    Definition: plugin.h:227
    -
    static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1185
    +
    static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1193
    -
    GArray * keymap
    Definition: rdp_plugin.h:388
    -
    UINT16 last_y
    Definition: rdp_plugin.h:384
    -
    unsigned orig_keycode
    Definition: rdp_plugin.h:315
    -
    static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
    Definition: rdp_event.c:236
    +
    GArray * keymap
    Definition: rdp_plugin.h:389
    +
    UINT16 last_y
    Definition: rdp_plugin.h:385
    +
    unsigned orig_keycode
    Definition: rdp_plugin.h:316
    +
    static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
    Definition: rdp_event.c:237
    -
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1457
    -
    static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:605
    +
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1465
    +
    static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:606
    struct remmina_plugin_rdp_event::@42::@44 key_event
    - +
    struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
    gint(* protocol_plugin_get_height)(RemminaProtocolWidget *gp)
    Definition: plugin.h:170
    -
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:483
    -
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:380
    +
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:484
    +
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:381
    static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:174
    CLIPRDR_FORMAT_LIST * remmina_rdp_cliprdr_get_client_format_list(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:709
    -
    pthread_cond_t sync_wait_cond
    Definition: rdp_plugin.h:270
    -
    rfClipboard clipboard
    Definition: rdp_plugin.h:386
    -
    static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
    Definition: rdp_event.c:732
    -
    HANDLE event_handle
    Definition: rdp_plugin.h:382
    -
    static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
    Definition: rdp_event.c:517
    -
    static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1322
    -
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1044
    +
    pthread_cond_t sync_wait_cond
    Definition: rdp_plugin.h:271
    +
    rfClipboard clipboard
    Definition: rdp_plugin.h:387
    +
    static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
    Definition: rdp_event.c:733
    +
    HANDLE event_handle
    Definition: rdp_plugin.h:383
    +
    static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
    Definition: rdp_event.c:518
    +
    static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1330
    +
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1052
    -
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:561
    +
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:562
    RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
    Definition: plugin.h:178
    - -
    GHashTable * object_table
    Definition: rdp_plugin.h:373
    -
    gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:873
    -
    static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
    Definition: rdp_event.c:539
    - -
    static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1345
    -
    static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
    Definition: rdp_event.c:221
    -
    gboolean connected
    Definition: rdp_plugin.h:343
    - -
    RemminaScaleMode scale
    Definition: rdp_plugin.h:330
    -
    freerdp * instance
    Definition: rdp_plugin.h:327
    + +
    GHashTable * object_table
    Definition: rdp_plugin.h:374
    +
    gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:881
    +
    static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
    Definition: rdp_event.c:540
    + +
    static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1353
    +
    static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
    Definition: rdp_event.c:222
    +
    gboolean connected
    Definition: rdp_plugin.h:344
    + +
    RemminaScaleMode scale
    Definition: rdp_plugin.h:331
    +
    freerdp * instance
    Definition: rdp_plugin.h:328
    -
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:335
    -
    static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gint x, gint y)
    Definition: rdp_event.c:1231
    +
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:336
    +
    static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gint x, gint y)
    Definition: rdp_event.c:1239
    void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
    Definition: plugin.h:180
    -
    static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1164
    -
    GArray * pressed_keys
    Definition: rdp_plugin.h:379
    -
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1118
    -
    rdpSettings * settings
    Definition: rdp_plugin.h:326
    -
    gint scale_height
    Definition: rdp_plugin.h:357
    +
    static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1172
    +
    GArray * pressed_keys
    Definition: rdp_plugin.h:380
    +
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1126
    +
    rdpSettings * settings
    Definition: rdp_plugin.h:327
    +
    gint scale_height
    Definition: rdp_plugin.h:358
    void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
    Definition: plugin.h:171
    -
    Definition: rdp_plugin.h:314
    -
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1312
    +
    Definition: rdp_plugin.h:315
    +
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1320
    struct remmina_plugin_rdp_ui_object::@50::@55 nocodec
    @@ -224,17 +224,17 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
    void remmina_rdp_monitor_get(rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
    Set the MonitorIDs, the maxwidth and maxheight.
    Definition: rdp_monitor.c:68
    void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
    Definition: rdp_event.c:150
    - -
    static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1269
    + +
    static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1277
    gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:52
    struct remmina_plugin_rdp_ui_object::@50::@58 pos
    gboolean(* is_main_thread)(void)
    Definition: plugin.h:250
    -
    static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:343
    -
    gint scale_width
    Definition: rdp_plugin.h:356
    -
    pthread_mutex_t ui_queue_mutex
    Definition: rdp_plugin.h:376
    -
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:266
    - - +
    static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
    Definition: rdp_event.c:344
    +
    gint scale_width
    Definition: rdp_plugin.h:357
    +
    pthread_mutex_t ui_queue_mutex
    Definition: rdp_plugin.h:377
    +
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:267
    + +
    diff --git a/public/rdp__event_8h.html b/public/rdp__event_8h.html index ac09de5d6..7b08b56b3 100644 --- a/public/rdp__event_8h.html +++ b/public/rdp__event_8h.html @@ -136,7 +136,7 @@ Functions

    Fixme: This comment needed for TS_SUPPRESS_OUTPUT_PDU But it works only when we stay in the same window mode, if we switch to fullscreen, for instance, the object refernce is lost, so we loose these events.

    -

    Definition at line 912 of file rdp_event.c.

    +

    Definition at line 920 of file rdp_event.c.

    @@ -206,7 +206,7 @@ Functions
    -

    Definition at line 1457 of file rdp_event.c.

    +

    Definition at line 1465 of file rdp_event.c.

    @@ -236,7 +236,7 @@ Functions
    -

    Definition at line 1463 of file rdp_event.c.

    +

    Definition at line 1471 of file rdp_event.c.

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

    Definition at line 1475 of file rdp_event.c.

    +

    Definition at line 1483 of file rdp_event.c.

    @@ -286,7 +286,7 @@ Functions
    -

    Definition at line 483 of file rdp_event.c.

    +

    Definition at line 484 of file rdp_event.c.

    @@ -306,7 +306,7 @@ Functions
    -

    Definition at line 1312 of file rdp_event.c.

    +

    Definition at line 1320 of file rdp_event.c.

    @@ -326,7 +326,7 @@ Functions
    -

    Definition at line 1044 of file rdp_event.c.

    +

    Definition at line 1052 of file rdp_event.c.

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

    Definition at line 301 of file rdp_event.c.

    +

    Definition at line 302 of file rdp_event.c.

    @@ -394,7 +394,7 @@ Functions
    -

    Definition at line 1118 of file rdp_event.c.

    +

    Definition at line 1126 of file rdp_event.c.

    @@ -414,7 +414,7 @@ Functions
    -

    Definition at line 561 of file rdp_event.c.

    +

    Definition at line 562 of file rdp_event.c.

    diff --git a/public/rdp__event_8h_source.html b/public/rdp__event_8h_source.html index 3b0330210..4dcd32c57 100644 --- a/public/rdp__event_8h_source.html +++ b/public/rdp__event_8h_source.html @@ -86,22 +86,22 @@ $(document).ready(function(){initNavTree('rdp__event_8h_source.html','');});
    rdp_event.h
    -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) 2017-2023 Antenore Gatta, Giovanni Panozzo
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    19  * Boston, MA 02110-1301, USA.
    20  *
    21  * In addition, as a special exception, the copyright holders give
    22  * permission to link the code of portions of this program with the
    23  * OpenSSL library under certain conditions as described in each
    24  * individual source file, and distribute linked combinations
    25  * including the two.
    26  * You must obey the GNU General Public License in all respects
    27  * for all of the code used other than OpenSSL. * If you modify
    28  * file(s) with this exception, you may extend this exception to your
    29  * version of the file(s), but you are not obligated to do so. * If you
    30  * do not wish to do so, delete this exception statement from your
    31  * version. * If you delete this exception statement from all source
    32  * files in the program, then also delete it here.
    33  *
    34  */
    35 
    36 #pragma once
    37 
    38 #include <glib.h>
    39 #include "common/remmina_plugin.h"
    40 #include "rdp_plugin.h"
    41 
    42 G_BEGIN_DECLS
    43 
    44 
    50 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h);
    57 
    58 G_END_DECLS
    void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    Definition: rdp_event.c:301
    -
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1312
    - +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) 2017-2023 Antenore Gatta, Giovanni Panozzo
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    19  * Boston, MA 02110-1301, USA.
    20  *
    21  * In addition, as a special exception, the copyright holders give
    22  * permission to link the code of portions of this program with the
    23  * OpenSSL library under certain conditions as described in each
    24  * individual source file, and distribute linked combinations
    25  * including the two.
    26  * You must obey the GNU General Public License in all respects
    27  * for all of the code used other than OpenSSL. * If you modify
    28  * file(s) with this exception, you may extend this exception to your
    29  * version of the file(s), but you are not obligated to do so. * If you
    30  * do not wish to do so, delete this exception statement from your
    31  * version. * If you delete this exception statement from all source
    32  * files in the program, then also delete it here.
    33  *
    34  */
    35 
    36 #pragma once
    37 
    38 #include <glib.h>
    39 #include "common/remmina_plugin.h"
    40 #include "rdp_plugin.h"
    41 
    42 G_BEGIN_DECLS
    43 
    44 
    50 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h);
    57 
    58 G_END_DECLS
    void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
    Definition: rdp_event.c:302
    +
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1320
    + -
    G_BEGIN_DECLS void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:912
    -
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1118
    -
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1463
    +
    G_BEGIN_DECLS void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:920
    +
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1126
    +
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1471
    -
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1044
    -
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:561
    -
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1457
    +
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1052
    +
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:562
    +
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1465
    gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:74
    -
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:483
    +
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:484
    gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:52
    -
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1475
    +
    void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1483
    diff --git a/public/rdp__graphics_8c_source.html b/public/rdp__graphics_8c_source.html index 4380f01b4..48ccac091 100644 --- a/public/rdp__graphics_8c_source.html +++ b/public/rdp__graphics_8c_source.html @@ -86,52 +86,52 @@ $(document).ready(function(){initNavTree('rdp__graphics_8c_source.html','');});
    rdp_graphics.c
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2010 Jay Sorg
    4  * Copyright (C) 2010-2011 Vic Lee
    5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
    6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    7  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    8  *
    9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    22  * Boston, MA 02110-1301, USA.
    23  *
    24  * In addition, as a special exception, the copyright holders give
    25  * permission to link the code of portions of this program with the
    26  * OpenSSL library under certain conditions as described in each
    27  * individual source file, and distribute linked combinations
    28  * including the two.
    29  * You must obey the GNU General Public License in all respects
    30  * for all of the code used other than OpenSSL. * If you modify
    31  * file(s) with this exception, you may extend this exception to your
    32  * version of the file(s), but you are not obligated to do so. * If you
    33  * do not wish to do so, delete this exception statement from your
    34  * version. * If you delete this exception statement from all source
    35  * files in the program, then also delete it here.
    36  *
    37  */
    38 
    39 #include "rdp_plugin.h"
    40 #include "rdp_event.h"
    41 #include "rdp_graphics.h"
    42 
    43 #include <freerdp/codec/color.h>
    44 #include <freerdp/codec/bitmap.h>
    45 #include <winpr/memory.h>
    46 
    47 //#define RF_BITMAP
    48 //#define RF_GLYPH
    49 
    50 /* Bitmap Class */
    51 
    52 BOOL rf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
    53 {
    54  TRACE_CALL(__func__);
    55 #ifdef RF_BITMAP
    56  UINT8* data;
    57  Pixmap pixmap;
    58  XImage* image;
    59  rfContext* rfi = (rfContext*)context;
    60 
    61  XSetFunction(rfi->display, rfi->gc, GXcopy);
    62  pixmap = XCreatePixmap(rfi->display, rfi->drawable, bitmap->width, bitmap->height, rfi->depth);
    63 
    64  if (bitmap->data != NULL) {
    65  data = freerdp_image_convert(bitmap->data, NULL,
    66  bitmap->width, bitmap->height, rfi->srcBpp, rfi->bpp, rfi->clrconv);
    67 
    68  if (bitmap->ephemeral != TRUE) {
    69  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
    70  ZPixmap, 0, (char*)data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
    71 
    72  XPutImage(rfi->display, pixmap, rfi->gc, image, 0, 0, 0, 0, bitmap->width, bitmap->height);
    73  XFree(image);
    74 
    75  if (data != bitmap->data) && (data != NULL)
    76  free(data);
    77  }else {
    78  if (data != bitmap->data) && (data != NULL)
    79  free(bitmap->data);
    80 
    81  bitmap->data = data;
    82  }
    83  }
    84 
    85  ((rfBitmap*)bitmap)->pixmap = pixmap;
    86 #endif
    87  return TRUE;
    88 }
    89 
    90 void rf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
    91 {
    92  TRACE_CALL(__func__);
    93 #ifdef RF_BITMAP
    94  rfContext* rfi = (rfContext*)context;
    95 
    96  printf("rf_Bitmap_Free\n");
    97 
    98  if (((rfBitmap*)bitmap)->pixmap != 0)
    99  XFreePixmap(rfi->display, ((rfBitmap*)bitmap)->pixmap);
    100 #endif
    101 }
    102 
    103 BOOL rf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
    104 {
    105  TRACE_CALL(__func__);
    106 #ifdef RF_BITMAP
    107  XImage* image;
    108  int width, height;
    109  rfContext* rfi = (rfContext*)context;
    110 
    111  printf("rf_Bitmap_Paint\n");
    112 
    113  width = bitmap->right - bitmap->left + 1;
    114  height = bitmap->bottom - bitmap->top + 1;
    115 
    116  XSetFunction(rfi->display, rfi->gc, GXcopy);
    117 
    118  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
    119  ZPixmap, 0, (char*)bitmap->data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
    120 
    121  XPutImage(rfi->display, rfi->primary, rfi->gc,
    122  image, 0, 0, bitmap->left, bitmap->top, width, height);
    123 
    124  XFree(image);
    125 
    126  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc,
    127  // bitmap->left, bitmap->top, width, height, bitmap->left, bitmap->top);
    128 
    129  //gdi_InvalidateRegion(rfi->hdc, bitmap->left, bitmap->top, width, height);
    130 #endif
    131  return FALSE;
    132 }
    133 
    134 BOOL rf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
    135  const BYTE* data, UINT32 width, UINT32 height, UINT32 bpp, UINT32 length, BOOL compressed, UINT32 codec_id)
    136 {
    137  TRACE_CALL(__func__);
    138 #ifdef RF_BITMAP
    139  UINT16 size;
    140 
    141  printf("rf_Bitmap_Decompress\n");
    142 
    143  size = width * height * (bpp + 7) / 8;
    144 
    145  if (bitmap->data == NULL)
    146  bitmap->data = (UINT8*)xmalloc(size);
    147  else
    148  bitmap->data = (UINT8*)xrealloc(bitmap->data, size);
    149 
    150  if (compressed) {
    151  BOOL status;
    152 
    153  status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp);
    154 
    155  if (status != TRUE) {
    156  printf("Bitmap Decompression Failed\n");
    157  }
    158  }else {
    159  freerdp_image_flip(data, bitmap->data, width, height, bpp);
    160  }
    161 
    162  bitmap->compressed = FALSE;
    163  bitmap->length = size;
    164  bitmap->bpp = bpp;
    165 #endif
    166  return TRUE;
    167 }
    168 
    169 BOOL rf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
    170 {
    171  TRACE_CALL(__func__);
    172 #ifdef RF_BITMAP
    173  rfContext* rfi = (rfContext*)context;
    174 
    175  if (primary)
    176  rfi->drawing = rfi->primary;
    177  else
    178  rfi->drawing = ((rfBitmap*)bitmap)->pixmap;
    179 #endif
    180  return TRUE;
    181 }
    182 
    183 /* Pointer Class */
    184 
    185 BOOL rf_Pointer_New(rdpContext* context, rdpPointer* pointer)
    186 {
    187  TRACE_CALL(__func__);
    189  rfContext* rfi = (rfContext*)context;
    190 
    191  if (pointer->xorMaskData != 0) {
    192  ui = g_new0(RemminaPluginRdpUiObject, 1);
    194  ui->cursor.context = context;
    195  ui->cursor.pointer = (rfPointer*)pointer;
    196  ui->cursor.type = REMMINA_RDP_POINTER_NEW;
    197  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    198  }
    199  return FALSE;
    200 }
    201 
    202 void rf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
    203 {
    204  TRACE_CALL(__func__);
    206  rfContext* rfi = (rfContext*)context;
    207 
    208  if (G_IS_OBJECT(((rfPointer*)pointer)->cursor))
    209  {
    210  ui = g_new0(RemminaPluginRdpUiObject, 1);
    212  ui->cursor.context = context;
    213  ui->cursor.pointer = (rfPointer*)pointer;
    214  ui->cursor.type = REMMINA_RDP_POINTER_FREE;
    216  }
    217 }
    218 
    219 BOOL rf_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
    220 {
    221  TRACE_CALL(__func__);
    223  rfContext* rfi = (rfContext*)context;
    224 
    225  ui = g_new0(RemminaPluginRdpUiObject, 1);
    227  ui->cursor.pointer = (rfPointer*)pointer;
    228  ui->cursor.type = REMMINA_RDP_POINTER_SET;
    229 
    230  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    231 
    232 }
    233 
    234 BOOL rf_Pointer_SetNull(rdpContext* context)
    235 {
    236  TRACE_CALL(__func__);
    238  rfContext* rfi = (rfContext*)context;
    239 
    240  ui = g_new0(RemminaPluginRdpUiObject, 1);
    242  ui->cursor.type = REMMINA_RDP_POINTER_NULL;
    243 
    244  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    245 }
    246 
    247 BOOL rf_Pointer_SetDefault(rdpContext* context)
    248 {
    249  TRACE_CALL(__func__);
    251  rfContext* rfi = (rfContext*)context;
    252 
    253  ui = g_new0(RemminaPluginRdpUiObject, 1);
    256 
    257  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    258 }
    259 
    260 BOOL rf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
    261 {
    262  TRACE_CALL(__func__);
    264  rfContext* rfi = (rfContext*)context;
    265  ui = g_new0(RemminaPluginRdpUiObject, 1);
    268  ui->pos.x = x;
    269  ui->pos.y = y;
    270 
    271  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    272 }
    273 
    274 /* Glyph Class */
    275 
    276 BOOL rf_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
    277 {
    278  TRACE_CALL(__func__);
    279 #ifdef RF_GLYPH
    280  int scanline;
    281  XImage* image;
    282  rfContext* rfi;
    283  rfGlyph* rf_glyph;
    284 
    285  rf_glyph = (rfGlyph*)glyph;
    286  rfi = (rfContext*)context;
    287 
    288  scanline = (glyph->cx + 7) / 8;
    289 
    290  rf_glyph->pixmap = XCreatePixmap(rfi->display, rfi->drawing, glyph->cx, glyph->cy, 1);
    291 
    292  image = XCreateImage(rfi->display, rfi->visual, 1,
    293  ZPixmap, 0, (char*)glyph->aj, glyph->cx, glyph->cy, 8, scanline);
    294 
    295  image->byte_order = MSBFirst;
    296  image->bitmap_bit_order = MSBFirst;
    297 
    298  XInitImage(image);
    299  XPutImage(rfi->display, rf_glyph->pixmap, rfi->gc_mono, image, 0, 0, 0, 0, glyph->cx, glyph->cy);
    300  XFree(image);
    301 #endif
    302  return TRUE;
    303 }
    304 
    305 void rf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
    306 {
    307  TRACE_CALL(__func__);
    308 #ifdef RF_GLYPH
    309  rfContext* rfi = (rfContext*)context;
    310 
    311  if (((rfGlyph*)glyph)->pixmap != 0)
    312  XFreePixmap(rfi->display, ((rfGlyph*)glyph)->pixmap);
    313 #endif
    314 }
    315 
    316 static BOOL rf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x,
    317  INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy,
    318  BOOL fOpRedundant)
    319 {
    320  TRACE_CALL(__func__);
    321 #ifdef RF_GLYPH
    322  rfGlyph* rf_glyph;
    323  rfContext* rfi = (rfContext*)context;
    324 
    325  rf_glyph = (rfGlyph*)glyph;
    326 
    327  XSetStipple(rfi->display, rfi->gc, rf_glyph->pixmap);
    328  XSetTSOrigin(rfi->display, rfi->gc, x, y);
    329  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, glyph->cx, glyph->cy);
    330  XSetStipple(rfi->display, rfi->gc, rfi->bitmap_mono);
    331 #endif
    332  return TRUE;
    333 }
    334 
    335 static BOOL rf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y,
    336  INT32 width, INT32 height, UINT32 bgcolor,
    337  UINT32 fgcolor, BOOL fOpRedundant)
    338 {
    339  TRACE_CALL(__func__);
    340 #ifdef RF_GLYPH
    341  rfContext* rfi = (rfContext*)context;
    342 
    343  bgcolor = (rfi->clrconv->invert) ?
    344  freerdp_color_convert_var_bgr(bgcolor, rfi->srcBpp, 32, rfi->clrconv) :
    345  freerdp_color_convert_var_rgb(bgcolor, rfi->srcBpp, 32, rfi->clrconv);
    346 
    347  fgcolor = (rfi->clrconv->invert) ?
    348  freerdp_color_convert_var_bgr(fgcolor, rfi->srcBpp, 32, rfi->clrconv) :
    349  freerdp_color_convert_var_rgb(fgcolor, rfi->srcBpp, 32, rfi->clrconv);
    350 
    351  XSetFunction(rfi->display, rfi->gc, GXcopy);
    352  XSetFillStyle(rfi->display, rfi->gc, FillSolid);
    353  XSetForeground(rfi->display, rfi->gc, fgcolor);
    354  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, width, height);
    355 
    356  XSetForeground(rfi->display, rfi->gc, bgcolor);
    357  XSetBackground(rfi->display, rfi->gc, fgcolor);
    358  XSetFillStyle(rfi->display, rfi->gc, FillStippled);
    359 #endif
    360  return TRUE;
    361 }
    362 
    363 static BOOL rf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y,
    364  INT32 width, INT32 height,
    365  UINT32 bgcolor, UINT32 fgcolor)
    366 {
    367  TRACE_CALL(__func__);
    368 #ifdef RF_GLYPH
    369  rfContext* rfi = (rfContext*)context;
    370 
    371  if (rfi->drawing == rfi->primary) {
    372  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc, x, y, width, height, x, y);
    373  //gdi_InvalidateRegion(rfi->hdc, x, y, width, height);
    374  }
    375 #endif
    376  return TRUE;
    377 }
    378 
    379 /* Graphics Module */
    380 
    381 void rf_register_graphics(rdpGraphics* graphics)
    382 {
    383  TRACE_CALL(__func__);
    384  rdpBitmap* bitmap;
    385  rdpPointer* pointer;
    386  rdpGlyph* glyph;
    387 
    388  bitmap = (rdpBitmap*)malloc(sizeof(rdpBitmap));
    389  ZeroMemory(bitmap, sizeof(rdpBitmap));
    390 #ifdef RF_BITMAP
    391  bitmap->size = sizeof(rfBitmap);
    392 #else
    393  bitmap->size = 0;
    394 #endif
    395 
    396  bitmap->New = rf_Bitmap_New;
    397  bitmap->Free = rf_Bitmap_Free;
    398  bitmap->Paint = rf_Bitmap_Paint;
    399  bitmap->Decompress = rf_Bitmap_Decompress;
    400  bitmap->SetSurface = rf_Bitmap_SetSurface;
    401 
    402  graphics_register_bitmap(graphics, bitmap);
    403  free(bitmap);
    404 
    405  pointer = (rdpPointer*)malloc(sizeof(rdpPointer));
    406  ZeroMemory(pointer, sizeof(rdpPointer));
    407 
    408  pointer->size = sizeof(rfPointer);
    409 
    410  pointer->New = rf_Pointer_New;
    411  pointer->Free = rf_Pointer_Free;
    412  pointer->Set = rf_Pointer_Set;
    413  pointer->SetNull = rf_Pointer_SetNull;
    414  pointer->SetDefault = rf_Pointer_SetDefault;
    415  pointer->SetPosition = rf_Pointer_SetPosition;
    416 
    417  graphics_register_pointer(graphics, pointer);
    418 
    419  free(pointer);
    420 
    421  glyph = (rdpGlyph*)malloc(sizeof(rdpGlyph));
    422  ZeroMemory(glyph, sizeof(rdpGlyph));
    423 
    424 #ifdef RF_GLYPH
    425  glyph->size = sizeof(rfGlyph);
    426 #else
    427  glyph->size = 0;
    428 #endif
    429 
    430  glyph->New = rf_Glyph_New;
    431  glyph->Free = rf_Glyph_Free;
    432  glyph->Draw = rf_Glyph_Draw;
    433  glyph->BeginDraw = rf_Glyph_BeginDraw;
    434  glyph->EndDraw = rf_Glyph_EndDraw;
    435 
    436  graphics_register_glyph(graphics, glyph);
    437 
    438  free(glyph);
    439 }
    - +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2010 Jay Sorg
    4  * Copyright (C) 2010-2011 Vic Lee
    5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
    6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
    7  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
    8  *
    9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    22  * Boston, MA 02110-1301, USA.
    23  *
    24  * In addition, as a special exception, the copyright holders give
    25  * permission to link the code of portions of this program with the
    26  * OpenSSL library under certain conditions as described in each
    27  * individual source file, and distribute linked combinations
    28  * including the two.
    29  * You must obey the GNU General Public License in all respects
    30  * for all of the code used other than OpenSSL. * If you modify
    31  * file(s) with this exception, you may extend this exception to your
    32  * version of the file(s), but you are not obligated to do so. * If you
    33  * do not wish to do so, delete this exception statement from your
    34  * version. * If you delete this exception statement from all source
    35  * files in the program, then also delete it here.
    36  *
    37  */
    38 
    39 #include "rdp_plugin.h"
    40 #include "rdp_event.h"
    41 #include "rdp_graphics.h"
    42 
    43 #include <freerdp/codec/color.h>
    44 #include <freerdp/codec/bitmap.h>
    45 #include <winpr/memory.h>
    46 
    47 //#define RF_BITMAP
    48 //#define RF_GLYPH
    49 
    50 /* Bitmap Class */
    51 
    52 BOOL rf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
    53 {
    54  TRACE_CALL(__func__);
    55 #ifdef RF_BITMAP
    56  UINT8* data;
    57  Pixmap pixmap;
    58  XImage* image;
    59  rfContext* rfi = (rfContext*)context;
    60 
    61  XSetFunction(rfi->display, rfi->gc, GXcopy);
    62  pixmap = XCreatePixmap(rfi->display, rfi->drawable, bitmap->width, bitmap->height, rfi->depth);
    63 
    64  if (bitmap->data != NULL) {
    65  data = freerdp_image_convert(bitmap->data, NULL,
    66  bitmap->width, bitmap->height, rfi->srcBpp, rfi->bpp, rfi->clrconv);
    67 
    68  if (bitmap->ephemeral != TRUE) {
    69  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
    70  ZPixmap, 0, (char*)data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
    71 
    72  XPutImage(rfi->display, pixmap, rfi->gc, image, 0, 0, 0, 0, bitmap->width, bitmap->height);
    73  XFree(image);
    74 
    75  if (data != bitmap->data) && (data != NULL)
    76  free(data);
    77  }else {
    78  if (data != bitmap->data) && (data != NULL)
    79  free(bitmap->data);
    80 
    81  bitmap->data = data;
    82  }
    83  }
    84 
    85  ((rfBitmap*)bitmap)->pixmap = pixmap;
    86 #endif
    87  return TRUE;
    88 }
    89 
    90 void rf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
    91 {
    92  TRACE_CALL(__func__);
    93 #ifdef RF_BITMAP
    94  rfContext* rfi = (rfContext*)context;
    95 
    96  printf("rf_Bitmap_Free\n");
    97 
    98  if (((rfBitmap*)bitmap)->pixmap != 0)
    99  XFreePixmap(rfi->display, ((rfBitmap*)bitmap)->pixmap);
    100 #endif
    101 }
    102 
    103 BOOL rf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
    104 {
    105  TRACE_CALL(__func__);
    106 #ifdef RF_BITMAP
    107  XImage* image;
    108  int width, height;
    109  rfContext* rfi = (rfContext*)context;
    110 
    111  printf("rf_Bitmap_Paint\n");
    112 
    113  width = bitmap->right - bitmap->left + 1;
    114  height = bitmap->bottom - bitmap->top + 1;
    115 
    116  XSetFunction(rfi->display, rfi->gc, GXcopy);
    117 
    118  image = XCreateImage(rfi->display, rfi->visual, rfi->depth,
    119  ZPixmap, 0, (char*)bitmap->data, bitmap->width, bitmap->height, rfi->scanline_pad, 0);
    120 
    121  XPutImage(rfi->display, rfi->primary, rfi->gc,
    122  image, 0, 0, bitmap->left, bitmap->top, width, height);
    123 
    124  XFree(image);
    125 
    126  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc,
    127  // bitmap->left, bitmap->top, width, height, bitmap->left, bitmap->top);
    128 
    129  //gdi_InvalidateRegion(rfi->hdc, bitmap->left, bitmap->top, width, height);
    130 #endif
    131  return FALSE;
    132 }
    133 
    134 BOOL rf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
    135  const BYTE* data, UINT32 width, UINT32 height, UINT32 bpp, UINT32 length, BOOL compressed, UINT32 codec_id)
    136 {
    137  TRACE_CALL(__func__);
    138 #ifdef RF_BITMAP
    139  UINT16 size;
    140 
    141  printf("rf_Bitmap_Decompress\n");
    142 
    143  size = width * height * (bpp + 7) / 8;
    144 
    145  if (bitmap->data == NULL)
    146  bitmap->data = (UINT8*)xmalloc(size);
    147  else
    148  bitmap->data = (UINT8*)xrealloc(bitmap->data, size);
    149 
    150  if (compressed) {
    151  BOOL status;
    152 
    153  status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp);
    154 
    155  if (status != TRUE) {
    156  printf("Bitmap Decompression Failed\n");
    157  }
    158  }else {
    159  freerdp_image_flip(data, bitmap->data, width, height, bpp);
    160  }
    161 
    162  bitmap->compressed = FALSE;
    163  bitmap->length = size;
    164  bitmap->bpp = bpp;
    165 #endif
    166  return TRUE;
    167 }
    168 
    169 BOOL rf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
    170 {
    171  TRACE_CALL(__func__);
    172 #ifdef RF_BITMAP
    173  rfContext* rfi = (rfContext*)context;
    174 
    175  if (primary)
    176  rfi->drawing = rfi->primary;
    177  else
    178  rfi->drawing = ((rfBitmap*)bitmap)->pixmap;
    179 #endif
    180  return TRUE;
    181 }
    182 
    183 /* Pointer Class */
    184 
    185 BOOL rf_Pointer_New(rdpContext* context, rdpPointer* pointer)
    186 {
    187  TRACE_CALL(__func__);
    189  rfContext* rfi = (rfContext*)context;
    190 
    191  if (pointer->xorMaskData != 0) {
    192  ui = g_new0(RemminaPluginRdpUiObject, 1);
    194  ui->cursor.context = context;
    195  ui->cursor.pointer = (rfPointer*)pointer;
    196  ui->cursor.type = REMMINA_RDP_POINTER_NEW;
    197  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    198  }
    199  return FALSE;
    200 }
    201 
    202 void rf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
    203 {
    204  TRACE_CALL(__func__);
    206  rfContext* rfi = (rfContext*)context;
    207 
    208  if (G_IS_OBJECT(((rfPointer*)pointer)->cursor))
    209  {
    210  ui = g_new0(RemminaPluginRdpUiObject, 1);
    212  ui->cursor.context = context;
    213  ui->cursor.pointer = (rfPointer*)pointer;
    214  ui->cursor.type = REMMINA_RDP_POINTER_FREE;
    216  }
    217 }
    218 
    219 BOOL rf_Pointer_Set(rdpContext* context, const rdpPointer* pointer)
    220 {
    221  TRACE_CALL(__func__);
    223  rfContext* rfi = (rfContext*)context;
    224 
    225  ui = g_new0(RemminaPluginRdpUiObject, 1);
    227  ui->cursor.pointer = (rfPointer*)pointer;
    228  ui->cursor.type = REMMINA_RDP_POINTER_SET;
    229 
    230  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    231 
    232 }
    233 
    234 BOOL rf_Pointer_SetNull(rdpContext* context)
    235 {
    236  TRACE_CALL(__func__);
    238  rfContext* rfi = (rfContext*)context;
    239 
    240  ui = g_new0(RemminaPluginRdpUiObject, 1);
    242  ui->cursor.type = REMMINA_RDP_POINTER_NULL;
    243 
    244  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    245 }
    246 
    247 BOOL rf_Pointer_SetDefault(rdpContext* context)
    248 {
    249  TRACE_CALL(__func__);
    251  rfContext* rfi = (rfContext*)context;
    252 
    253  ui = g_new0(RemminaPluginRdpUiObject, 1);
    256 
    257  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    258 }
    259 
    260 BOOL rf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
    261 {
    262  TRACE_CALL(__func__);
    264  rfContext* rfi = (rfContext*)context;
    265  ui = g_new0(RemminaPluginRdpUiObject, 1);
    268  ui->pos.x = x;
    269  ui->pos.y = y;
    270 
    271  return remmina_rdp_event_queue_ui_sync_retint(rfi->protocol_widget, ui) ? TRUE : FALSE;
    272 }
    273 
    274 /* Glyph Class */
    275 
    276 BOOL rf_Glyph_New(rdpContext* context, const rdpGlyph* glyph)
    277 {
    278  TRACE_CALL(__func__);
    279 #ifdef RF_GLYPH
    280  int scanline;
    281  XImage* image;
    282  rfContext* rfi;
    283  rfGlyph* rf_glyph;
    284 
    285  rf_glyph = (rfGlyph*)glyph;
    286  rfi = (rfContext*)context;
    287 
    288  scanline = (glyph->cx + 7) / 8;
    289 
    290  rf_glyph->pixmap = XCreatePixmap(rfi->display, rfi->drawing, glyph->cx, glyph->cy, 1);
    291 
    292  image = XCreateImage(rfi->display, rfi->visual, 1,
    293  ZPixmap, 0, (char*)glyph->aj, glyph->cx, glyph->cy, 8, scanline);
    294 
    295  image->byte_order = MSBFirst;
    296  image->bitmap_bit_order = MSBFirst;
    297 
    298  XInitImage(image);
    299  XPutImage(rfi->display, rf_glyph->pixmap, rfi->gc_mono, image, 0, 0, 0, 0, glyph->cx, glyph->cy);
    300  XFree(image);
    301 #endif
    302  return TRUE;
    303 }
    304 
    305 void rf_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
    306 {
    307  TRACE_CALL(__func__);
    308 #ifdef RF_GLYPH
    309  rfContext* rfi = (rfContext*)context;
    310 
    311  if (((rfGlyph*)glyph)->pixmap != 0)
    312  XFreePixmap(rfi->display, ((rfGlyph*)glyph)->pixmap);
    313 #endif
    314 }
    315 
    316 static BOOL rf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x,
    317  INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy,
    318  BOOL fOpRedundant)
    319 {
    320  TRACE_CALL(__func__);
    321 #ifdef RF_GLYPH
    322  rfGlyph* rf_glyph;
    323  rfContext* rfi = (rfContext*)context;
    324 
    325  rf_glyph = (rfGlyph*)glyph;
    326 
    327  XSetStipple(rfi->display, rfi->gc, rf_glyph->pixmap);
    328  XSetTSOrigin(rfi->display, rfi->gc, x, y);
    329  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, glyph->cx, glyph->cy);
    330  XSetStipple(rfi->display, rfi->gc, rfi->bitmap_mono);
    331 #endif
    332  return TRUE;
    333 }
    334 
    335 static BOOL rf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y,
    336  INT32 width, INT32 height, UINT32 bgcolor,
    337  UINT32 fgcolor, BOOL fOpRedundant)
    338 {
    339  TRACE_CALL(__func__);
    340 #ifdef RF_GLYPH
    341  rfContext* rfi = (rfContext*)context;
    342 
    343  bgcolor = (rfi->clrconv->invert) ?
    344  freerdp_color_convert_var_bgr(bgcolor, rfi->srcBpp, 32, rfi->clrconv) :
    345  freerdp_color_convert_var_rgb(bgcolor, rfi->srcBpp, 32, rfi->clrconv);
    346 
    347  fgcolor = (rfi->clrconv->invert) ?
    348  freerdp_color_convert_var_bgr(fgcolor, rfi->srcBpp, 32, rfi->clrconv) :
    349  freerdp_color_convert_var_rgb(fgcolor, rfi->srcBpp, 32, rfi->clrconv);
    350 
    351  XSetFunction(rfi->display, rfi->gc, GXcopy);
    352  XSetFillStyle(rfi->display, rfi->gc, FillSolid);
    353  XSetForeground(rfi->display, rfi->gc, fgcolor);
    354  XFillRectangle(rfi->display, rfi->drawing, rfi->gc, x, y, width, height);
    355 
    356  XSetForeground(rfi->display, rfi->gc, bgcolor);
    357  XSetBackground(rfi->display, rfi->gc, fgcolor);
    358  XSetFillStyle(rfi->display, rfi->gc, FillStippled);
    359 #endif
    360  return TRUE;
    361 }
    362 
    363 static BOOL rf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y,
    364  INT32 width, INT32 height,
    365  UINT32 bgcolor, UINT32 fgcolor)
    366 {
    367  TRACE_CALL(__func__);
    368 #ifdef RF_GLYPH
    369  rfContext* rfi = (rfContext*)context;
    370 
    371  if (rfi->drawing == rfi->primary) {
    372  //XCopyArea(rfi->display, rfi->primary, rfi->drawable, rfi->gc, x, y, width, height, x, y);
    373  //gdi_InvalidateRegion(rfi->hdc, x, y, width, height);
    374  }
    375 #endif
    376  return TRUE;
    377 }
    378 
    379 /* Graphics Module */
    380 
    381 void rf_register_graphics(rdpGraphics* graphics)
    382 {
    383  TRACE_CALL(__func__);
    384  rdpBitmap* bitmap;
    385  rdpPointer* pointer;
    386  rdpGlyph* glyph;
    387 
    388  bitmap = (rdpBitmap*)malloc(sizeof(rdpBitmap));
    389  ZeroMemory(bitmap, sizeof(rdpBitmap));
    390 #ifdef RF_BITMAP
    391  bitmap->size = sizeof(rfBitmap);
    392 #else
    393  bitmap->size = 0;
    394 #endif
    395 
    396  bitmap->New = rf_Bitmap_New;
    397  bitmap->Free = rf_Bitmap_Free;
    398  bitmap->Paint = rf_Bitmap_Paint;
    399  bitmap->Decompress = rf_Bitmap_Decompress;
    400  bitmap->SetSurface = rf_Bitmap_SetSurface;
    401 
    402  graphics_register_bitmap(graphics, bitmap);
    403  free(bitmap);
    404 
    405  pointer = (rdpPointer*)malloc(sizeof(rdpPointer));
    406  ZeroMemory(pointer, sizeof(rdpPointer));
    407 
    408  pointer->size = sizeof(rfPointer);
    409 
    410  pointer->New = rf_Pointer_New;
    411  pointer->Free = rf_Pointer_Free;
    412  pointer->Set = rf_Pointer_Set;
    413  pointer->SetNull = rf_Pointer_SetNull;
    414  pointer->SetDefault = rf_Pointer_SetDefault;
    415  pointer->SetPosition = rf_Pointer_SetPosition;
    416 
    417  graphics_register_pointer(graphics, pointer);
    418 
    419  free(pointer);
    420 
    421  glyph = (rdpGlyph*)malloc(sizeof(rdpGlyph));
    422  ZeroMemory(glyph, sizeof(rdpGlyph));
    423 
    424 #ifdef RF_GLYPH
    425  glyph->size = sizeof(rfGlyph);
    426 #else
    427  glyph->size = 0;
    428 #endif
    429 
    430  glyph->New = rf_Glyph_New;
    431  glyph->Free = rf_Glyph_Free;
    432  glyph->Draw = rf_Glyph_Draw;
    433  glyph->BeginDraw = rf_Glyph_BeginDraw;
    434  glyph->EndDraw = rf_Glyph_EndDraw;
    435 
    436  graphics_register_glyph(graphics, glyph);
    437 
    438  free(glyph);
    439 }
    +
    void rf_Glyph_Free(rdpContext *context, rdpGlyph *glyph)
    Definition: rdp_graphics.c:305
    struct remmina_plugin_rdp_ui_object::@50::@53 cursor
    BOOL rf_Glyph_New(rdpContext *context, const rdpGlyph *glyph)
    Definition: rdp_graphics.c:276
    BOOL rf_Bitmap_New(rdpContext *context, rdpBitmap *bitmap)
    Definition: rdp_graphics.c:52
    BOOL rf_Pointer_New(rdpContext *context, rdpPointer *pointer)
    Definition: rdp_graphics.c:185
    - - + +
    BOOL rf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y)
    Definition: rdp_graphics.c:260
    void rf_Pointer_Free(rdpContext *context, rdpPointer *pointer)
    Definition: rdp_graphics.c:202
    - +
    struct rf_glyph rfGlyph
    Definition: rdp_plugin.h:176
    -
    GdkDisplay * display
    Definition: rdp_plugin.h:364
    +
    GdkDisplay * display
    Definition: rdp_plugin.h:365
    struct rf_bitmap rfBitmap
    Definition: rdp_plugin.h:168
    BOOL rf_Bitmap_Decompress(rdpContext *context, rdpBitmap *bitmap, const BYTE *data, UINT32 width, UINT32 height, UINT32 bpp, UINT32 length, BOOL compressed, UINT32 codec_id)
    Definition: rdp_graphics.c:134
    void rf_register_graphics(rdpGraphics *graphics)
    Definition: rdp_graphics.c:381
    struct rf_pointer rfPointer
    Definition: rdp_plugin.h:160
    - -
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:323
    + +
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:324
    BOOL rf_Bitmap_SetSurface(rdpContext *context, rdpBitmap *bitmap, BOOL primary)
    Definition: rdp_graphics.c:169
    BOOL rf_Pointer_Set(rdpContext *context, const rdpPointer *pointer)
    Definition: rdp_graphics.c:219
    -
    GdkVisual * visual
    Definition: rdp_plugin.h:365
    - +
    GdkVisual * visual
    Definition: rdp_plugin.h:366
    + - +
    static BOOL rf_Glyph_EndDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor)
    Definition: rdp_graphics.c:363
    Pixmap pixmap
    Definition: rdp_plugin.h:174
    -
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1463
    -
    gint scanline_pad
    Definition: rdp_plugin.h:369
    +
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1471
    +
    gint scanline_pad
    Definition: rdp_plugin.h:370
    static BOOL rf_Glyph_BeginDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
    Definition: rdp_graphics.c:335
    - +
    BOOL rf_Bitmap_Paint(rdpContext *context, rdpBitmap *bitmap)
    Definition: rdp_graphics.c:103
    BOOL rf_Pointer_SetNull(rdpContext *context)
    Definition: rdp_graphics.c:234
    -
    gint srcBpp
    Definition: rdp_plugin.h:363
    +
    gint srcBpp
    Definition: rdp_plugin.h:364
    BOOL rf_Pointer_SetDefault(rdpContext *context)
    Definition: rdp_graphics.c:247
    static BOOL rf_Glyph_Draw(rdpContext *context, const rdpGlyph *glyph, INT32 x, INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
    Definition: rdp_graphics.c:316
    - +
    void rf_Bitmap_Free(rdpContext *context, rdpBitmap *bitmap)
    Definition: rdp_graphics.c:90
    struct remmina_plugin_rdp_ui_object::@50::@58 pos
    -
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:266
    +
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:267
    diff --git a/public/rdp__monitor_8c_source.html b/public/rdp__monitor_8c_source.html index d31c21b4d..2bcb2fe65 100644 --- a/public/rdp__monitor_8c_source.html +++ b/public/rdp__monitor_8c_source.html @@ -87,10 +87,10 @@ $(document).ready(function(){initNavTree('rdp__monitor_8c_source.html','');});
    Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program; if not, write to the Free Software
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    18  * Boston, MA 02110-1301, USA.
    19  *
    20  * In addition, as a special exception, the copyright holders give
    21  * permission to link the code of portions of this program with the
    22  * OpenSSL library under certain conditions as described in each
    23  * individual source file, and distribute linked combinations
    24  * including the two.
    25  * You must obey the GNU General Public License in all respects
    26  * for all of the code used other than OpenSSL. * If you modify
    27  * file(s) with this exception, you may extend this exception to your
    28  * version of the file(s), but you are not obligated to do so. * If you
    29  * do not wish to do so, delete this exception statement from your
    30  * version. * If you delete this exception statement from all source
    31  * files in the program, then also delete it here.
    32  *
    33  */
    34 
    35 #include "rdp_plugin.h"
    36 #include "rdp_monitor.h"
    37 
    39 gint remmina_rdp_utils_strpos(const gchar *haystack, const gchar *needle)
    40 {
    41  TRACE_CALL(__func__);
    42  const gchar *sub;
    43 
    44  if (!*needle)
    45  return -1;
    46 
    47  sub = strstr(haystack, needle);
    48  if (!sub)
    49  return -1;
    50 
    51  return sub - haystack;
    52 }
    53 
    54 /* https://github.com/adlocode/xfwm4/blob/1d21be9ffc0fa1cea91905a07d1446c5227745f4/common/xfwm-common.c */
    55 
    56 
    68 void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
    69 {
    70  TRACE_CALL(__func__);
    71 
    72  GdkDisplay *display;
    73  GdkMonitor *monitor;
    74  gboolean has_custom_monitors = FALSE;
    75 
    76  gboolean primary_found = FALSE;
    77 
    78  gint n_monitors;
    79  gint scale;
    80  gint index = 0;
    81  gint count = 0;
    82 
    83  static gchar buffer[256];
    84  gint buffer_offset = 0;
    85 
    86  GdkRectangle geometry = { 0, 0, 0, 0 };
    87  GdkRectangle tempgeom = { 0, 0, 0, 0 };
    88  GdkRectangle destgeom = { 0, 0, 0, 0 };
    89  rdpSettings* settings;
    90  if (!rfi || !rfi->settings)
    91  return;
    92 
    93  settings = rfi->settings;
    94 
    95  *maxwidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
    96  *maxheight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
    97 
    98  display = gdk_display_get_default ();
    99  n_monitors = gdk_display_get_n_monitors(display);
    100 
    101  /* Get monitor at windows curently in use */
    102  //w = gtk_widget_get_window(rfi->drawing_area);
    103 
    104  //current_monitor = gdk_display_get_monitor_at_window (display, w);
    105 
    106  /* we got monitorids as options */
    107  if (*monitorids)
    108  has_custom_monitors = TRUE;
    109 
    110  rdpMonitor* base = (rdpMonitor *)freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
    111  for (gint i = 0; i < n_monitors; ++i) {
    112  rdpMonitor* current;
    113  if (has_custom_monitors) {
    114  REMMINA_PLUGIN_DEBUG("We have custom monitors");
    115  gchar itoc[11];
    116  snprintf(itoc, sizeof(itoc), "%d", i);
    117  if (remmina_rdp_utils_strpos(*monitorids, itoc) < 0 ) {
    118  REMMINA_PLUGIN_DEBUG("Monitor n %d it's out of the provided list", i);
    119  index += 1;
    120  continue;
    121  }
    122  }
    123 
    124  monitor = gdk_display_get_monitor(display, i);
    125  if (monitor == NULL) {
    126  REMMINA_PLUGIN_DEBUG("Monitor n %d does not exist or is not active", i);
    127  index +=1;
    128  continue;
    129  }
    130 
    131  monitor = gdk_display_get_monitor(display, index);
    132  current = &base[index];
    133  REMMINA_PLUGIN_DEBUG("Monitor n %d", index);
    134  /* If the desktop env in use doesn't have the working area concept
    135  * gdk_monitor_get_workarea will return the monitor geometry*/
    136  //gdk_monitor_get_workarea (monitor, &geometry);
    137  gdk_monitor_get_geometry (monitor, &geometry);
    138  current->x = geometry.x;
    139  REMMINA_PLUGIN_DEBUG("Monitor n %d x: %d", index, geometry.x);
    140  current->y = geometry.y;
    141  REMMINA_PLUGIN_DEBUG("Monitor n %d y: %d", index, geometry.y);
    142  /* geometry contain the application geometry, to obtain the real one
    143  * we must multiply by the scale factor */
    144  scale = gdk_monitor_get_scale_factor (monitor);
    145  REMMINA_PLUGIN_DEBUG("Monitor n %d scale: %d", index, scale);
    146  geometry.x *= scale;
    147  geometry.y *= scale;
    148  geometry.width *= scale;
    149  geometry.height *= scale;
    150  REMMINA_PLUGIN_DEBUG("Monitor n %d width: %d", index, geometry.width);
    151  REMMINA_PLUGIN_DEBUG("Monitor n %d height: %d", index, geometry.height);
    152  current->width = geometry.width;
    153  current->height = geometry.height;
    154  current->attributes.physicalHeight = gdk_monitor_get_height_mm (monitor);
    155  REMMINA_PLUGIN_DEBUG("Monitor n %d physical height: %d", i, current->attributes.physicalHeight);
    156  current->attributes.physicalWidth = gdk_monitor_get_width_mm (monitor);
    157  REMMINA_PLUGIN_DEBUG("Monitor n %d physical width: %d", i, current->attributes.physicalWidth);
    158  current->orig_screen = index;
    159  if (!primary_found) {
    160  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, current->x);
    161  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, current->y);
    162  }
    163  if (gdk_monitor_is_primary(monitor)) {
    164  REMMINA_PLUGIN_DEBUG ("Primary monitor found with id: %d", index);
    165  current->is_primary = TRUE;
    166  primary_found = TRUE;
    167  if (current->x != 0 || current->y != 0)
    168  {
    169  REMMINA_PLUGIN_DEBUG ("Primary monitor not at 0,0 coordinates: %d", index);
    170  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, current->x);
    171  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, current->y);
    172  }
    173  } else {
    174  if (!primary_found && current->x == 0 &&
    175  current->y == 0)
    176  {
    177  REMMINA_PLUGIN_DEBUG ("Monitor %d has 0,0 coordinates", index);
    178  current->is_primary = TRUE;
    179  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, current->x);
    180  freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, current->y);
    181  primary_found = TRUE;
    182  REMMINA_PLUGIN_DEBUG ("Primary monitor set to id: %d", index);
    183  }
    184  }
    185  REMMINA_PLUGIN_DEBUG ("Local X Shift: %d", freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftX));
    186  REMMINA_PLUGIN_DEBUG ("Local Y Shift: %d", freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftY));
    187  //current->x =
    188  //current->x - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftX);
    189  //REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", index, current->x);
    190  //current->y =
    191  //current->y - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftY);
    192  //REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", index, current->y);
    193 
    194  if (buffer_offset == 0)
    195  buffer_offset = g_sprintf(buffer + buffer_offset, "%d", i);
    196  else
    197  buffer_offset = g_sprintf(buffer + buffer_offset, ",%d", i);
    198  REMMINA_PLUGIN_DEBUG("Monitor IDs buffer: %s", buffer);
    199  gdk_rectangle_union(&tempgeom, &geometry, &destgeom);
    200  memcpy(&tempgeom, &destgeom, sizeof tempgeom);
    201  count++;
    202  index++;
    203 
    204  }
    205  freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, index);
    206  /* Subtract monitor shift from monitor variables for server-side use.
    207  * We maintain monitor shift value as Window requires the primary monitor to have a
    208  * coordinate of 0,0 In some X configurations, no monitor may have a coordinate of 0,0. This
    209  * can also be happen if the user requests specific monitors from the command-line as well.
    210  * So, we make sure to translate our primary monitor's upper-left corner to 0,0 on the
    211  * server.
    212  */
    213  for (gint i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
    214  {
    215  rdpMonitor* current = &base[i];
    216  current->x =
    217  current->x - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftX);
    218  REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", i, current->x);
    219  current->y =
    220  current->y - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftY);
    221  REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", i, current->y);
    222  }
    223 
    224  REMMINA_PLUGIN_DEBUG("%d monitors on %d have been configured", freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount), count);
    225  *maxwidth = destgeom.width;
    226  *maxheight = destgeom.height;
    227  REMMINA_PLUGIN_DEBUG("maxw and maxh: %ux%u", *maxwidth, *maxheight);
    228  if (n_monitors > 1)
    229  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportMonitorLayoutPdu, TRUE);
    230  *monitorids = g_strdup(buffer);
    231 }
    gint remmina_rdp_utils_strpos(const gchar *haystack, const gchar *needle)
    Utility functions should be moved somewhere else
    Definition: rdp_monitor.c:39
    - + -
    rdpSettings * settings
    Definition: rdp_plugin.h:326
    +
    rdpSettings * settings
    Definition: rdp_plugin.h:327
    void remmina_rdp_monitor_get(rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
    Set the MonitorIDs, the maxwidth and maxheight.
    Definition: rdp_monitor.c:68
    diff --git a/public/rdp__monitor_8h_source.html b/public/rdp__monitor_8h_source.html index dade82255..ee1397e13 100644 --- a/public/rdp__monitor_8h_source.html +++ b/public/rdp__monitor_8h_source.html @@ -86,7 +86,7 @@ $(document).ready(function(){initNavTree('rdp__monitor_8h_source.html','');});
    rdp_monitor.h
    -Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program; if not, write to the Free Software
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    18  * Boston, MA 02110-1301, USA.
    19  *
    20  * In addition, as a special exception, the copyright holders give
    21  * permission to link the code of portions of this program with the
    22  * OpenSSL library under certain conditions as described in each
    23  * individual source file, and distribute linked combinations
    24  * including the two.
    25  * You must obey the GNU General Public License in all respects
    26  * for all of the code used other than OpenSSL. * If you modify
    27  * file(s) with this exception, you may extend this exception to your
    28  * version of the file(s), but you are not obligated to do so. * If you
    29  * do not wish to do so, delete this exception statement from your
    30  * version. * If you delete this exception statement from all source
    31  * files in the program, then also delete it here.
    32  *
    33  */
    34 
    35 #pragma once
    36 
    37 
    38 #include <freerdp/freerdp.h>
    39 #include "rdp_plugin.h"
    40 
    41 G_BEGIN_DECLS
    42 
    43 void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight);
    44 
    45 G_END_DECLS
    +Go to the documentation of this file.
    1 /*
    2  * Remmina - The GTK+ Remote Desktop Client
    3  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program; if not, write to the Free Software
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    18  * Boston, MA 02110-1301, USA.
    19  *
    20  * In addition, as a special exception, the copyright holders give
    21  * permission to link the code of portions of this program with the
    22  * OpenSSL library under certain conditions as described in each
    23  * individual source file, and distribute linked combinations
    24  * including the two.
    25  * You must obey the GNU General Public License in all respects
    26  * for all of the code used other than OpenSSL. * If you modify
    27  * file(s) with this exception, you may extend this exception to your
    28  * version of the file(s), but you are not obligated to do so. * If you
    29  * do not wish to do so, delete this exception statement from your
    30  * version. * If you delete this exception statement from all source
    31  * files in the program, then also delete it here.
    32  *
    33  */
    34 
    35 #pragma once
    36 
    37 
    38 #include <freerdp/freerdp.h>
    39 #include "rdp_plugin.h"
    40 
    41 G_BEGIN_DECLS
    42 
    43 void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight);
    44 
    45 G_END_DECLS
    G_BEGIN_DECLS void remmina_rdp_monitor_get(rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
    Set the MonitorIDs, the maxwidth and maxheight.
    Definition: rdp_monitor.c:68
    diff --git a/public/rdp__plugin_8c.html b/public/rdp__plugin_8c.html index 99842642b..77f6da580 100644 --- a/public/rdp__plugin_8c.html +++ b/public/rdp__plugin_8c.html @@ -268,7 +268,7 @@ Variables
    -

    Definition at line 3035 of file rdp_plugin.c.

    +

    Definition at line 3041 of file rdp_plugin.c.

    @@ -296,7 +296,7 @@ Variables
    -

    Definition at line 2382 of file rdp_plugin.c.

    +

    Definition at line 2388 of file rdp_plugin.c.

    @@ -324,7 +324,7 @@ Variables
    -

    Definition at line 1330 of file rdp_plugin.c.

    +

    Definition at line 1336 of file rdp_plugin.c.

    @@ -344,7 +344,7 @@ Variables
    -

    Definition at line 3055 of file rdp_plugin.c.

    +

    Definition at line 3061 of file rdp_plugin.c.

    @@ -394,7 +394,7 @@ Variables
    -

    Definition at line 775 of file rdp_plugin.c.

    +

    Definition at line 781 of file rdp_plugin.c.

    @@ -432,7 +432,7 @@ Variables
    -

    Definition at line 2573 of file rdp_plugin.c.

    +

    Definition at line 2579 of file rdp_plugin.c.

    @@ -460,7 +460,7 @@ Variables
    -

    Definition at line 2525 of file rdp_plugin.c.

    +

    Definition at line 2531 of file rdp_plugin.c.

    @@ -580,7 +580,7 @@ Variables
    -

    Definition at line 1091 of file rdp_plugin.c.

    +

    Definition at line 1097 of file rdp_plugin.c.

    @@ -619,7 +619,7 @@ Variables
    Todo:
    we should lock FreeRDP subthread to update rfi->primary_buffer, rfi->gdi and w/h, from here to memcpy, but… how ?
    -

    Definition at line 2639 of file rdp_plugin.c.

    +

    Definition at line 2645 of file rdp_plugin.c.

    @@ -669,7 +669,7 @@ Variables
    -

    Definition at line 834 of file rdp_plugin.c.

    +

    Definition at line 840 of file rdp_plugin.c.

    @@ -697,7 +697,7 @@ Variables
    -

    Definition at line 2439 of file rdp_plugin.c.

    +

    Definition at line 2445 of file rdp_plugin.c.

    @@ -741,7 +741,7 @@ Variables
    -

    Definition at line 2629 of file rdp_plugin.c.

    +

    Definition at line 2635 of file rdp_plugin.c.

    @@ -791,7 +791,7 @@ Variables
    -

    Definition at line 1064 of file rdp_plugin.c.

    +

    Definition at line 1070 of file rdp_plugin.c.

    @@ -821,7 +821,7 @@ Variables

    Proxy support Proxy settings are hidden at the moment as an advanced feature

    multitransport enables RDP8 UDP support

    -

    Definition at line 1358 of file rdp_plugin.c.

    +

    Definition at line 1364 of file rdp_plugin.c.

    @@ -849,7 +849,7 @@ Variables
    -

    Definition at line 993 of file rdp_plugin.c.

    +

    Definition at line 999 of file rdp_plugin.c.

    @@ -877,7 +877,7 @@ Variables
    -

    Definition at line 2412 of file rdp_plugin.c.

    +

    Definition at line 2418 of file rdp_plugin.c.

    @@ -905,7 +905,7 @@ Variables
    -

    Definition at line 2477 of file rdp_plugin.c.

    +

    Definition at line 2483 of file rdp_plugin.c.

    @@ -934,7 +934,7 @@ Variables

    Do not use alpha as it's not used with the desktop CAIRO_FORMAT_ARGB32 See https://gitlab.com/Remmina/Remmina/-/issues/2456

    -

    Definition at line 700 of file rdp_plugin.c.

    +

    Definition at line 706 of file rdp_plugin.c.

    @@ -962,7 +962,7 @@ Variables
    -

    Definition at line 978 of file rdp_plugin.c.

    +

    Definition at line 984 of file rdp_plugin.c.

    @@ -990,7 +990,7 @@ Variables
    -

    Definition at line 675 of file rdp_plugin.c.

    +

    Definition at line 681 of file rdp_plugin.c.

    @@ -1028,7 +1028,7 @@ Variables
    -

    Definition at line 2567 of file rdp_plugin.c.

    +

    Definition at line 2573 of file rdp_plugin.c.

    @@ -1056,7 +1056,7 @@ Variables
    -

    Definition at line 1247 of file rdp_plugin.c.

    +

    Definition at line 1253 of file rdp_plugin.c.

    @@ -1094,7 +1094,7 @@ Variables
    -

    Definition at line 1257 of file rdp_plugin.c.

    +

    Definition at line 1263 of file rdp_plugin.c.

    @@ -1147,7 +1147,7 @@ Variables

    We pass NULL and we do not check for errors. The following code is how it is supposed to work.

    Todo:
    Ask CUPS mailing list for help.
    const char *model = cupsGetOption("printer-make-and-model",
    dest->num_options,
    dest->options);

    When remmina_rdp_find_prdriver doesn't return a DriverName it means that we don't want to share that printer

    -

    Definition at line 1166 of file rdp_plugin.c.

    +

    Definition at line 1172 of file rdp_plugin.c.

    @@ -1175,7 +1175,7 @@ Variables
    -

    Definition at line 342 of file rdp_plugin.c.

    +

    Definition at line 348 of file rdp_plugin.c.

    @@ -1237,7 +1237,7 @@ Variables
    -

    Definition at line 937 of file rdp_plugin.c.

    +

    Definition at line 943 of file rdp_plugin.c.

    @@ -1311,7 +1311,7 @@ Variables
    -

    Definition at line 914 of file rdp_plugin.c.

    +

    Definition at line 920 of file rdp_plugin.c.

    @@ -1403,7 +1403,7 @@ Variables
    -

    Definition at line 956 of file rdp_plugin.c.

    +

    Definition at line 962 of file rdp_plugin.c.

    @@ -1431,7 +1431,7 @@ Variables
    -

    Definition at line 401 of file rdp_plugin.c.

    +

    Definition at line 407 of file rdp_plugin.c.

    @@ -1459,7 +1459,7 @@ Variables
    -

    Definition at line 518 of file rdp_plugin.c.

    +

    Definition at line 524 of file rdp_plugin.c.

    @@ -1487,7 +1487,7 @@ Variables
    -

    Definition at line 580 of file rdp_plugin.c.

    +

    Definition at line 586 of file rdp_plugin.c.

    @@ -1515,7 +1515,7 @@ Variables
    -

    Definition at line 533 of file rdp_plugin.c.

    +

    Definition at line 539 of file rdp_plugin.c.

    @@ -1565,7 +1565,7 @@ Variables
    -

    Definition at line 663 of file rdp_plugin.c.

    +

    Definition at line 669 of file rdp_plugin.c.

    @@ -1603,7 +1603,7 @@ Variables
    -

    Definition at line 634 of file rdp_plugin.c.

    +

    Definition at line 640 of file rdp_plugin.c.

    @@ -1641,7 +1641,7 @@ Variables
    -

    Definition at line 618 of file rdp_plugin.c.

    +

    Definition at line 624 of file rdp_plugin.c.

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

    Definition at line 2352 of file rdp_plugin.c.

    +

    Definition at line 2358 of file rdp_plugin.c.

    @@ -1723,7 +1723,7 @@ Variables
    Initial value:
    =
    N_("Options for redirection of audio output:\n"
    " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    " [channel:<channel>] Audio output\n"
    " • sys:pulse\n"
    " • format:1\n"
    " • sys:oss,dev:1,format:1\n"
    " • sys:alsa")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2805 of file rdp_plugin.c.

    +

    Definition at line 2811 of file rdp_plugin.c.

    @@ -1748,7 +1748,7 @@ Variables
    Initial value:
    =
    N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2785 of file rdp_plugin.c.

    +

    Definition at line 2791 of file rdp_plugin.c.

    @@ -1773,7 +1773,7 @@ Variables
    Initial value:
    =
    N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
    " • < 4034: Windows XP base smart card functions\n"
    " • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
    " SCardWriteCache(), SCardGetTransmitCount()\n"
    " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
    " SCardGetDeviceTypeId()")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2788 of file rdp_plugin.c.

    +

    Definition at line 2794 of file rdp_plugin.c.

    @@ -1798,7 +1798,7 @@ Variables
    Initial value:
    =
    {
    "99", N_("Automatic (32 bpp) (Server chooses its best format)"),
    "66", N_("GFX AVC444 (32 bpp)"),
    "65", N_("GFX AVC420 (32 bpp)"),
    "64", N_("GFX RFX (32 bpp)"),
    "63", N_("GFX RFX Progressive (32 bpp)"),
    "0", N_("RemoteFX (32 bpp)"),
    "32", N_("True colour (32 bpp)"),
    "24", N_("True colour (24 bpp)"),
    "16", N_("High colour (16 bpp)"),
    "15", N_("High colour (15 bpp)"),
    "8", N_("256 colours (8 bpp)"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2679 of file rdp_plugin.c.

    +

    Definition at line 2685 of file rdp_plugin.c.

    @@ -1823,7 +1823,7 @@ Variables
    Initial value:
    =
    N_("Redirect directory <path> as named share <name>.\n"
    " • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
    " • MyHome,/home/remminer\n"
    " • /home/remminer\n"
    " • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
    "Hotplug support is enabled with:\n"
    " • hotplug,*\n"
    "\n")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2843 of file rdp_plugin.c.

    +

    Definition at line 2849 of file rdp_plugin.c.

    @@ -1871,7 +1871,7 @@ Variables
    Initial value:
    =
    {
    "http", "HTTP",
    "rpc", "RPC",
    "auto", "Auto",
    NULL
    }
    -

    Definition at line 2765 of file rdp_plugin.c.

    +

    Definition at line 2771 of file rdp_plugin.c.

    @@ -1919,7 +1919,7 @@ Variables
    Initial value:
    =
    {
    "INFO", "INFO",
    "FATAL", "FATAL",
    "ERROR", "ERROR",
    "WARN", "WARN",
    "DEBUG", "DEBUG",
    "TRACE", "TRACE",
    "OFF", "OFF",
    NULL
    }
    -

    Definition at line 2697 of file rdp_plugin.c.

    +

    Definition at line 2703 of file rdp_plugin.c.

    @@ -1944,7 +1944,7 @@ Variables
    Initial value:
    =
    N_("Options for redirection of audio input:\n"
    " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    " [channel:<channel>] Audio input (microphone)\n"
    " • sys:pulse\n"
    " • format:1\n"
    " • sys:oss,dev:1,format:1\n"
    " • sys:alsa")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2796 of file rdp_plugin.c.

    +

    Definition at line 2802 of file rdp_plugin.c.

    @@ -1969,7 +1969,7 @@ Variables
    Initial value:
    =
    N_("Comma-separated list of monitor IDs and desktop orientations:\n"
    " • [<id>:<orientation-in-degrees>,]\n"
    " • 0,1,2,3\n"
    " • 0:270,1:90\n"
    "Orientations are specified in degrees, valid values are:\n"
    " • 0 (landscape)\n"
    " • 90 (portrait)\n"
    " • 180 (landscape flipped)\n"
    " • 270 (portrait flipped)\n"
    "\n")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2831 of file rdp_plugin.c.

    +

    Definition at line 2837 of file rdp_plugin.c.

    @@ -1994,7 +1994,7 @@ Variables
    Initial value:
    =
    {
    "No", N_("No"),
    "60", N_("Every 1 min"),
    "180", N_("Every 3 min"),
    "300", N_("Every 5 min"),
    "600", N_("Every 10 min"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2755 of file rdp_plugin.c.

    +

    Definition at line 2761 of file rdp_plugin.c.

    @@ -2019,7 +2019,7 @@ Variables
    Initial value:
    =
    {
    "none", N_("None"),
    "autodetect", N_("Auto-detect"),
    "modem", N_("Modem"),
    "broadband-low", N_("Low performance broadband"),
    "satellite", N_("Satellite"),
    "broadband-high", N_("High performance broadband"),
    "wan", N_("WAN"),
    "lan", N_("LAN"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2721 of file rdp_plugin.c.

    +

    Definition at line 2727 of file rdp_plugin.c.

    @@ -2044,7 +2044,7 @@ Variables
    Initial value:
    =
    N_("Performance optimisations based on the network connection type:\n"
    "Using auto-detection is advised.\n"
    "If “Auto-detect” fails, choose the most appropriate option in the list.\n")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2826 of file rdp_plugin.c.

    +

    Definition at line 2832 of file rdp_plugin.c.

    @@ -2069,7 +2069,7 @@ Variables
    Initial value:
    =
    {
    "0", N_("Poor (fastest)"),
    "1", N_("Medium"),
    "2", N_("Good"),
    "9", N_("Best (slowest)"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2711 of file rdp_plugin.c.

    +

    Definition at line 2717 of file rdp_plugin.c.

    @@ -2093,7 +2093,7 @@ Variables
    -

    Definition at line 2981 of file rdp_plugin.c.

    +

    Definition at line 2987 of file rdp_plugin.c.

    @@ -2132,24 +2132,24 @@ Variables
    -Initial value:
    =
    {
    "RDP",
    N_("RDP - Remote Desktop Protocol"),
    GETTEXT_PACKAGE,
    "org.remmina.Remmina-rdp-symbolic",
    "org.remmina.Remmina-rdp-ssh-symbolic",
    }
    static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2477
    +Initial value:
    =
    {
    "RDP",
    N_("RDP - Remote Desktop Protocol"),
    GETTEXT_PACKAGE,
    "org.remmina.Remmina-rdp-symbolic",
    "org.remmina.Remmina-rdp-ssh-symbolic",
    }
    static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2483
    gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:74
    -
    static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2567
    +
    static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2573
    -
    static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
    Definition: rdp_plugin.c:2900
    -
    static void remmina_rdp_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2439
    +
    static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
    Definition: rdp_plugin.c:2906
    +
    static void remmina_rdp_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2445
    -
    static const RemminaProtocolFeature remmina_rdp_features[]
    Definition: rdp_plugin.c:2967
    -
    static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    Definition: rdp_plugin.c:2629
    -
    static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2525
    -
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2981
    -
    static const RemminaProtocolSetting remmina_rdp_basic_settings[]
    Definition: rdp_plugin.c:2870
    -
    static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    Definition: rdp_plugin.c:2639
    +
    static const RemminaProtocolFeature remmina_rdp_features[]
    Definition: rdp_plugin.c:2973
    +
    static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    Definition: rdp_plugin.c:2635
    +
    static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2531
    +
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2987
    +
    static const RemminaProtocolSetting remmina_rdp_basic_settings[]
    Definition: rdp_plugin.c:2876
    +
    static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    Definition: rdp_plugin.c:2645
    gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:52
    -
    static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2573
    +
    static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2579
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2984 of file rdp_plugin.c.

    +

    Definition at line 2990 of file rdp_plugin.c.

    @@ -2173,7 +2173,7 @@ Variables
    -

    Definition at line 2900 of file rdp_plugin.c.

    +

    Definition at line 2906 of file rdp_plugin.c.

    @@ -2197,21 +2197,21 @@ Variables
    Initial value:
    =
    {
    { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
    { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
    }
    -
    static gchar network_tooltip[]
    Definition: rdp_plugin.c:2826
    +
    static gchar network_tooltip[]
    Definition: rdp_plugin.c:2832
    -
    static gpointer network_list[]
    Definition: rdp_plugin.c:2721
    +
    static gpointer network_list[]
    Definition: rdp_plugin.c:2727
    -
    static gpointer colordepth_list[]
    Definition: rdp_plugin.c:2679
    -
    static gchar monitorids_tooltip[]
    Definition: rdp_plugin.c:2831
    +
    static gpointer colordepth_list[]
    Definition: rdp_plugin.c:2685
    +
    static gchar monitorids_tooltip[]
    Definition: rdp_plugin.c:2837
    -
    static gchar drive_tooltip[]
    Definition: rdp_plugin.c:2843
    +
    static gchar drive_tooltip[]
    Definition: rdp_plugin.c:2849
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2870 of file rdp_plugin.c.

    +

    Definition at line 2876 of file rdp_plugin.c.

    @@ -2243,7 +2243,7 @@ Variables
    Definition: types.h:50
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2967 of file rdp_plugin.c.

    +

    Definition at line 2973 of file rdp_plugin.c.

    @@ -2270,11 +2270,11 @@ Variables
    Definition: plugin.h:49
    gboolean remmina_rdp_file_import_test(RemminaFilePlugin *plugin, const gchar *from_file)
    Definition: rdp_file.c:41
    gboolean remmina_rdp_file_export(RemminaFilePlugin *plugin, RemminaFile *remminafile, const gchar *to_file)
    Definition: rdp_file.c:282
    -
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2981
    +
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2987
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    RemminaFile * remmina_rdp_file_import(RemminaFilePlugin *plugin, const gchar *from_file)
    Definition: rdp_file.c:185
    -

    Definition at line 3009 of file rdp_plugin.c.

    +

    Definition at line 3015 of file rdp_plugin.c.

    @@ -2299,10 +2299,10 @@ Variables
    Initial value:
    =
    {
    "RDPS",
    N_("RDP - Preferences"),
    GETTEXT_PACKAGE,
    "RDP",
    }
    GtkWidget * remmina_rdp_settings_new(RemminaPrefPlugin *plugin)
    Definition: rdp_settings.c:696
    -
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2981
    +
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2987
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 3024 of file rdp_plugin.c.

    +

    Definition at line 3030 of file rdp_plugin.c.

    @@ -2327,7 +2327,7 @@ Variables
    Initial value:
    =
    {
    "", N_("Automatic negotiation"),
    "nla", N_("NLA protocol security"),
    "tls", N_("TLS protocol security"),
    "rdp", N_("RDP protocol security"),
    "ext", N_("NLA extended protocol security"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2744 of file rdp_plugin.c.

    +

    Definition at line 2750 of file rdp_plugin.c.

    @@ -2352,7 +2352,7 @@ Variables
    Initial value:
    =
    {
    "off", N_("Off"),
    "local", N_("Local"),
    "remote", N_("Remote"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2735 of file rdp_plugin.c.

    +

    Definition at line 2741 of file rdp_plugin.c.

    @@ -2377,7 +2377,7 @@ Variables
    Initial value:
    =
    N_("Advanced setting for high latency links:\n"
    "Adjusts the connection timeout. Use if your connection times out.\n"
    "The highest possible value is 600000 ms (10 minutes).\n")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2821 of file rdp_plugin.c.

    +

    Definition at line 2827 of file rdp_plugin.c.

    @@ -2402,7 +2402,7 @@ Variables
    Initial value:
    =
    {
    "", N_("Default"),
    "0", N_("0 — Windows 7 compatible"),
    "1", N_("1"),
    "2", N_("2"),
    "3", N_("3"),
    "4", N_("4"),
    "5", N_("5"),
    NULL
    }
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2773 of file rdp_plugin.c.

    +

    Definition at line 2779 of file rdp_plugin.c.

    @@ -2427,7 +2427,7 @@ Variables
    Initial value:
    =
    N_("Options for redirection of USB device:\n"
    " • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
    " • auto\n"
    " • id:054c:0268#4669:6e6b,addr:04:0c")
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    -

    Definition at line 2815 of file rdp_plugin.c.

    +

    Definition at line 2821 of file rdp_plugin.c.

    diff --git a/public/rdp__plugin_8c_source.html b/public/rdp__plugin_8c_source.html index 8d3ac1e95..27bac3685 100644 --- a/public/rdp__plugin_8c_source.html +++ b/public/rdp__plugin_8c_source.html @@ -86,79 +86,79 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
    rdp_plugin.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-2022 Antenore Gatta, Giovanni Panozzo
    6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
    7  *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    16  * GNU General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    21  * Boston, MA 02110-1301, USA.
    22  *
    23  * In addition, as a special exception, the copyright holders give
    24  * permission to link the code of portions of this program with the
    25  * OpenSSL library under certain conditions as described in each
    26  * individual source file, and distribute linked combinations
    27  * including the two.
    28  * You must obey the GNU General Public License in all respects
    29  * for all of the code used other than OpenSSL. * If you modify
    30  * file(s) with this exception, you may extend this exception to your
    31  * version of the file(s), but you are not obligated to do so. * If you
    32  * do not wish to do so, delete this exception statement from your
    33  * version. * If you delete this exception statement from all source
    34  * files in the program, then also delete it here.
    35  *
    36  */
    37 
    38 
    39 #define _GNU_SOURCE
    40 
    41 #include "remmina/plugin.h"
    42 #include "rdp_plugin.h"
    43 #include "rdp_event.h"
    44 #include "rdp_graphics.h"
    45 #include "rdp_file.h"
    46 #include "rdp_settings.h"
    47 #include "rdp_cliprdr.h"
    48 #include "rdp_monitor.h"
    49 #include "rdp_channels.h"
    50 
    51 #include <errno.h>
    52 #include <pthread.h>
    53 #include <time.h>
    54 #include <sys/time.h>
    55 #ifdef GDK_WINDOWING_X11
    56 #include <cairo/cairo-xlib.h>
    57 #else
    58 #include <cairo/cairo.h>
    59 #endif
    60 #include <freerdp/addin.h>
    61 #include <freerdp/assistance.h>
    62 #include <freerdp/settings.h>
    63 #include <freerdp/freerdp.h>
    64 #include <freerdp/constants.h>
    65 #include <freerdp/client/cliprdr.h>
    66 #include <freerdp/client/channels.h>
    67 #include <freerdp/client/cmdline.h>
    68 #include <freerdp/error.h>
    69 #include <freerdp/event.h>
    70 #include <winpr/memory.h>
    71 #include <winpr/cmdline.h>
    72 #include <ctype.h>
    73 
    74 #ifdef HAVE_CUPS
    75 #include <cups/cups.h>
    76 #endif
    77 
    78 #include <unistd.h>
    79 #include <string.h>
    80 
    81 #ifdef GDK_WINDOWING_X11
    82 #include <X11/Xlib.h>
    83 #include <X11/XKBlib.h>
    84 #include <gdk/gdkx.h>
    85 #elif defined(GDK_WINDOWING_WAYLAND)
    86 #include <gdk/gdkwayland.h>
    87 #endif
    88 
    89 #if defined(__FreeBSD__)
    90 #include <pthread_np.h>
    91 #endif
    92 
    93 #include <freerdp/locale/keyboard.h>
    94 
    95 #define REMMINA_RDP_FEATURE_TOOL_REFRESH 1
    96 #define REMMINA_RDP_FEATURE_SCALE 2
    97 #define REMMINA_RDP_FEATURE_UNFOCUS 3
    98 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4
    99 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5
    100 #define REMMINA_RDP_FEATURE_MULTIMON 6
    101 #define REMMINA_RDP_FEATURE_VIEWONLY 7
    102 
    103 #define REMMINA_CONNECTION_TYPE_NONE 0
    104 
    105 #ifdef WITH_FREERDP3
    106  #define CLPARAM const char
    107 #else
    108  #define CLPARAM char
    109 #endif
    110 
    111 
    113 
    114 static BOOL gfx_h264_available = FALSE;
    115 // keep track of last interaction time for keep alive
    116 static time_t last_time;
    117 
    118 /* Compatibility: these functions have been introduced with https://github.com/FreeRDP/FreeRDP/commit/8c5d96784d
    119  * and are missing on older FreeRDP, so we add them here.
    120  * They should be removed from here after all distributed versions of FreeRDP (libwinpr) will have
    121  * CommandLineParseCommaSeparatedValuesEx() onboard.
    122  *
    123  * (C) Copyright goes to the FreeRDP authors.
    124  */
    125 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
    126 {
    127  TRACE_CALL(__func__);
    128 #if FREERDP_CHECK_VERSION(2, 0, 0)
    129  return (CLPARAM **)CommandLineParseCommaSeparatedValuesEx(name, list, count);
    130 #else
    131  char **p;
    132  char *str;
    133  size_t nArgs;
    134  size_t index;
    135  size_t nCommas;
    136  size_t prefix, len;
    137 
    138  nCommas = 0;
    139 
    140  if (count == NULL)
    141  return NULL;
    142 
    143  *count = 0;
    144 
    145  if (!list) {
    146  if (name) {
    147  size_t len = strlen(name);
    148  p = (char **)calloc(2UL + len, sizeof(char *));
    149 
    150  if (p) {
    151  char *dst = (char *)&p[1];
    152  p[0] = dst;
    153  sprintf_s(dst, len + 1, "%s", name);
    154  *count = 1;
    155  return p;
    156  }
    157  }
    158 
    159  return NULL;
    160  }
    161 
    162  {
    163  const char *it = list;
    164 
    165  while ((it = strchr(it, ',')) != NULL) {
    166  it++;
    167  nCommas++;
    168  }
    169  }
    170 
    171  nArgs = nCommas + 1;
    172 
    173  if (name)
    174  nArgs++;
    175 
    176  prefix = (nArgs + 1UL) * sizeof(char *);
    177  len = strlen(list);
    178  p = (char **)calloc(len + prefix + 1, sizeof(char *));
    179 
    180  if (!p)
    181  return NULL;
    182 
    183  str = &((char *)p)[prefix];
    184  memcpy(str, list, len);
    185 
    186  if (name)
    187  p[0] = (char *)name;
    188 
    189  for (index = name ? 1 : 0; index < nArgs; index++) {
    190  char *comma = strchr(str, ',');
    191  p[index] = str;
    192 
    193  if (comma) {
    194  str = comma + 1;
    195  *comma = '\0';
    196  }
    197  }
    198 
    199  *count = nArgs;
    200  return p;
    201 #endif
    202 }
    203 
    204 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
    205 {
    206  TRACE_CALL(__func__);
    207  return remmina_rdp_CommandLineParseCommaSeparatedValuesEx(NULL, list, count);
    208 }
    209 
    210 /*
    211  * End of CommandLineParseCommaSeparatedValuesEx() compatibility and copyright
    212  */
    214 {
    215  TRACE_CALL(__func__);
    216  UINT16 flags;
    217  rdpInput *input;
    218  rfContext *rfi = GET_PLUGIN_DATA(gp);
    219  RemminaPluginRdpEvent *event;
    220  DISPLAY_CONTROL_MONITOR_LAYOUT *dcml;
    221  CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
    222  RemminaFile *remminafile;
    223 
    224  if (rfi->event_queue == NULL)
    225  return true;
    226 
    227  input = rfi->instance->input;
    228 
    229  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    230 
    231  while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) {
    232  time(&last_time); //update last user interaction time
    233  switch (event->type) {
    235  flags = event->key_event.extended ? KBD_FLAGS_EXTENDED : 0;
    236  flags |= event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
    237  input->KeyboardEvent(input, flags, event->key_event.key_code);
    238  break;
    239 
    241  /*
    242  * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx
    243  */
    244  flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
    245  input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code);
    246  break;
    247 
    249  if (event->mouse_event.extended)
    250  input->ExtendedMouseEvent(input, event->mouse_event.flags,
    251  event->mouse_event.x, event->mouse_event.y);
    252  else
    253  input->MouseEvent(input, event->mouse_event.flags,
    254  event->mouse_event.x, event->mouse_event.y);
    255  break;
    256 
    258  rfi->clipboard.context->ClientFormatList(rfi->clipboard.context, event->clipboard_formatlist.pFormatList);
    259  free(event->clipboard_formatlist.pFormatList);
    260  break;
    261 
    263  response.msgFlags = (event->clipboard_formatdataresponse.data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
    264  response.dataLen = event->clipboard_formatdataresponse.size;
    265  response.requestedFormatData = event->clipboard_formatdataresponse.data;
    266  rfi->clipboard.context->ClientFormatDataResponse(rfi->clipboard.context, &response);
    267  break;
    268 
    270  REMMINA_PLUGIN_DEBUG("Sending client FormatDataRequest to server");
    271  gettimeofday(&(rfi->clipboard.clientformatdatarequest_tv), NULL);
    272  rfi->clipboard.context->ClientFormatDataRequest(rfi->clipboard.context, event->clipboard_formatdatarequest.pFormatDataRequest);
    273  free(event->clipboard_formatdatarequest.pFormatDataRequest);
    274  break;
    275 
    277  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    278  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    279  /* TODO Add an option for this */
    280  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    281  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    282  /* got some crashes with g_malloc0, to be investigated */
    283  dcml = calloc(freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
    284  REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:");
    285  if (!dcml)
    286  break;
    287 
    288  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    289  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
    290  const rdpMonitor *current = &base[i];
    291  REMMINA_PLUGIN_DEBUG("Sending display layout for monitor n° %d", i);
    292  dcml[i].Flags = (current->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
    293  REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags);
    294  dcml[i].Left = current->x;
    295  REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left);
    296  dcml[i].Top = current->y;
    297  REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top);
    298  dcml[i].Width = current->width;
    299  REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width);
    300  dcml[i].Height = current->height;
    301  REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height);
    302  dcml[i].PhysicalWidth = current->attributes.physicalWidth;
    303  REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth);
    304  dcml[i].PhysicalHeight = current->attributes.physicalHeight;
    305  REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight);
    306  if (current->attributes.orientation)
    307  dcml[i].Orientation = current->attributes.orientation;
    308  else
    309  dcml[i].Orientation = event->monitor_layout.desktopOrientation;
    310  REMMINA_PLUGIN_DEBUG("Monitor %d orientation: %d", i, dcml[i].Orientation);
    311  dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
    312  dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
    313  }
    314  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), dcml);
    315  g_free(dcml);
    316  } else {
    317  dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
    318  if (dcml) {
    319  dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
    320  dcml->Width = event->monitor_layout.width;
    321  dcml->Height = event->monitor_layout.height;
    322  dcml->Orientation = event->monitor_layout.desktopOrientation;
    323  dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
    324  dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
    325  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml);
    326  g_free(dcml); \
    327  }
    328  }
    329  break;
    331  /* Disconnect requested via GUI (i.e: tab destroy/close) */
    332  freerdp_abort_connect(rfi->instance);
    333  break;
    334  }
    335 
    336  g_free(event);
    337  }
    338 
    339  return true;
    340 }
    341 
    343 {
    344  TRACE_CALL(__func__);
    345 
    346  /* Opens the optional SSH tunnel if needed.
    347  * Used also when reopening the same tunnel for a FreeRDP reconnect.
    348  * Returns TRUE if all OK, and setups correct rfi->Settings values
    349  * with connection and certificate parameters */
    350 
    351  gchar *hostport;
    352  gchar *s;
    353  gchar *host;
    354  gchar *cert_host;
    355  gint cert_port;
    356  gint port;
    357 
    358  rfContext *rfi = GET_PLUGIN_DATA(gp);
    359 
    360  REMMINA_PLUGIN_DEBUG("Tunnel init");
    361  hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 3389, FALSE);
    362  if (hostport == NULL)
    363  return FALSE;
    364 
    365  remmina_plugin_service->get_server_port(hostport, 3389, &host, &port);
    366 
    367  if (host[0] == 0)
    368  return FALSE;
    369 
    370  REMMINA_PLUGIN_DEBUG("protocol_plugin_start_direct_tunnel() returned %s", hostport);
    371 
    372  cert_host = host;
    373  cert_port = port;
    374 
    375  if (!rfi->is_reconnecting) {
    376  /* settings->CertificateName and settings->ServerHostname is created
    377  * only on 1st connect, not on reconnections */
    378 
    379  freerdp_settings_set_string(rfi->settings, FreeRDP_ServerHostname, host);
    380 
    381  if (cert_port == 3389) {
    382  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, cert_host);
    383  } else {
    384  s = g_strdup_printf("%s:%d", cert_host, cert_port);
    385  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, s);
    386  g_free(s);
    387  }
    388  }
    389 
    390  REMMINA_PLUGIN_DEBUG("Tunnel has been optionally initialized. Now connecting to %s:%d", host, port);
    391 
    392  if (cert_host != host) g_free(cert_host);
    393  g_free(host);
    394  g_free(hostport);
    395 
    396  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ServerPort, port);
    397 
    398  return TRUE;
    399 }
    400 
    401 static BOOL rf_auto_reconnect(rfContext *rfi)
    402 {
    403  TRACE_CALL(__func__);
    404  rdpSettings *settings = rfi->instance->settings;
    406  time_t treconn;
    407  gchar *cval;
    408  gint maxattempts;
    409 
    411  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    412 
    413  rfi->is_reconnecting = TRUE;
    414  rfi->stop_reconnecting_requested = FALSE;
    415 
    416  /* Get the value set in FreeRDP_AutoReconnectMaxRetries (20) */
    417  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
    418  REMMINA_PLUGIN_DEBUG("maxattempts from default: %d", maxattempts);
    419  /* Get the value from the global preferences if any */
    420  if ((cval = remmina_plugin_service->pref_get_value("rdp_reconnect_attempts")) != NULL)
    421  maxattempts = atoi(cval);
    422  REMMINA_PLUGIN_DEBUG("maxattempts from general preferences: %d", maxattempts);
    423  /* Get the value from the profile if any, otherwise uses the value of maxattempts */
    424  maxattempts = remmina_plugin_service->file_get_int(remminafile, "rdp_reconnect_attempts", maxattempts);
    425  REMMINA_PLUGIN_DEBUG("maxattempts from general plugin: %d", maxattempts);
    426  /* If maxattemps is <= 0, we get the value from FreeRDP_AutoReconnectMaxRetries (20) */
    427  if (maxattempts <= 0)
    428  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
    429  freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, maxattempts);
    430  REMMINA_PLUGIN_DEBUG("maxattempts set to: %d", maxattempts);
    431 
    432  rfi->reconnect_maxattempts = maxattempts;
    433  rfi->reconnect_nattempt = 0;
    434 
    435  /* Only auto reconnect on network disconnects. */
    436  switch (freerdp_error_info(rfi->instance)) {
    437  case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
    438  /* Disconnected by server hitting a bug or resource limit */
    439  break;
    440  case ERRINFO_SUCCESS:
    441  /* A network disconnect was detected */
    442  break;
    443  default:
    444  rfi->is_reconnecting = FALSE;
    445  return FALSE;
    446  }
    447 
    448  if (!freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled)) {
    449  /* No auto-reconnect - just quit */
    450  rfi->is_reconnecting = FALSE;
    451  return FALSE;
    452  }
    453 
    454  /* A network disconnect was detected and we should try to reconnect */
    455  REMMINA_PLUGIN_DEBUG("[%s] network disconnection detected, initiating reconnection attempt",
    456  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    457 
    458  ui = g_new0(RemminaPluginRdpUiObject, 1);
    461 
    462  /* Sleep half a second to allow:
    463  * - processing of the UI event we just pushed on the queue
    464  * - better network conditions
    465  * Remember: We hare on a thread, so the main gui won’t lock */
    466  usleep(500000);
    467 
    468  /* Perform an auto-reconnect. */
    469  while (TRUE) {
    470  /* Quit retrying if max retries has been exceeded */
    471  if (rfi->reconnect_nattempt++ >= rfi->reconnect_maxattempts) {
    472  REMMINA_PLUGIN_DEBUG("[%s] maximum number of reconnection attempts exceeded.",
    473  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    474  break;
    475  }
    476 
    477  if (rfi->stop_reconnecting_requested) {
    478  REMMINA_PLUGIN_DEBUG("[%s] reconnect request loop interrupted by user.",
    479  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    480  break;
    481  }
    482 
    483  /* Attempt the next reconnect */
    484  REMMINA_PLUGIN_DEBUG("[%s] reconnection, attempt #%d of %d",
    485  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname), rfi->reconnect_nattempt, rfi->reconnect_maxattempts);
    486 
    487  ui = g_new0(RemminaPluginRdpUiObject, 1);
    490 
    491  treconn = time(NULL);
    492 
    493  /* Reconnect the SSH tunnel, if needed */
    495  REMMINA_PLUGIN_DEBUG("[%s] unable to recreate tunnel with remmina_rdp_tunnel_init.",
    496  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    497  } else {
    498  if (freerdp_reconnect(rfi->instance)) {
    499  /* Reconnection is successful */
    500  REMMINA_PLUGIN_DEBUG("[%s] reconnected.", freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    501  rfi->is_reconnecting = FALSE;
    502  return TRUE;
    503  }
    504  }
    505 
    506  /* Wait until 5 secs have elapsed from last reconnect attempt, while checking for rfi->stop_reconnecting_requested */
    507  while (time(NULL) - treconn < 5) {
    509  break;
    510  usleep(200000); // 200ms sleep
    511  }
    512  }
    513 
    514  rfi->is_reconnecting = FALSE;
    515  return FALSE;
    516 }
    517 
    518 static BOOL rf_begin_paint(rdpContext *context)
    519 {
    520  TRACE_CALL(__func__);
    521  rdpGdi *gdi;
    522 
    523  if (!context)
    524  return FALSE;
    525 
    526  gdi = context->gdi;
    527  if (!gdi || !gdi->primary || !gdi->primary->hdc || !gdi->primary->hdc->hwnd)
    528  return FALSE;
    529 
    530  return TRUE;
    531 }
    532 
    533 static BOOL rf_end_paint(rdpContext *context)
    534 {
    535  TRACE_CALL(__func__);
    536  rdpGdi *gdi;
    537  rfContext *rfi;
    539  int i, ninvalid;
    540  region *reg;
    541  HGDI_RGN cinvalid;
    542 
    543  gdi = context->gdi;
    544  rfi = (rfContext *)context;
    545 
    546  if (gdi == NULL || gdi->primary == NULL || gdi->primary->hdc == NULL || gdi->primary->hdc->hwnd == NULL)
    547  return TRUE;
    548 
    549  if (gdi->primary->hdc->hwnd->invalid->null)
    550  return TRUE;
    551 
    552  if (gdi->primary->hdc->hwnd->ninvalid < 1)
    553  return TRUE;
    554 
    555  ninvalid = gdi->primary->hdc->hwnd->ninvalid;
    556  cinvalid = gdi->primary->hdc->hwnd->cinvalid;
    557  reg = (region *)g_malloc(sizeof(region) * ninvalid);
    558  for (i = 0; i < ninvalid; i++) {
    559  reg[i].x = cinvalid[i].x;
    560  reg[i].y = cinvalid[i].y;
    561  reg[i].w = cinvalid[i].w;
    562  reg[i].h = cinvalid[i].h;
    563  }
    564 
    565  ui = g_new0(RemminaPluginRdpUiObject, 1);
    567  ui->reg.ninvalid = ninvalid;
    568  ui->reg.ureg = reg;
    569 
    571 
    572 
    573  gdi->primary->hdc->hwnd->invalid->null = TRUE;
    574  gdi->primary->hdc->hwnd->ninvalid = 0;
    575 
    576 
    577  return TRUE;
    578 }
    579 
    580 static BOOL rf_desktop_resize(rdpContext *context)
    581 {
    582  TRACE_CALL(__func__);
    583  rfContext *rfi;
    586  UINT32 w, h;
    587 
    588  rfi = (rfContext *)context;
    589  gp = rfi->protocol_widget;
    590 
    591  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    592  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
    593  remmina_plugin_service->protocol_plugin_set_width(gp, w);
    594  remmina_plugin_service->protocol_plugin_set_height(gp, h);
    595 
    596  ui = g_new0(RemminaPluginRdpUiObject, 1);
    600 
    601  /* Tell libfreerdp to change its internal GDI bitmap width and heigt,
    602  * this will also destroy gdi->primary_buffer, making our rfi->surface invalid */
    603  gdi_resize(((rdpContext *)rfi)->gdi, w, h);
    604 
    605  /* Call to remmina_rdp_event_update_scale(gp) on the main UI thread,
    606  * this will recreate rfi->surface from gdi->primary_buffer */
    607 
    608  ui = g_new0(RemminaPluginRdpUiObject, 1);
    612 
    613  remmina_plugin_service->protocol_plugin_desktop_resize(gp);
    614 
    615  return TRUE;
    616 }
    617 
    618 static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
    619 {
    620  TRACE_CALL(__func__);
    621  rfContext *rfi;
    623  GdkDisplay *disp;
    624 
    625  rfi = (rfContext *)context;
    626  gp = rfi->protocol_widget;
    627 
    628  disp = gtk_widget_get_display(GTK_WIDGET(gp));
    629  gdk_display_beep(disp);
    630 
    631  return TRUE;
    632 }
    633 
    634 static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
    635 {
    636  TRACE_CALL(__func__);
    637  rfContext *rfi;
    639  GdkDisplay *disp;
    640 
    641  rfi = (rfContext *)context;
    642  gp = rfi->protocol_widget;
    643  disp = gtk_widget_get_display(GTK_WIDGET(gp));
    644 
    645 #ifdef GDK_WINDOWING_X11
    646  if (GDK_IS_X11_DISPLAY(disp)) {
    647  /* TODO: We are not on the main thread. Will X.Org complain? */
    648  Display *x11_display;
    649  x11_display = gdk_x11_display_get_xdisplay(disp);
    650  XkbLockModifiers(x11_display, XkbUseCoreKbd,
    651  LockMask | Mod2Mask,
    652  ((led_flags & KBD_SYNC_CAPS_LOCK) ? LockMask : 0) |
    653  ((led_flags & KBD_SYNC_NUM_LOCK) ? Mod2Mask : 0)
    654  );
    655 
    656  /* TODO: Add support to KANA_LOCK and SCROLL_LOCK */
    657  }
    658 #endif
    659 
    660  return TRUE;
    661 }
    662 
    663 static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState,
    664  UINT32 imeConvMode)
    665 {
    666  TRACE_CALL(__func__);
    667  if (!context)
    668  return FALSE;
    669 
    670  /* Unimplemented, we ignore it */
    671 
    672  return TRUE;
    673 }
    674 
    675 static BOOL remmina_rdp_pre_connect(freerdp *instance)
    676 {
    677  TRACE_CALL(__func__);
    678  rdpChannels *channels;
    679  rdpSettings *settings;
    680  rdpContext *context = instance->context;
    681 
    682  settings = instance->settings;
    683  channels = context->channels;
    684  freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX);
    685  freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
    686  freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE);
    687  freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 1);
    688 
    689  PubSub_SubscribeChannelConnected(instance->context->pubSub,
    691  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
    693 
    694  if (!freerdp_client_load_addins(channels, settings))
    695  return FALSE;
    696 
    697  return true;
    698 }
    699 
    700 static BOOL remmina_rdp_post_connect(freerdp *instance)
    701 {
    702  TRACE_CALL(__func__);
    703  rfContext *rfi;
    706  UINT32 freerdp_local_color_format;
    707 
    708  rfi = (rfContext *)instance->context;
    709  gp = rfi->protocol_widget;
    710  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK;
    711 
    712  rfi->attempt_interactive_authentication = FALSE; // We authenticated!
    713 
    714  rfi->srcBpp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth);
    715 
    716  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) == FALSE)
    717  rfi->sw_gdi = TRUE;
    718 
    719  rf_register_graphics(instance->context->graphics);
    720 
    721  REMMINA_PLUGIN_DEBUG("bpp: %d", rfi->bpp);
    722  switch (rfi->bpp) {
    723  case 24:
    724  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
    725  freerdp_local_color_format = PIXEL_FORMAT_BGRX32;
    726  rfi->cairo_format = CAIRO_FORMAT_RGB24;
    727  break;
    728  case 32:
    733  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
    734  freerdp_local_color_format = PIXEL_FORMAT_BGRA32;
    735  rfi->cairo_format = CAIRO_FORMAT_RGB24;
    736  break;
    737  default:
    738  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB16_565");
    739  freerdp_local_color_format = PIXEL_FORMAT_RGB16;
    740  rfi->cairo_format = CAIRO_FORMAT_RGB16_565;
    741  break;
    742  }
    743 
    744  if (!gdi_init(instance, freerdp_local_color_format)) {
    745  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_GDI_INIT;
    746  return FALSE;
    747  }
    748 
    749  if (instance->context->codecs->h264 == NULL && freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
    750  gdi_free(instance);
    751  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_NO_H264;
    752  return FALSE;
    753  }
    754 
    755  // pointer_cache_register_callbacks(instance->update);
    756 
    757  instance->update->BeginPaint = rf_begin_paint;
    758  instance->update->EndPaint = rf_end_paint;
    759  instance->update->DesktopResize = rf_desktop_resize;
    760 
    761  instance->update->PlaySound = rf_play_sound;
    762  instance->update->SetKeyboardIndicators = rf_keyboard_set_indicators;
    763  instance->update->SetKeyboardImeStatus = rf_keyboard_set_ime_status;
    764 
    766  rfi->connected = true;
    767 
    768  ui = g_new0(RemminaPluginRdpUiObject, 1);
    771 
    772  return TRUE;
    773 }
    774 
    775 static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
    776 {
    777  TRACE_CALL(__func__);
    778  gchar *s_username, *s_password, *s_domain;
    779  gint ret;
    780  rfContext *rfi;
    782  gboolean save;
    783  gboolean disablepasswordstoring;
    784  RemminaFile *remminafile;
    785 
    786  rfi = (rfContext *)instance->context;
    787  gp = rfi->protocol_widget;
    788  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    789  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
    790 
    791  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    793  _("Enter RDP authentication credentials"),
    794  remmina_plugin_service->file_get_string(remminafile, "username"),
    795  remmina_plugin_service->file_get_string(remminafile, "password"),
    796  remmina_plugin_service->file_get_string(remminafile, "domain"),
    797  NULL);
    798  if (ret == GTK_RESPONSE_OK) {
    799  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
    800  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_Username, s_username);
    801 
    802  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
    803  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s_password);
    804 
    805  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
    806  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, s_domain);
    807 
    808  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
    809  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
    810 
    811  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
    812  if (save) {
    813  // User has requested to save credentials. We put the password
    814  // into remminafile->settings. It will be saved later, on successful connection, by
    815  // rcw.c
    816  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
    817  } else {
    818  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
    819  }
    820 
    821 
    822  if (s_username) g_free(s_username);
    823  if (s_password) g_free(s_password);
    824  if (s_domain) g_free(s_domain);
    825 
    826  return TRUE;
    827  } else {
    828  return FALSE;
    829  }
    830 
    831  return TRUE;
    832 }
    833 
    834 static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
    835 {
    836  TRACE_CALL(__func__);
    837  gchar *s_username, *s_password, *s_domain;
    838  gint ret;
    839  rfContext *rfi;
    841  gboolean save;
    842  gboolean disablepasswordstoring;
    843  gboolean basecredforgw;
    844  RemminaFile *remminafile;
    845 
    846  rfi = (rfContext *)instance->context;
    847  gp = rfi->protocol_widget;
    848  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    849 
    850  if (!remmina_plugin_service->file_get_string(remminafile, "gateway_server"))
    851  return false;
    852  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
    853  basecredforgw = remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE);
    854 
    855  if (basecredforgw) {
    856  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    858  _("Enter RDP authentication credentials"),
    859  remmina_plugin_service->file_get_string(remminafile, "username"),
    860  remmina_plugin_service->file_get_string(remminafile, "password"),
    861  remmina_plugin_service->file_get_string(remminafile, "domain"),
    862  NULL);
    863  } else {
    864  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    866  _("Enter RDP gateway authentication credentials"),
    867  remmina_plugin_service->file_get_string(remminafile, "gateway_username"),
    868  remmina_plugin_service->file_get_string(remminafile, "gateway_password"),
    869  remmina_plugin_service->file_get_string(remminafile, "gateway_domain"),
    870  NULL);
    871  }
    872 
    873 
    874  if (ret == GTK_RESPONSE_OK) {
    875  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
    876  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, s_username);
    877 
    878  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
    879  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s_password);
    880 
    881  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
    882  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, s_domain);
    883 
    884  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
    885 
    886  if (basecredforgw) {
    887  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
    888  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
    889  if (save)
    890  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
    891  else
    892  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
    893  } else {
    894  remmina_plugin_service->file_set_string(remminafile, "gateway_username", s_username);
    895  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", s_domain);
    896  if (save)
    897  remmina_plugin_service->file_set_string(remminafile, "gateway_password", s_password);
    898  else
    899  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
    900  }
    901 
    902  if (s_username) g_free(s_username);
    903  if (s_password) g_free(s_password);
    904  if (s_domain) g_free(s_domain);
    905 
    906  return true;
    907  } else {
    908  return false;
    909  }
    910 
    911  return true;
    912 }
    913 
    914 static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
    915  const char *common_name, const char *subject,
    916  const char *issuer, const char *fingerprint, DWORD flags)
    917 {
    918  TRACE_CALL(__func__);
    919  gint status;
    920  rfContext *rfi;
    922 
    923  rfi = (rfContext *)instance->context;
    924  gp = rfi->protocol_widget;
    925 
    926  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
    927 
    928  if (status == GTK_RESPONSE_OK)
    929  return 1;
    930 
    931  return 0;
    932 }
    933 
    934 static DWORD
    935 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__ ((unused));
    936 static DWORD
    937 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
    938  const char *issuer, const char *fingerprint, BOOL host_mismatch)
    939 {
    940  TRACE_CALL(__func__);
    941  gint status;
    942  rfContext *rfi;
    944 
    945  rfi = (rfContext *)instance->context;
    946  gp = rfi->protocol_widget;
    947 
    948  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
    949 
    950  if (status == GTK_RESPONSE_OK)
    951  return 1;
    952 
    953  return 0;
    954 }
    955 
    956 static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
    957  const char *common_name, const char *subject,
    958  const char *issuer, const char *fingerprint,
    959  const char *old_subject, const char *old_issuer,
    960  const char *old_fingerprint, DWORD flags)
    961 {
    962  TRACE_CALL(__func__);
    963  gint status;
    964  rfContext *rfi;
    966 
    967  rfi = (rfContext *)instance->context;
    968  gp = rfi->protocol_widget;
    969 
    970  status = remmina_plugin_service->protocol_plugin_changed_certificate(gp, subject, issuer, fingerprint, old_fingerprint);
    971 
    972  if (status == GTK_RESPONSE_OK)
    973  return 1;
    974 
    975  return 0;
    976 }
    977 
    978 static void remmina_rdp_post_disconnect(freerdp *instance)
    979 {
    980  TRACE_CALL(__func__);
    981 
    982  if (!instance || !instance->context)
    983  return;
    984 
    985  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
    987  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
    989 
    990  /* The remaining cleanup will be continued on main thread by complete_cleanup_on_main_thread() */
    991 }
    992 
    994 {
    995  TRACE_CALL(__func__);
    996  DWORD status;
    997  gchar buf[100];
    998  rfContext *rfi = GET_PLUGIN_DATA(gp);
    999  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1000  time_t cur_time, time_diff;
    1001 
    1002  int jitter_time = remmina_plugin_service->file_get_int(remminafile, "rdp_mouse_jitter", 0);
    1003  time(&last_time);
    1004  while (!freerdp_shall_disconnect(rfi->instance)) {
    1005  //move mouse if we've been idle and option is selected
    1006  time(&cur_time);
    1007  time_diff = cur_time - last_time;
    1008  if (jitter_time > 0 && time_diff > jitter_time){
    1009  last_time = cur_time;
    1011  }
    1012 
    1013  HANDLE handles[64]={0};
    1014  DWORD nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64);
    1015  if (rfi->event_handle)
    1016  handles[nCount++] = rfi->event_handle;
    1017 
    1018  handles[nCount++] = rfi->instance->context->abortEvent;
    1019 
    1020  if (nCount == 0) {
    1021  fprintf(stderr, "freerdp_get_event_handles failed\n");
    1022  break;
    1023  }
    1024 
    1025  status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
    1026 
    1027  if (status == WAIT_FAILED) {
    1028  fprintf(stderr, "WaitForMultipleObjects failed with %lu\n", (unsigned long)status);
    1029  break;
    1030  }
    1031 
    1032  if (rfi->event_handle && WaitForSingleObject(rfi->event_handle, 0) == WAIT_OBJECT_0) {
    1033  if (!rf_process_event_queue(gp)) {
    1034  fprintf(stderr, "Could not process local keyboard/mouse event queue\n");
    1035  break;
    1036  }
    1037  if (read(rfi->event_pipe[0], buf, sizeof(buf))) {
    1038  }
    1039  }
    1040 
    1041  /* Check if a processed event called freerdp_abort_connect() and exit if true */
    1042  if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0)
    1043  /* Session disconnected by local user action */
    1044  break;
    1045 
    1046  if (!freerdp_check_event_handles(rfi->instance->context)) {
    1047  if (rf_auto_reconnect(rfi)) {
    1048  /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */
    1049  remmina_plugin_service->protocol_plugin_set_error(gp, NULL);
    1050  continue;
    1051  }
    1052  if (freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS)
    1053  fprintf(stderr, "Could not check FreeRDP file descriptor\n");
    1054  break;
    1055  }
    1056  }
    1057  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
    1058  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    1059  REMMINA_PLUGIN_AUDIT(_("Disconnected from %s via RDP"), host);
    1060  freerdp_disconnect(rfi->instance);
    1061  REMMINA_PLUGIN_DEBUG("RDP client disconnected");
    1062 }
    1063 
    1064 static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
    1065 {
    1066  TRACE_CALL(__func__);
    1067  PVIRTUALCHANNELENTRY entry = NULL;
    1068  PVIRTUALCHANNELENTRYEX entryEx = NULL;
    1069 
    1070  entryEx = (PVIRTUALCHANNELENTRYEX)(void *)freerdp_load_channel_addin_entry(
    1071  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
    1072 
    1073  if (!entryEx)
    1074  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
    1075 
    1076  if (entryEx) {
    1077  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0) {
    1078  fprintf(stderr, "loading channel %s\n", name);
    1079  return TRUE;
    1080  }
    1081  } else if (entry) {
    1082  if (freerdp_channels_client_load(channels, settings, entry, data) == 0) {
    1083  fprintf(stderr, "loading channel %s\n", name);
    1084  return TRUE;
    1085  }
    1086  }
    1087 
    1088  return FALSE;
    1089 }
    1090 
    1091 static gchar *remmina_rdp_find_prdriver(char *smap, char *prn)
    1092 {
    1093  char c, *p, *dr;
    1094  int matching;
    1095  size_t sz;
    1096 
    1097  enum { S_WAITPR,
    1098  S_INPRINTER,
    1099  S_WAITCOLON,
    1100  S_WAITDRIVER,
    1101  S_INDRIVER,
    1102  S_WAITSEMICOLON } state = S_WAITPR;
    1103 
    1104  matching = 0;
    1105  while ((c = *smap++) != 0) {
    1106  switch (state) {
    1107  case S_WAITPR:
    1108  if (c != '\"') return NULL;
    1109  state = S_INPRINTER;
    1110  p = prn;
    1111  matching = 1;
    1112  break;
    1113  case S_INPRINTER:
    1114  if (matching && c == *p && *p != 0) {
    1115  p++;
    1116  } else if (c == '\"') {
    1117  if (*p != 0)
    1118  matching = 0;
    1119  state = S_WAITCOLON;
    1120  } else {
    1121  matching = 0;
    1122  }
    1123  break;
    1124  case S_WAITCOLON:
    1125  if (c != ':')
    1126  return NULL;
    1127  state = S_WAITDRIVER;
    1128  break;
    1129  case S_WAITDRIVER:
    1130  if (c != '\"')
    1131  return NULL;
    1132  state = S_INDRIVER;
    1133  dr = smap;
    1134  break;
    1135  case S_INDRIVER:
    1136  if (c == '\"') {
    1137  if (matching)
    1138  goto found;
    1139  else
    1140  state = S_WAITSEMICOLON;
    1141  }
    1142  break;
    1143  case S_WAITSEMICOLON:
    1144  if (c != ';')
    1145  return NULL;
    1146  state = S_WAITPR;
    1147  break;
    1148  }
    1149  }
    1150  return NULL;
    1151 
    1152 found:
    1153  sz = smap - dr;
    1154  p = (char *)malloc(sz);
    1155  memcpy(p, dr, sz);
    1156  p[sz - 1] = 0;
    1157  return p;
    1158 }
    1159 
    1160 #ifdef HAVE_CUPS
    1161 
    1166 static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
    1167 {
    1168  rfContext *rfi = (rfContext *)user_data;
    1170 
    1185  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1186  const gchar *s = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
    1187 
    1188  RDPDR_PRINTER *printer;
    1189  printer = (RDPDR_PRINTER *)calloc(1, sizeof(RDPDR_PRINTER));
    1190 
    1191 #ifdef WITH_FREERDP3
    1192  RDPDR_DEVICE *pdev;
    1193  pdev = &(printer->device);
    1194 #else
    1195  RDPDR_PRINTER *pdev;
    1196  pdev = printer;
    1197 #endif
    1198 
    1199  pdev->Type = RDPDR_DTYP_PRINT;
    1200  REMMINA_PLUGIN_DEBUG("Printer Type: %d", pdev->Type);
    1201 
    1202  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectPrinters, TRUE);
    1203  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    1204 
    1205  REMMINA_PLUGIN_DEBUG("Destination: %s", dest->name);
    1206  if (!(pdev->Name = _strdup(dest->name))) {
    1207  free(printer);
    1208  return 1;
    1209  }
    1210 
    1211  REMMINA_PLUGIN_DEBUG("Printer Name: %s", pdev->Name);
    1212 
    1213  if (s) {
    1214  gchar *d = remmina_rdp_find_prdriver(strdup(s), pdev->Name);
    1215  if (d) {
    1216  printer->DriverName = strdup(d);
    1217  REMMINA_PLUGIN_DEBUG("Printer DriverName set to: %s", printer->DriverName);
    1218  g_free(d);
    1219  } else {
    1225  free(pdev->Name);
    1226  free(printer);
    1227  return 1;
    1228  }
    1229  } else {
    1230  /* We set to a default driver*/
    1231  printer->DriverName = _strdup("MS Publisher Imagesetter");
    1232  }
    1233 
    1234  REMMINA_PLUGIN_DEBUG("Printer Driver: %s", printer->DriverName);
    1235  if (!freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)printer)) {
    1236  free(printer->DriverName);
    1237  free(pdev->Name);
    1238  free(printer);
    1239  return 1;
    1240  }
    1241 
    1242  return 1;
    1243 }
    1244 #endif /* HAVE_CUPS */
    1245 
    1246 /* Send Ctrl+Alt+Del keystrokes to the plugin drawing_area widget */
    1248 {
    1249  TRACE_CALL(__func__);
    1250  guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
    1251  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1252 
    1253  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
    1254  keys, G_N_ELEMENTS(keys), GDK_KEY_PRESS | GDK_KEY_RELEASE);
    1255 }
    1256 
    1257 static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
    1258 {
    1259  freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type);
    1260 
    1261  if (type == CONNECTION_TYPE_MODEM) {
    1262  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1263  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1264  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
    1265  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1266  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1267  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, TRUE);
    1268  } else if (type == CONNECTION_TYPE_BROADBAND_LOW) {
    1269  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1270  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1271  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
    1272  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1273  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1274  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1275  } else if (type == CONNECTION_TYPE_SATELLITE) {
    1276  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1277  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1278  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1279  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1280  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1281  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1282  } else if (type == CONNECTION_TYPE_BROADBAND_HIGH) {
    1283  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1284  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1285  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1286  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1287  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1288  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1289  } else if (type == CONNECTION_TYPE_WAN) {
    1290  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1291  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1292  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1293  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1294  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1295  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1296  } else if (type == CONNECTION_TYPE_LAN) {
    1297  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1298  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1299  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1300  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1301  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1302  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1303  } else if (type == CONNECTION_TYPE_AUTODETECT) {
    1304  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1305  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1306  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1307  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1308  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1309  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1310  freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE);
    1311 
    1312  /* Automatically activate GFX and RFX codec support */
    1313 #ifdef WITH_GFX_H264
    1314  freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1315  freerdp_settings_set_bool(settings, FreeRDP_GfxH264, gfx_h264_available);
    1316 #endif
    1317  freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE);
    1318  freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1319  } else if (type == REMMINA_CONNECTION_TYPE_NONE) {
    1320  return FALSE;
    1321  } else {
    1322  return FALSE;
    1323  }
    1324 
    1325  return TRUE;
    1326 }
    1327 
    1328 #ifdef GDK_WINDOWING_X11
    1329 #if FREERDP_CHECK_VERSION(2, 3, 0)
    1330 static gchar *remmina_get_rdp_kbd_remap(const gchar *keymap)
    1331 {
    1332  TRACE_CALL(__func__);
    1333  guint *table;
    1334  gchar keys[20];
    1335  gchar *rdp_kbd_remap = NULL;
    1336  gint i;
    1337  Display *display;
    1338 
    1339  table = remmina_plugin_service->pref_keymap_get_table(keymap);
    1340  if (!table)
    1341  return rdp_kbd_remap;
    1342  rdp_kbd_remap = g_malloc0(512);
    1343  display = XOpenDisplay(0);
    1344  for (i = 0; table[i] > 0; i += 2) {
    1345  g_snprintf(keys, sizeof(keys), "0x%02x=0x%02x", freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i])),
    1346  freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i + 1])));
    1347  if (i > 0)
    1348  g_strlcat(rdp_kbd_remap, ",", 512);
    1349  g_strlcat(rdp_kbd_remap, keys, 512);
    1350  }
    1351  XCloseDisplay(display);
    1352 
    1353  return rdp_kbd_remap;
    1354 }
    1355 #endif
    1356 #endif
    1357 
    1359 {
    1360  TRACE_CALL(__func__);
    1361  const gchar *s;
    1362  gchar *sm;
    1363  gchar *value;
    1364  const gchar *cs;
    1365  RemminaFile *remminafile;
    1366  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1367  rdpChannels *channels;
    1368  gchar *gateway_host;
    1369  gint gateway_port;
    1370  gchar *datapath = NULL;
    1371  gboolean status = TRUE;
    1372 #ifdef GDK_WINDOWING_X11
    1373  gchar *rdp_kbd_remap;
    1374 #endif
    1375  gint i;
    1376 
    1377  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
    1378 
    1379  channels = rfi->instance->context->channels;
    1380 
    1381  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1382 
    1383  datapath = g_build_path("/",
    1384  remmina_plugin_service->file_get_user_datadir(),
    1385  "RDP",
    1386  NULL);
    1387  REMMINA_PLUGIN_DEBUG("RDP data path is %s", datapath);
    1388 
    1389  if ((datapath != NULL) && (datapath[0] != '\0'))
    1390  if (access(datapath, W_OK) == 0)
    1391  freerdp_settings_set_string(rfi->settings, FreeRDP_ConfigPath, datapath);
    1392  g_free(datapath);
    1393 
    1394  if (remmina_plugin_service->file_get_int(remminafile, "assistance_mode", 0)){
    1395  rdpAssistanceFile* file = freerdp_assistance_file_new();
    1396  if (!file){
    1397  REMMINA_PLUGIN_DEBUG("Could not allocate assistance file structure");
    1398  return FALSE;
    1399  }
    1400 
    1401  if (remmina_plugin_service->file_get_string(remminafile, "assistance_file") == NULL ||
    1402  remmina_plugin_service->file_get_string(remminafile, "assistance_pass") == NULL ){
    1403 
    1404  REMMINA_PLUGIN_DEBUG("Assistance file and password are not set while assistance mode is on");
    1405  return FALSE;
    1406  }
    1407 
    1408  status = freerdp_assistance_parse_file(file,
    1409  remmina_plugin_service->file_get_string(remminafile, "assistance_file"),
    1410  remmina_plugin_service->file_get_string(remminafile, "assistance_pass"));
    1411 
    1412  if (status < 0){
    1413  REMMINA_PLUGIN_DEBUG("Could not parse assistance file");
    1414  return FALSE;
    1415  }
    1416 
    1417 
    1418  if (!freerdp_assistance_populate_settings_from_assistance_file(file, rfi->settings)){
    1419  REMMINA_PLUGIN_DEBUG("Could not populate settings from assistance file");
    1420  return FALSE;
    1421  }
    1422  }
    1423 
    1424 
    1425 #if defined(PROXY_TYPE_IGNORE)
    1426  if (!remmina_plugin_service->file_get_int(remminafile, "useproxyenv", FALSE) ? TRUE : FALSE) {
    1427  REMMINA_PLUGIN_DEBUG("Not using system proxy settings");
    1428  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
    1429  }
    1430 #endif
    1431 
    1432  if (!remmina_rdp_tunnel_init(gp))
    1433  return FALSE;
    1434 
    1435  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, (remmina_plugin_service->file_get_int(remminafile, "disableautoreconnect", FALSE) ? FALSE : TRUE));
    1436  /* Disable RDP auto reconnection when SSH tunnel is enabled */
    1437  if (remmina_plugin_service->file_get_int(remminafile, "ssh_tunnel_enabled", FALSE))
    1438  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, FALSE);
    1439 
    1440  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, remmina_plugin_service->file_get_int(remminafile, "colordepth", 99));
    1441 
    1442  freerdp_settings_set_bool(rfi->settings, FreeRDP_SoftwareGdi, TRUE);
    1443  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    1444 
    1445  /* Avoid using H.264 modes if they are not available on libfreerdp */
    1446  if (!gfx_h264_available && (freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth) == 65 || freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth == 66)))
    1447  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 64); // Fallback to GFX RFX
    1448 
    1449  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 0) {
    1450  /* RFX (Win7)*/
    1451  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1452  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, FALSE);
    1453  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1454  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 63) {
    1455  /* /gfx (RFX Progressive) (Win8) */
    1456  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1457  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1458  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
    1459  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1460  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 64) {
    1461  /* /gfx:rfx (Win8) */
    1462  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1463  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1464  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1465  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
    1466  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1467  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 65) {
    1468  /* /gfx:avc420 (Win8.1) */
    1469  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1470  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1471  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1472  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1473  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 66) {
    1474  /* /gfx:avc444 (Win10) */
    1475  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1476  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1477  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1478  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1479  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 99) {
    1480  /* Automatic (Let the server choose its best format) */
    1481  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1482  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1483  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1484  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1485  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1486  }
    1487 
    1488  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) ||
    1489  freerdp_settings_get_bool(rfi->settings, FreeRDP_NSCodec) ||
    1490  freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
    1491  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
    1492  freerdp_settings_set_bool(rfi->settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
    1493  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1494  rfi->bpp = 32;
    1495  }
    1496 
    1497  gint w = remmina_plugin_service->get_profile_remote_width(gp);
    1498  gint h = remmina_plugin_service->get_profile_remote_height(gp);
    1499  /* multiple of 4 */
    1500  w = (w + 3) & ~0x3;
    1501  h = (h + 3) & ~0x3;
    1502  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, w);
    1503  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, h);
    1504  REMMINA_PLUGIN_DEBUG("Resolution set by the user: %dx%d", w, h);
    1505 
    1506  /* Workaround for FreeRDP issue #5417: in GFX AVC modes we can't go under
    1507  * AVC_MIN_DESKTOP_WIDTH x AVC_MIN_DESKTOP_HEIGHT */
    1508  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline) &&
    1509  freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
    1510  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) <
    1511  AVC_MIN_DESKTOP_WIDTH)
    1512  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth,
    1513  AVC_MIN_DESKTOP_WIDTH);
    1514  if (freerdp_settings_get_uint32(rfi->settings,
    1515  FreeRDP_DesktopHeight) <
    1516  AVC_MIN_DESKTOP_HEIGHT)
    1517  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight,
    1518  AVC_MIN_DESKTOP_HEIGHT);
    1519  }
    1520 
    1521  /* Workaround for FreeRDP issue #5119. This will make our horizontal resolution
    1522  * an even value, but it will add a vertical black 1 pixel line on the
    1523  * right of the desktop */
    1524  if ((freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) & 1) != 0) {
    1525  UINT32 tmp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    1526  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, tmp - 1);
    1527  }
    1528 
    1529  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
    1530  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    1531 
    1532  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    1533  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
    1534  REMMINA_PLUGIN_DEBUG("Resolution set after workarounds: %dx%d", w, h);
    1535 
    1536 
    1537  if (remmina_plugin_service->file_get_string(remminafile, "username"))
    1538  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, remmina_plugin_service->file_get_string(remminafile, "username"));
    1539 
    1540  if (remmina_plugin_service->file_get_string(remminafile, "domain"))
    1541  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, remmina_plugin_service->file_get_string(remminafile, "domain"));
    1542 
    1543  s = remmina_plugin_service->file_get_string(remminafile, "password");
    1544  if (s) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s);
    1545 
    1546  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoLogonEnabled, TRUE);
    1547 
    1552  gchar *proxy_type = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_type"));
    1553  gchar *proxy_username = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_username"));
    1554  gchar *proxy_password = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_password"));
    1555  gchar *proxy_hostname = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_hostname"));
    1556  gint proxy_port = remmina_plugin_service->file_get_int(remminafile, "proxy_port", 80);
    1557  REMMINA_PLUGIN_DEBUG("proxy_type: %s", proxy_type);
    1558  REMMINA_PLUGIN_DEBUG("proxy_username: %s", proxy_username);
    1559  REMMINA_PLUGIN_DEBUG("proxy_password: %s", proxy_password);
    1560  REMMINA_PLUGIN_DEBUG("proxy_hostname: %s", proxy_hostname);
    1561  REMMINA_PLUGIN_DEBUG("proxy_port: %d", proxy_port);
    1562  if (proxy_type && proxy_hostname) {
    1563  if (g_strcmp0(proxy_type, "no_proxy") == 0)
    1564  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
    1565  else if (g_strcmp0(proxy_type, "http") == 0)
    1566  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP);
    1567  else if (g_strcmp0(proxy_type, "socks5") == 0)
    1568  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS);
    1569  else
    1570  g_warning("Invalid proxy protocol, at the moment only no_proxy, HTTP and SOCKS5 are supported");
    1571  REMMINA_PLUGIN_DEBUG("ProxyType set to: %" PRIu32, freerdp_settings_get_uint32(rfi->settings, FreeRDP_ProxyType));
    1572  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyHostname, proxy_hostname);
    1573  if (proxy_username)
    1574  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyUsername, proxy_username);
    1575  if (proxy_password)
    1576  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyPassword, proxy_password);
    1577  if (proxy_port)
    1578  freerdp_settings_set_uint16(rfi->settings, FreeRDP_ProxyPort, proxy_port);
    1579  }
    1580  g_free(proxy_hostname);
    1581  g_free(proxy_username);
    1582  g_free(proxy_password);
    1583 
    1584  if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)) {
    1585  // Reset gateway credentials
    1586  remmina_plugin_service->file_set_string(remminafile, "gateway_username", NULL);
    1587  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", NULL);
    1588  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
    1589  }
    1590 
    1591  /* Remote Desktop Gateway server address */
    1592  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, FALSE);
    1593  s = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
    1594  if (s) {
    1595  cs = remmina_plugin_service->file_get_string(remminafile, "gwtransp");
    1596 #if FREERDP_CHECK_VERSION(2, 3, 1)
    1597  if (remmina_plugin_service->file_get_int(remminafile, "websockets", FALSE))
    1598  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, TRUE);
    1599  else
    1600  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, FALSE);
    1601 #endif
    1602  if (g_strcmp0(cs, "http") == 0) {
    1603  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, FALSE);
    1604  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
    1605  } else if (g_strcmp0(cs, "rpc") == 0) {
    1606  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
    1607  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, FALSE);
    1608  } else if (g_strcmp0(cs, "auto") == 0) {
    1609  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
    1610  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
    1611  }
    1612  remmina_plugin_service->get_server_port(s, 443, &gateway_host, &gateway_port);
    1613  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayHostname, gateway_host);
    1614  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GatewayPort, gateway_port);
    1615  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, TRUE);
    1616  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, TRUE);
    1617  }
    1618  /* Remote Desktop Gateway domain */
    1619  if (remmina_plugin_service->file_get_string(remminafile, "gateway_domain")) {
    1620  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, remmina_plugin_service->file_get_string(remminafile, "gateway_domain"));
    1621  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1622  }
    1623  /* Remote Desktop Gateway username */
    1624  if (remmina_plugin_service->file_get_string(remminafile, "gateway_username")) {
    1625  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, remmina_plugin_service->file_get_string(remminafile, "gateway_username"));
    1626  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1627  }
    1628  /* Remote Desktop Gateway password */
    1629  s = remmina_plugin_service->file_get_string(remminafile, "gateway_password");
    1630  if (s) {
    1631  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s);
    1632  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1633  }
    1634  /* If no different credentials were provided for the Remote Desktop Gateway
    1635  * use the same authentication credentials for the host */
    1636  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled) && freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials)) {
    1637  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, freerdp_settings_get_string(rfi->settings, FreeRDP_Domain));
    1638  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, freerdp_settings_get_string(rfi->settings, FreeRDP_Username));
    1639  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, freerdp_settings_get_string(rfi->settings, FreeRDP_Password));
    1640  }
    1641  /* Remote Desktop Gateway usage */
    1642  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled))
    1643  freerdp_set_gateway_usage_method(rfi->settings,
    1644  remmina_plugin_service->file_get_int(remminafile, "gateway_usage", FALSE) ? TSC_PROXY_MODE_DETECT : TSC_PROXY_MODE_DIRECT);
    1645 
    1646  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayAccessToken,
    1647  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
    1648 
    1649  freerdp_settings_set_uint32(rfi->settings, FreeRDP_AuthenticationLevel, remmina_plugin_service->file_get_int(
    1650  remminafile, "authentication level", freerdp_settings_get_uint32(rfi->settings, FreeRDP_AuthenticationLevel)));
    1651 
    1652  /* Certificate ignore */
    1653  freerdp_settings_set_bool(rfi->settings, FreeRDP_IgnoreCertificate, remmina_plugin_service->file_get_int(remminafile, "cert_ignore", 0));
    1654  freerdp_settings_set_bool(rfi->settings, FreeRDP_OldLicenseBehaviour, remmina_plugin_service->file_get_int(remminafile, "old-license", 0));
    1655  freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowUnanouncedOrdersFromServer, remmina_plugin_service->file_get_int(remminafile, "relax-order-checks", 0));
    1656  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GlyphSupportLevel, (remmina_plugin_service->file_get_int(remminafile, "glyph-cache", 0) ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE));
    1657 
    1658  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientname")))
    1659  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, cs);
    1660  else
    1661  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, g_get_host_name());
    1662 
    1663  /* Client Build number is optional, if not specified defaults to 0, allow for comments to appear after number */
    1664  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientbuild"))) {
    1665  if (*cs) {
    1666  UINT32 val = strtoul(cs, NULL, 0);
    1667  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ClientBuild, val);
    1668  }
    1669  }
    1670 
    1671 
    1672  if (remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo")) {
    1673  char *tmp = strdup(remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo"));
    1674  rfi->settings->LoadBalanceInfo = (BYTE *)tmp;
    1675 
    1676  freerdp_settings_set_uint32(rfi->settings, FreeRDP_LoadBalanceInfoLength, strlen(tmp));
    1677  }
    1678 
    1679  if (remmina_plugin_service->file_get_string(remminafile, "exec"))
    1680  freerdp_settings_set_string(rfi->settings, FreeRDP_AlternateShell, remmina_plugin_service->file_get_string(remminafile, "exec"));
    1681 
    1682  if (remmina_plugin_service->file_get_string(remminafile, "execpath"))
    1683  freerdp_settings_set_string(rfi->settings, FreeRDP_ShellWorkingDirectory, remmina_plugin_service->file_get_string(remminafile, "execpath"));
    1684 
    1685  sm = g_strdup_printf("rdp_quality_%i", remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0));
    1686  value = remmina_plugin_service->pref_get_value(sm);
    1687  g_free(sm);
    1688 
    1689  if (value && value[0]) {
    1690  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, strtoul(value, NULL, 16));
    1691  } else {
    1692  switch (remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0)) {
    1693  case 9:
    1694  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_9);
    1695  break;
    1696 
    1697  case 2:
    1698  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_2);
    1699  break;
    1700 
    1701  case 1:
    1702  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_1);
    1703  break;
    1704 
    1705  case 0:
    1706  default:
    1707  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_0);
    1708  break;
    1709  }
    1710  }
    1711  g_free(value);
    1712 
    1713  if ((cs = remmina_plugin_service->file_get_string(remminafile, "network"))) {
    1714  guint32 type = 0;
    1715 
    1716  if (g_strcmp0(cs, "modem") == 0)
    1717  type = CONNECTION_TYPE_MODEM;
    1718  else if (g_strcmp0(cs, "broadband") == 0)
    1719  type = CONNECTION_TYPE_BROADBAND_HIGH;
    1720  else if (g_strcmp0(cs, "broadband-low") == 0)
    1721  type = CONNECTION_TYPE_BROADBAND_LOW;
    1722  else if (g_strcmp0(cs, "broadband-high") == 0)
    1723  type = CONNECTION_TYPE_BROADBAND_HIGH;
    1724  else if (g_strcmp0(cs, "wan") == 0)
    1725  type = CONNECTION_TYPE_WAN;
    1726  else if (g_strcmp0(cs, "lan") == 0)
    1727  type = CONNECTION_TYPE_LAN;
    1728  else if ((g_strcmp0(cs, "autodetect") == 0))
    1729  type = CONNECTION_TYPE_AUTODETECT;
    1730  else if ((g_strcmp0(cs, "none") == 0))
    1731  type = REMMINA_CONNECTION_TYPE_NONE;
    1732  else
    1733  type = REMMINA_CONNECTION_TYPE_NONE;
    1734 
    1735  if (!remmina_rdp_set_connection_type(rfi->settings, type))
    1736  REMMINA_PLUGIN_DEBUG("Network settings not set");
    1737  }
    1738 
    1739  /* PerformanceFlags bitmask need also to be splitted into BOOL variables
    1740  * like freerdp_settings_set_bool(rfi->settings, FreeRDP_DisableWallpaper, freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowFontSmoothing…
    1741  * or freerdp_get_param_bool() function will return the wrong value
    1742  */
    1743  freerdp_performance_flags_split(rfi->settings);
    1744 
    1745 #ifdef GDK_WINDOWING_X11
    1746 #if FREERDP_CHECK_VERSION(2, 3, 0)
    1747  rdp_kbd_remap = remmina_get_rdp_kbd_remap(remmina_plugin_service->file_get_string(remminafile, "keymap"));
    1748  if (rdp_kbd_remap != NULL) {
    1749  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, rdp_kbd_remap);
    1750  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
    1751  g_free(rdp_kbd_remap);
    1752  }
    1753  else {
    1754  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, remmina_plugin_service->pref_get_value("rdp_kbd_remap"));
    1755  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
    1756  }
    1757 #endif
    1758 #endif
    1759 
    1760  freerdp_settings_set_uint32(rfi->settings, FreeRDP_KeyboardLayout, remmina_rdp_settings_get_keyboard_layout());
    1761 
    1762  if (remmina_plugin_service->file_get_int(remminafile, "console", FALSE))
    1763  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1764 
    1765  if (remmina_plugin_service->file_get_int(remminafile, "restricted-admin", FALSE)) {
    1766  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1767  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
    1768  }
    1769 
    1770  if (remmina_plugin_service->file_get_string(remminafile, "pth")) {
    1771  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1772  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
    1773  freerdp_settings_set_string(rfi->settings, FreeRDP_PasswordHash, remmina_plugin_service->file_get_string(remminafile, "pth"));
    1774  remmina_plugin_service->file_set_int(remminafile, "restricted-admin", TRUE);
    1775  }
    1776 
    1777  cs = remmina_plugin_service->file_get_string(remminafile, "security");
    1778  if (g_strcmp0(cs, "rdp") == 0) {
    1779  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, TRUE);
    1780  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1781  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1782  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1783  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseRdpSecurityLayer, TRUE);
    1784  } else if (g_strcmp0(cs, "tls") == 0) {
    1785  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1786  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, TRUE);
    1787  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1788  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1789  } else if (g_strcmp0(cs, "nla") == 0) {
    1790  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1791  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1792  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, TRUE);
    1793  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1794  } else if (g_strcmp0(cs, "ext") == 0) {
    1795  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1796  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1797  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1798  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, TRUE);
    1799  } else {
    1800  /* This is "-nego" switch of xfreerdp */
    1801  freerdp_settings_set_bool(rfi->settings, FreeRDP_NegotiateSecurityLayer, TRUE);
    1802  }
    1803 
    1804  cs = remmina_plugin_service->file_get_string(remminafile, "tls-seclevel");
    1805  if (cs && g_strcmp0(cs,"")!=0) {
    1806  i = atoi(cs);
    1807  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TlsSecLevel, i);
    1808  }
    1809 
    1810  freerdp_settings_set_bool(rfi->settings, FreeRDP_CompressionEnabled, TRUE);
    1811  if (remmina_plugin_service->file_get_int(remminafile, "disable_fastpath", FALSE)) {
    1812  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, FALSE);
    1813  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, FALSE);
    1814  } else {
    1815  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, TRUE);
    1816  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
    1817  }
    1818 
    1819  /* Orientation and scaling settings */
    1820  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
    1821 
    1822  freerdp_settings_set_uint16(rfi->settings, FreeRDP_DesktopOrientation, desktopOrientation);
    1823  if (desktopScaleFactor != 0 && deviceScaleFactor != 0) {
    1824  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopScaleFactor, desktopScaleFactor);
    1825  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DeviceScaleFactor, deviceScaleFactor);
    1826  }
    1827 
    1828  /* Try to enable "Display Control Virtual Channel Extension", needed to
    1829  * dynamically resize remote desktop. This will automatically open
    1830  * the "disp" dynamic channel, if available */
    1831  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportDisplayControl, TRUE);
    1832 
    1833  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportDisplayControl)) {
    1834  CLPARAM *d[1];
    1835  int dcount;
    1836 
    1837  dcount = 1;
    1838  d[0] = "disp";
    1839  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
    1840  }
    1841 
    1842  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
    1843  CLPARAM *d[1];
    1844 
    1845  int dcount;
    1846 
    1847  dcount = 1;
    1848  d[0] = "rdpgfx";
    1849  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
    1850  }
    1851 
    1852  /* Sound settings */
    1853  cs = remmina_plugin_service->file_get_string(remminafile, "sound");
    1854  if (g_strcmp0(cs, "remote") == 0) {
    1855  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, TRUE);
    1856  } else if (g_str_has_prefix(cs, "local")) {
    1857  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, TRUE);
    1858  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
    1859  } else {
    1860  /* Disable sound */
    1861  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, FALSE);
    1862  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, FALSE);
    1863  }
    1864 
    1865  cs = remmina_plugin_service->file_get_string(remminafile, "microphone");
    1866  if (cs != NULL && cs[0] != '\0') {
    1867  if (g_strcmp0(cs, "0") == 0) {
    1868  REMMINA_PLUGIN_DEBUG("“microphone” was set to 0, setting to \"\"");
    1869  remmina_plugin_service->file_set_string(remminafile, "microphone", "");
    1870  } else {
    1871  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
    1872  REMMINA_PLUGIN_DEBUG("“microphone” set to “%s”", cs);
    1873  CLPARAM **p;
    1874  size_t count;
    1875 
    1876  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("audin", g_strdup(cs), &count);
    1877 
    1878  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1879  g_free(p);
    1880  }
    1881  }
    1882 
    1883  cs = remmina_plugin_service->file_get_string(remminafile, "audio-output");
    1884  if (cs != NULL && cs[0] != '\0') {
    1885  REMMINA_PLUGIN_DEBUG("audio output set to %s", cs);
    1886  CLPARAM **p;
    1887  size_t count;
    1888 
    1889  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("rdpsnd", g_strdup(cs), &count);
    1890  status = freerdp_client_add_static_channel(rfi->settings, count, p);
    1891  if (status)
    1892  status = freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1893  g_free(p);
    1894  }
    1895 
    1896 
    1897  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_level");
    1898  if (cs != NULL && cs[0] != '\0')
    1899  REMMINA_PLUGIN_DEBUG("Log level set to to %s", cs);
    1900  else
    1901  cs = g_strdup("INFO");
    1902  wLog *root = WLog_GetRoot();
    1903  WLog_SetStringLogLevel(root, cs);
    1904 
    1905  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_filters");
    1906  if (cs != NULL && cs[0] != '\0') {
    1907  REMMINA_PLUGIN_DEBUG("Log filters set to to %s", cs);
    1908  WLog_AddStringLogFilters(cs);
    1909  } else {
    1910  WLog_AddStringLogFilters(NULL);
    1911  }
    1912 
    1913 
    1914  cs = remmina_plugin_service->file_get_string(remminafile, "usb");
    1915  if (cs != NULL && cs[0] != '\0') {
    1916  CLPARAM **p;
    1917  size_t count;
    1918  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("urbdrc", g_strdup(cs), &count);
    1919  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1920  g_free(p);
    1921  }
    1922 
    1923  cs = remmina_plugin_service->file_get_string(remminafile, "vc");
    1924  if (cs != NULL && cs[0] != '\0') {
    1925  CLPARAM **p;
    1926  size_t count;
    1927  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
    1928  freerdp_client_add_static_channel(rfi->settings, count, p);
    1929  g_free(p);
    1930  }
    1931 
    1932  cs = remmina_plugin_service->file_get_string(remminafile, "dvc");
    1933  if (cs != NULL && cs[0] != '\0') {
    1934  CLPARAM **p;
    1935  size_t count;
    1936  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
    1937  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1938  g_free(p);
    1939  }
    1940 
    1941  cs = remmina_plugin_service->file_get_string(remminafile, "rdp2tcp");
    1942  if (cs != NULL && cs[0] != '\0') {
    1943  g_free(rfi->settings->RDP2TCPArgs);
    1944  rfi->settings->RDP2TCPArgs = g_strdup(cs);
    1945  REMMINA_PLUGIN_DEBUG("rdp2tcp set to %s", rfi->settings->RDP2TCPArgs);
    1946  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdp2tcp", rfi->settings->RDP2TCPArgs);
    1947  }
    1948 
    1949  int vermaj, vermin, verrev;
    1950  freerdp_get_version(&vermaj, &vermin, &verrev);
    1951 
    1952 #if FREERDP_CHECK_VERSION(2, 1, 0)
    1953  cs = remmina_plugin_service->file_get_string(remminafile, "timeout");
    1954  if (cs != NULL && cs[0] != '\0') {
    1955  const gchar *endptr = NULL;
    1956  guint64 val = g_ascii_strtoull(cs, (gchar **)&endptr, 10);
    1957  if (val > 600000 || val <= 0)
    1958  val = 600000;
    1959  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TcpAckTimeout, (UINT32)val);
    1960  }
    1961 #endif
    1962 
    1963  if (remmina_plugin_service->file_get_int(remminafile, "preferipv6", FALSE) ? TRUE : FALSE)
    1964  freerdp_settings_set_bool(rfi->settings, FreeRDP_PreferIPv6OverIPv4, TRUE);
    1965 
    1966  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectClipboard, remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE) ? FALSE : TRUE);
    1967 
    1968  cs = remmina_plugin_service->file_get_string(remminafile, "sharefolder");
    1969  if (cs != NULL && cs[0] != '\0') {
    1970  gchar *ccs = g_strdup(cs);
    1971  REMMINA_PLUGIN_DEBUG("[Deprecated->migrating] - Old sharefolder %s to \"drive \"", ccs);
    1972  if (!remmina_plugin_service->file_get_string(remminafile, "drive")) {
    1973  remmina_plugin_service->file_set_string(remminafile, "drive", g_strdup(ccs));
    1974  remmina_plugin_service->file_set_string(remminafile, "sharefolder", NULL);
    1975  REMMINA_PLUGIN_DEBUG("[Deprecated->migrated] - drive set to %s", g_strdup(ccs));
    1976  }
    1977  g_free(ccs);
    1978  //CLPARAM **p;
    1979  //size_t count;
    1980  //p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(cs), &count);
    1981  //status = freerdp_client_add_device_channel(rfi->settings, count, p);
    1982  //g_free(p);
    1983  }
    1984  cs = remmina_plugin_service->file_get_string(remminafile, "drive");
    1985  if (cs != NULL && cs[0] != '\0') {
    1986  REMMINA_PLUGIN_DEBUG("Redirect directory set to %s", cs);
    1987  CLPARAM **p;
    1988  size_t count;
    1989 
    1990  gchar **folders = g_strsplit(cs, ";", -1);
    1991  for (i = 0; folders[i] != NULL; i++) {
    1992  REMMINA_PLUGIN_DEBUG("Parsing folder %s", folders[i]);
    1993  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(folders[i]), &count);
    1994  status = freerdp_client_add_device_channel(rfi->settings, count, p);
    1995  g_free(p);
    1996  }
    1997  g_strfreev(folders);
    1998  }
    1999 
    2000  if (remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE)) {
    2001 #ifdef HAVE_CUPS
    2002  REMMINA_PLUGIN_DEBUG("Sharing printers");
    2003  const gchar *po = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
    2004  if (po && po[0] != 0) {
    2005  /* Fallback to remmina code to override print drivers */
    2006  if (cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, remmina_rdp_set_printers, rfi))
    2007  REMMINA_PLUGIN_DEBUG("All printers have been shared");
    2008  else
    2009  REMMINA_PLUGIN_DEBUG("Cannot share printers, are there any available?");
    2010  } else {
    2011  /* Use libfreerdp code to map all printers */
    2012  CLPARAM *d[1];
    2013  int dcount;
    2014  dcount = 1;
    2015  d[0] = "printer";
    2016  freerdp_client_add_device_channel(rfi->settings, dcount, d);
    2017  }
    2018 #endif /* HAVE_CUPS */
    2019  }
    2020 
    2021  if (remmina_plugin_service->file_get_int(remminafile, "span", FALSE)) {
    2022  freerdp_settings_set_bool(rfi->settings, FreeRDP_SpanMonitors, TRUE);
    2023  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2024  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2025  remmina_plugin_service->file_set_int(remminafile, "multimon", 1);
    2026  }
    2027 
    2028  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    2029  guint32 maxwidth = 0;
    2030  guint32 maxheight = 0;
    2031  gchar *monitorids;
    2032  guint32 i;
    2033  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2034  /* TODO Add an option for this */
    2035  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    2036  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2037 
    2038  gchar *monitorids_string = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids"));
    2039  /* Otherwise we get all the attached monitors
    2040  * monitorids may contains desktop orientation values.
    2041  * But before we check if there are orientation attributes
    2042  */
    2043  if (monitorids_string != NULL && monitorids_string[0] != '\0') {
    2044  if (g_strstr_len(monitorids_string, -1, ",") != NULL) {
    2045  if (g_strstr_len(monitorids_string, -1, ":") != NULL) {
    2046  rdpMonitor *base = (rdpMonitor *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    2047  /* We have an ID and an orientation degree */
    2048  gchar **temp_items;
    2049  gchar **rot_items;
    2050  temp_items = g_strsplit(monitorids_string, ",", -1);
    2051  for (i = 0; i < g_strv_length(temp_items); i++) {
    2052  rot_items = g_strsplit(temp_items[i], ":", -1);
    2053  rdpMonitor *current = &base[atoi(rot_items[0])];
    2054  if (i == 0)
    2055  monitorids = g_strdup(rot_items[0]);
    2056  else
    2057  monitorids = g_strdup_printf("%s,%s", monitorids, rot_items[0]);
    2058  current->attributes.orientation = atoi(rot_items[1]);
    2059  REMMINA_PLUGIN_DEBUG("Monitor n %d orientation: %d", i, current->attributes.orientation);
    2060  }
    2061  } else {
    2062  monitorids = g_strdup(monitorids_string);
    2063  }
    2064  } else {
    2065  monitorids = g_strdup(monitorids_string);
    2066  }
    2067  } else {
    2068  monitorids = g_strdup(monitorids_string);
    2069  }
    2070  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
    2071  if (monitorids != NULL && monitorids[0] != '\0') {
    2072  UINT32 *base = (UINT32 *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorIds);
    2073  gchar **items;
    2074  items = g_strsplit(monitorids, ",", -1);
    2075  freerdp_settings_set_uint32(rfi->settings, FreeRDP_NumMonitorIds, g_strv_length(items));
    2076  REMMINA_PLUGIN_DEBUG("NumMonitorIds: %d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_NumMonitorIds));
    2077  for (i = 0; i < g_strv_length(items); i++) {
    2078  UINT32 *current = &base[i];
    2079  *current = atoi(items[i]);
    2080  REMMINA_PLUGIN_DEBUG("Added monitor with ID %" PRIu32, *current);
    2081  }
    2082  g_free(monitorids);
    2083  g_strfreev(items);
    2084  }
    2085  if (maxwidth && maxheight) {
    2086  REMMINA_PLUGIN_DEBUG("Setting DesktopWidth and DesktopHeight to: %dx%d", maxwidth, maxheight);
    2087  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, maxwidth);
    2088  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, maxheight);
    2089  REMMINA_PLUGIN_DEBUG("DesktopWidth and DesktopHeight set to: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2090  } else {
    2091  REMMINA_PLUGIN_DEBUG("Cannot set Desktop Size, we are using the previously set values: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2092  }
    2093  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
    2094  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2095  }
    2096 
    2097  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "smartcardname");
    2098  if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE) ||
    2099  (sn != NULL && sn[0] != '\0')) {
    2100  RDPDR_SMARTCARD *smartcard;
    2101  smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD));
    2102 
    2103 #ifdef WITH_FREERDP3
    2104  RDPDR_DEVICE *sdev;
    2105  sdev = &(smartcard->device);
    2106 #else
    2107  RDPDR_SMARTCARD *sdev;
    2108  sdev = smartcard;
    2109 #endif
    2110 
    2111  sdev->Type = RDPDR_DTYP_SMARTCARD;
    2112 
    2113  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2114 
    2115  if (sn != NULL && sn[0] != '\0')
    2116  sdev->Name = _strdup(sn);
    2117 
    2118  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSmartCards, TRUE);
    2119 
    2120  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)smartcard);
    2121  }
    2122 
    2123  if (remmina_plugin_service->file_get_int(remminafile, "passwordispin", FALSE))
    2124  /* Option works only combined with Username and Domain, because FreeRDP
    2125  * doesn’t know anything about info on smart card */
    2126  freerdp_settings_set_bool(rfi->settings, FreeRDP_PasswordIsSmartcardPin, TRUE);
    2127 
    2128  /* /serial[:<name>[,<path>[,<driver>[,permissive]]]] */
    2129  if (remmina_plugin_service->file_get_int(remminafile, "shareserial", FALSE)) {
    2130  RDPDR_SERIAL *serial;
    2131  serial = (RDPDR_SERIAL *)calloc(1, sizeof(RDPDR_SERIAL));
    2132 
    2133 #ifdef WITH_FREERDP3
    2134  RDPDR_DEVICE *sdev;
    2135  sdev = &(serial->device);
    2136 #else
    2137  RDPDR_SERIAL *sdev;
    2138  sdev = serial;
    2139 #endif
    2140 
    2141  sdev->Type = RDPDR_DTYP_SERIAL;
    2142 
    2143  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2144 
    2145  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "serialname");
    2146  if (sn != NULL && sn[0] != '\0')
    2147  sdev->Name = _strdup(sn);
    2148 
    2149  const gchar *sd = remmina_plugin_service->file_get_string(remminafile, "serialdriver");
    2150  if (sd != NULL && sd[0] != '\0')
    2151  serial->Driver = _strdup(sd);
    2152 
    2153  const gchar *sp = remmina_plugin_service->file_get_string(remminafile, "serialpath");
    2154  if (sp != NULL && sp[0] != '\0')
    2155  serial->Path = _strdup(sp);
    2156 
    2157  if (remmina_plugin_service->file_get_int(remminafile, "serialpermissive", FALSE))
    2158  serial->Permissive = _strdup("permissive");
    2159 
    2160  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSerialPorts, TRUE);
    2161 
    2162  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)serial);
    2163  }
    2164 
    2165  if (remmina_plugin_service->file_get_int(remminafile, "shareparallel", FALSE)) {
    2166  RDPDR_PARALLEL *parallel;
    2167  parallel = (RDPDR_PARALLEL *)calloc(1, sizeof(RDPDR_PARALLEL));
    2168 
    2169 #ifdef WITH_FREERDP3
    2170  RDPDR_DEVICE *pdev;
    2171  pdev = &(parallel->device);
    2172 #else
    2173  RDPDR_PARALLEL *pdev;
    2174  pdev = parallel;
    2175 #endif
    2176 
    2177  pdev->Type = RDPDR_DTYP_PARALLEL;
    2178 
    2179  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2180 
    2181  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectParallelPorts, TRUE);
    2182 
    2183  const gchar *pn = remmina_plugin_service->file_get_string(remminafile, "parallelname");
    2184  if (pn != NULL && pn[0] != '\0')
    2185  pdev->Name = _strdup(pn);
    2186  const gchar *dp = remmina_plugin_service->file_get_string(remminafile, "parallelpath");
    2187  if (dp != NULL && dp[0] != '\0')
    2188  parallel->Path = _strdup(dp);
    2189 
    2190  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel);
    2191  }
    2192 
    2196  if (remmina_plugin_service->file_get_int(remminafile, "multitransport", FALSE)) {
    2197  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2198  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportMultitransport, TRUE);
    2199  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags,
    2200  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED));
    2201  } else {
    2202  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags, 0);
    2203  }
    2204 
    2205  /* If needed, force interactive authentication by deleting all authentication fields,
    2206  * forcing libfreerdp to call our callbacks for authentication.
    2207  * This usually happens from a second attempt of connection, never on the 1st one. */
    2209  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, NULL);
    2210  freerdp_settings_set_string(rfi->settings, FreeRDP_Password, NULL);
    2211  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, NULL);
    2212 
    2213  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, NULL);
    2214  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, NULL);
    2215  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, NULL);
    2216 
    2217  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    2218  }
    2219 
    2220  gboolean orphaned;
    2221 
    2222  if (!freerdp_connect(rfi->instance)) {
    2223  orphaned = (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL);
    2224  if (!orphaned) {
    2225  UINT32 e;
    2226 
    2227  e = freerdp_get_last_error(rfi->instance->context);
    2228 
    2229  switch (e) {
    2230  case FREERDP_ERROR_AUTHENTICATION_FAILED:
    2231  case STATUS_LOGON_FAILURE: // wrong return code from FreeRDP introduced at the end of July 2016? (fixed with b86c0ba)
    2232 #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
    2233  case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
    2234 #endif
    2235  /* Logon failure, will retry with interactive authentication */
    2237  break;
    2238  case STATUS_ACCOUNT_LOCKED_OUT:
    2239 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
    2240  case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
    2241 #endif
    2242  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount locked out."),
    2243  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2244  break;
    2245  case STATUS_ACCOUNT_EXPIRED:
    2246 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
    2247  case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
    2248 #endif
    2249  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount expired."),
    2250  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2251  break;
    2252  case STATUS_PASSWORD_EXPIRED:
    2253 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED
    2254  case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
    2255 #endif
    2256  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nPassword expired."),
    2257  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2258  break;
    2259  case STATUS_ACCOUNT_DISABLED:
    2260 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
    2261  case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
    2262 #endif
    2263  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount disabled."),
    2264  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2265  break;
    2266 #ifdef FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES
    2267  /* https://msdn.microsoft.com/en-us/library/ee392247.aspx */
    2268  case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
    2269  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nInsufficient user privileges."),
    2270  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2271  break;
    2272 #endif
    2273  case STATUS_ACCOUNT_RESTRICTION:
    2274 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
    2275  case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
    2276 #endif
    2277  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount restricted."),
    2278  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2279  break;
    2280 
    2281  case STATUS_PASSWORD_MUST_CHANGE:
    2282 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
    2283  case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
    2284 #endif
    2285  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nChange user password before connecting."),
    2286  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2287  break;
    2288 
    2289  case FREERDP_ERROR_CONNECT_FAILED:
    2290  remmina_plugin_service->protocol_plugin_set_error(gp, _("Lost connection to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2291  break;
    2292  case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
    2293  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not find the address for the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2294  break;
    2295  case FREERDP_ERROR_TLS_CONNECT_FAILED:
    2296  remmina_plugin_service->protocol_plugin_set_error(gp,
    2297  _("Could not connect to the RDP server “%s” via TLS. See the DEBUG traces from a terminal for more information."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2298  break;
    2299  case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
    2300  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    2301  remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to establish a connection to the RDP server “%s”. Check “Security protocol negotiation”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2302  break;
    2303 #ifdef FREERDP_ERROR_POST_CONNECT_FAILED
    2304  case FREERDP_ERROR_POST_CONNECT_FAILED:
    2305  /* remmina_rdp_post_connect() returned FALSE to libfreerdp. We saved the error on rfi->postconnect_error */
    2306  switch (rfi->postconnect_error) {
    2307  case REMMINA_POSTCONNECT_ERROR_OK:
    2308  /* We should never come here */
    2309  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2310  break;
    2311  case REMMINA_POSTCONNECT_ERROR_GDI_INIT:
    2312  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not start libfreerdp-gdi."));
    2313  break;
    2314  case REMMINA_POSTCONNECT_ERROR_NO_H264:
    2315  remmina_plugin_service->protocol_plugin_set_error(gp, _("You requested a H.264 GFX mode for the server “%s”, but your libfreerdp does not support H.264. Please use a non-AVC colour depth setting."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2316  break;
    2317  }
    2318  break;
    2319 #endif
    2320 #ifdef FREERDP_ERROR_SERVER_DENIED_CONNECTION
    2321  case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
    2322  remmina_plugin_service->protocol_plugin_set_error(gp, _("The “%s” server refused the connection."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2323  break;
    2324 #endif
    2325  case 0x800759DB:
    2326  // E_PROXY_NAP_ACCESSDENIED https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/84cd92e4-592c-4219-95d8-18021ac654b0
    2327  remmina_plugin_service->protocol_plugin_set_error(gp, _("The Remote Desktop Gateway “%s” denied the user “%s\\%s” access due to policy."),
    2328  freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayHostname), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayDomain), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayUsername));
    2329  break;
    2330 
    2331  case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
    2332  rfi->user_cancelled = TRUE;
    2333  break;
    2334 
    2335  default:
    2336  g_printf("libfreerdp returned code is %08X\n", e);
    2337  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the “%s” RDP server."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2338  break;
    2339  }
    2340  }
    2341 
    2342  return FALSE;
    2343  }
    2344 
    2345  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = true; else orphaned = false;
    2346  if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled)
    2348 
    2349  return TRUE;
    2350 }
    2351 
    2352 static void rfi_uninit(rfContext *rfi)
    2353 {
    2354  freerdp *instance;
    2355 
    2356  instance = rfi->instance;
    2357 
    2358  if (rfi->remmina_plugin_thread) {
    2359  rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run
    2360  pthread_cancel(rfi->remmina_plugin_thread);
    2361  if (rfi->remmina_plugin_thread)
    2362  pthread_join(rfi->remmina_plugin_thread, NULL);
    2363  }
    2364 
    2365  if (instance) {
    2366  if (rfi->connected) {
    2367  freerdp_abort_connect(instance);
    2368  rfi->connected = false;
    2369  }
    2370  }
    2371 
    2372  if (instance) {
    2373  RDP_CLIENT_ENTRY_POINTS *pEntryPoints = instance->pClientEntryPoints;
    2374  if (pEntryPoints)
    2375  IFCALL(pEntryPoints->GlobalUninit);
    2376  free(instance->pClientEntryPoints);
    2377  freerdp_context_free(instance); /* context is rfContext* rfi */
    2378  freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */
    2379  }
    2380 }
    2381 
    2382 static gboolean complete_cleanup_on_main_thread(gpointer data)
    2383 {
    2384  TRACE_CALL(__func__);
    2385 
    2386  gboolean orphaned;
    2387  rfContext *rfi = (rfContext *)data;
    2389 
    2391 
    2392  gdi_free(rfi->instance);
    2393 
    2394  gp = rfi->protocol_widget;
    2395  if (GET_PLUGIN_DATA(gp) == NULL) orphaned = true; else orphaned = false;
    2396 
    2398  if (!orphaned) remmina_rdp_event_uninit(gp);
    2399 
    2400  if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data");
    2401 
    2402  rfi_uninit(rfi);
    2403 
    2404  /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface
    2405  * can be removed */
    2406  if (!orphaned)
    2407  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
    2408 
    2409  return G_SOURCE_REMOVE;
    2410 }
    2411 
    2412 static gpointer remmina_rdp_main_thread(gpointer data)
    2413 {
    2414  TRACE_CALL(__func__);
    2416  rfContext *rfi;
    2417 
    2418  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    2419  CANCEL_ASYNC
    2420 
    2421  gp = (RemminaProtocolWidget *)data;
    2422 
    2423  rfi = GET_PLUGIN_DATA(gp);
    2424 
    2426  do
    2427  remmina_rdp_main(gp);
    2428  while (!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled);
    2429 
    2430  rfi->remmina_plugin_thread = 0;
    2431 
    2432  /* cleanup */
    2433  g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi);
    2434 
    2435 
    2436  return NULL;
    2437 }
    2438 
    2440 {
    2441  TRACE_CALL(__func__);
    2442  freerdp *instance;
    2443  rfContext *rfi;
    2444 
    2445  instance = freerdp_new();
    2446  instance->PreConnect = remmina_rdp_pre_connect;
    2447  instance->PostConnect = remmina_rdp_post_connect;
    2448  instance->PostDisconnect = remmina_rdp_post_disconnect;
    2449  instance->Authenticate = remmina_rdp_authenticate;
    2450  instance->GatewayAuthenticate = remmina_rdp_gw_authenticate;
    2451  //instance->VerifyCertificate = remmina_rdp_verify_certificate;
    2452  instance->VerifyCertificateEx = remmina_rdp_verify_certificate_ex;
    2453  //instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate;
    2454  instance->VerifyChangedCertificateEx = remmina_rdp_verify_changed_certificate_ex;
    2455 
    2456  instance->ContextSize = sizeof(rfContext);
    2457  freerdp_context_new(instance);
    2458  rfi = (rfContext *)instance->context;
    2459 
    2460  g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free);
    2461 
    2462  rfi->protocol_widget = gp;
    2463  rfi->instance = instance;
    2464  rfi->settings = instance->settings;
    2465  rfi->connected = false;
    2466  rfi->is_reconnecting = false;
    2467  rfi->stop_reconnecting_requested = false;
    2468  rfi->user_cancelled = FALSE;
    2469  rfi->last_x = 0;
    2470  rfi->last_y = 0;
    2471 
    2472  freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
    2473 
    2475 }
    2476 
    2478 {
    2479  TRACE_CALL(__func__);
    2480  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2481  RemminaFile *remminafile;
    2482  const gchar *profile_name, *p;
    2483  gchar thname[16], c;
    2484  gint nthname = 0;
    2485 
    2486  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
    2487 
    2488  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    2489 
    2490 
    2491  if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) {
    2492  remmina_plugin_service->protocol_plugin_set_error(gp, "%s",
    2493  "Could not start pthread.");
    2494 
    2495  rfi->remmina_plugin_thread = 0;
    2496 
    2497  return FALSE;
    2498  }
    2499 
    2500  /* Generate a thread name to be used with pthread_setname_np() for debugging */
    2501  profile_name = remmina_plugin_service->file_get_string(remminafile, "name");
    2502  p = profile_name;
    2503  strcpy(thname, "RemmRDP:");
    2504  if (p) {
    2505  nthname = strlen(thname);
    2506  while ((c = *p) != 0 && nthname < sizeof(thname) - 1) {
    2507  if (isalnum(c))
    2508  thname[nthname++] = c;
    2509  p++;
    2510  }
    2511  } else {
    2512  strcat(thname, "<NONAM>");
    2513  nthname = strlen(thname);
    2514  }
    2515  thname[nthname] = 0;
    2516 #if defined(__linux__)
    2517  pthread_setname_np(rfi->remmina_plugin_thread, thname);
    2518 #elif defined(__FreeBSD__)
    2519  pthread_set_name_np(rfi->remmina_plugin_thread, thname);
    2520 #endif
    2521 
    2522  return TRUE;
    2523 }
    2524 
    2526 {
    2527  TRACE_CALL(__func__);
    2528 
    2529  REMMINA_PLUGIN_DEBUG("Requesting to close the connection");
    2530  RemminaPluginRdpEvent rdp_event = { 0 };
    2531  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2532 
    2533  if (!remmina_plugin_service->is_main_thread())
    2534  g_warning("WARNING: %s called on a subthread, which may not work or crash Remmina.", __func__);
    2535 
    2536  if (rfi && !rfi->connected) {
    2537  /* libfreerdp is attempting to connect, we cannot interrupt our main thread
    2538  * in the connect phase.
    2539  * So we remove "plugin-data" from gp, so our rfi remains "orphan"
    2540  */
    2542  g_object_steal_data(G_OBJECT(gp), "plugin-data");
    2543  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
    2544  return FALSE;
    2545  }
    2546 
    2547 
    2548  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
    2549  REMMINA_PLUGIN_DEBUG("[RDP] requesting clipboard transfer to abort");
    2550  /* Allow clipboard transfer from server to terminate */
    2551  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
    2552  usleep(100000);
    2553  }
    2554 
    2555  if (rfi->is_reconnecting) {
    2556  /* Special case: window closed when attempting to reconnect */
    2557  rfi->stop_reconnecting_requested = TRUE;
    2558  return FALSE;
    2559  }
    2560 
    2561  rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT;
    2562  remmina_rdp_event_event_push(gp, &rdp_event);
    2563 
    2564  return FALSE;
    2565 }
    2566 
    2568 {
    2569  TRACE_CALL(__func__);
    2570  return TRUE;
    2571 }
    2572 
    2574 {
    2575  TRACE_CALL(__func__);
    2576  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2577 
    2578  switch (feature->id) {
    2579  case REMMINA_RDP_FEATURE_UNFOCUS:
    2581  break;
    2582 
    2583  case REMMINA_RDP_FEATURE_SCALE:
    2584  if (rfi) {
    2585  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
    2587  } else {
    2588  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_SCALE");
    2589  }
    2590  break;
    2591 
    2592  case REMMINA_RDP_FEATURE_MULTIMON:
    2593  if (rfi) {
    2594  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    2595  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    2596  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2597  /* TODO Add an option for this */
    2598  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    2599  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2601  }
    2602  } else {
    2603  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_MULTIMON");
    2604  }
    2605  break;
    2606 
    2607  case REMMINA_RDP_FEATURE_DYNRESUPDATE:
    2608  break;
    2609 
    2610  case REMMINA_RDP_FEATURE_TOOL_REFRESH:
    2611  if (rfi)
    2612  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0,
    2613  remmina_plugin_service->protocol_plugin_get_width(gp),
    2614  remmina_plugin_service->protocol_plugin_get_height(gp));
    2615  else
    2616  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_TOOL_REFRESH");
    2617  break;
    2618 
    2619  case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL:
    2621  break;
    2622 
    2623  default:
    2624  break;
    2625  }
    2626 }
    2627 
    2628 /* Send a keystroke to the plugin window */
    2629 static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    2630 {
    2631  TRACE_CALL(__func__);
    2632  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2633 
    2634  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
    2635  keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
    2636  return;
    2637 }
    2638 
    2640 {
    2641  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2642  rdpGdi *gdi;
    2643  size_t szmem;
    2644 
    2645  UINT32 bytesPerPixel;
    2646  UINT32 bitsPerPixel;
    2647 
    2648  if (!rfi)
    2649  return FALSE;
    2650 
    2651  gdi = ((rdpContext *)rfi)->gdi;
    2652 
    2653  bytesPerPixel = GetBytesPerPixel(gdi->hdc->format);
    2654  bitsPerPixel = GetBitsPerPixel(gdi->hdc->format);
    2655 
    2659  szmem = gdi->width * gdi->height * bytesPerPixel;
    2660 
    2661  REMMINA_PLUGIN_DEBUG("allocating %zu bytes for a full screenshot", szmem);
    2662  rpsd->buffer = malloc(szmem);
    2663  if (!rpsd->buffer) {
    2664  REMMINA_PLUGIN_DEBUG("could not set aside %zu bytes for a full screenshot", szmem);
    2665  return FALSE;
    2666  }
    2667  rpsd->width = gdi->width;
    2668  rpsd->height = gdi->height;
    2669  rpsd->bitsPerPixel = bitsPerPixel;
    2670  rpsd->bytesPerPixel = bytesPerPixel;
    2671 
    2672  memcpy(rpsd->buffer, gdi->primary_buffer, szmem);
    2673 
    2674  /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
    2675  return TRUE;
    2676 }
    2677 
    2678 /* Array of key/value pairs for colour depths */
    2679 static gpointer colordepth_list[] =
    2680 {
    2681  /* 1st one is the default in a new install */
    2682  "99", N_("Automatic (32 bpp) (Server chooses its best format)"),
    2683  "66", N_("GFX AVC444 (32 bpp)"),
    2684  "65", N_("GFX AVC420 (32 bpp)"),
    2685  "64", N_("GFX RFX (32 bpp)"),
    2686  "63", N_("GFX RFX Progressive (32 bpp)"),
    2687  "0", N_("RemoteFX (32 bpp)"),
    2688  "32", N_("True colour (32 bpp)"),
    2689  "24", N_("True colour (24 bpp)"),
    2690  "16", N_("High colour (16 bpp)"),
    2691  "15", N_("High colour (15 bpp)"),
    2692  "8", N_("256 colours (8 bpp)"),
    2693  NULL
    2694 };
    2695 
    2696 /* Array of key/value pairs for the FreeRDP logging level */
    2697 static gpointer log_level[] =
    2698 {
    2699  "INFO", "INFO",
    2700  "FATAL", "FATAL",
    2701  "ERROR", "ERROR",
    2702  "WARN", "WARN",
    2703  "DEBUG", "DEBUG",
    2704  "TRACE", "TRACE",
    2705  "OFF", "OFF",
    2706  NULL
    2707 };
    2708 
    2709 
    2710 /* Array of key/value pairs for quality selection */
    2711 static gpointer quality_list[] =
    2712 {
    2713  "0", N_("Poor (fastest)"),
    2714  "1", N_("Medium"),
    2715  "2", N_("Good"),
    2716  "9", N_("Best (slowest)"),
    2717  NULL
    2718 };
    2719 
    2720 /* Array of key/value pairs for quality selection */
    2721 static gpointer network_list[] =
    2722 {
    2723  "none", N_("None"),
    2724  "autodetect", N_("Auto-detect"),
    2725  "modem", N_("Modem"),
    2726  "broadband-low", N_("Low performance broadband"),
    2727  "satellite", N_("Satellite"),
    2728  "broadband-high", N_("High performance broadband"),
    2729  "wan", N_("WAN"),
    2730  "lan", N_("LAN"),
    2731  NULL
    2732 };
    2733 
    2734 /* Array of key/value pairs for sound options */
    2735 static gpointer sound_list[] =
    2736 {
    2737  "off", N_("Off"),
    2738  "local", N_("Local"),
    2739  "remote", N_("Remote"),
    2740  NULL
    2741 };
    2742 
    2743 /* Array of key/value pairs for security */
    2744 static gpointer security_list[] =
    2745 {
    2746  "", N_("Automatic negotiation"),
    2747  "nla", N_("NLA protocol security"),
    2748  "tls", N_("TLS protocol security"),
    2749  "rdp", N_("RDP protocol security"),
    2750  "ext", N_("NLA extended protocol security"),
    2751  NULL
    2752 };
    2753 
    2754 /* Array of key/value pairs for mouse movement */
    2755 static gpointer mouse_jitter_list[] =
    2756 {
    2757  "No", N_("No"),
    2758  "60", N_("Every 1 min"),
    2759  "180", N_("Every 3 min"),
    2760  "300", N_("Every 5 min"),
    2761  "600", N_("Every 10 min"),
    2762  NULL
    2763 };
    2764 
    2765 static gpointer gwtransp_list[] =
    2766 {
    2767  "http", "HTTP",
    2768  "rpc", "RPC",
    2769  "auto", "Auto",
    2770  NULL
    2771 };
    2772 
    2773 static gpointer tls_seclevel[] =
    2774 {
    2775  "", N_("Default"),
    2776  "0", N_("0 — Windows 7 compatible"),
    2777  "1", N_("1"),
    2778  "2", N_("2"),
    2779  "3", N_("3"),
    2780  "4", N_("4"),
    2781  "5", N_("5"),
    2782  NULL
    2783 };
    2784 
    2785 static gchar clientbuild_list[] =
    2786  N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)");
    2787 
    2788 static gchar clientbuild_tooltip[] =
    2789  N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
    2790  " • < 4034: Windows XP base smart card functions\n"
    2791  " • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
    2792  " SCardWriteCache(), SCardGetTransmitCount()\n"
    2793  " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
    2794  " SCardGetDeviceTypeId()");
    2795 
    2796 static gchar microphone_tooltip[] =
    2797  N_("Options for redirection of audio input:\n"
    2798  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    2799  " [channel:<channel>] Audio input (microphone)\n"
    2800  " • sys:pulse\n"
    2801  " • format:1\n"
    2802  " • sys:oss,dev:1,format:1\n"
    2803  " • sys:alsa");
    2804 
    2805 static gchar audio_tooltip[] =
    2806  N_("Options for redirection of audio output:\n"
    2807  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    2808  " [channel:<channel>] Audio output\n"
    2809  " • sys:pulse\n"
    2810  " • format:1\n"
    2811  " • sys:oss,dev:1,format:1\n"
    2812  " • sys:alsa");
    2813 
    2814 
    2815 static gchar usb_tooltip[] =
    2816  N_("Options for redirection of USB device:\n"
    2817  " • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
    2818  " • auto\n"
    2819  " • id:054c:0268#4669:6e6b,addr:04:0c");
    2820 
    2821 static gchar timeout_tooltip[] =
    2822  N_("Advanced setting for high latency links:\n"
    2823  "Adjusts the connection timeout. Use if your connection times out.\n"
    2824  "The highest possible value is 600000 ms (10 minutes).\n");
    2825 
    2826 static gchar network_tooltip[] =
    2827  N_("Performance optimisations based on the network connection type:\n"
    2828  "Using auto-detection is advised.\n"
    2829  "If “Auto-detect” fails, choose the most appropriate option in the list.\n");
    2830 
    2831 static gchar monitorids_tooltip[] =
    2832  N_("Comma-separated list of monitor IDs and desktop orientations:\n"
    2833  " • [<id>:<orientation-in-degrees>,]\n"
    2834  " • 0,1,2,3\n"
    2835  " • 0:270,1:90\n"
    2836  "Orientations are specified in degrees, valid values are:\n"
    2837  " • 0 (landscape)\n"
    2838  " • 90 (portrait)\n"
    2839  " • 180 (landscape flipped)\n"
    2840  " • 270 (portrait flipped)\n"
    2841  "\n");
    2842 
    2843 static gchar drive_tooltip[] =
    2844  N_("Redirect directory <path> as named share <name>.\n"
    2845  " • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
    2846  " • MyHome,/home/remminer\n"
    2847  " • /home/remminer\n"
    2848  " • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
    2849  "Hotplug support is enabled with:\n"
    2850  " • hotplug,*\n"
    2851  "\n");
    2852 
    2853 /* Array of RemminaProtocolSetting for basic settings.
    2854  * Each item is composed by:
    2855  * a) RemminaProtocolSettingType for setting type
    2856  * b) Setting name
    2857  * c) Setting description
    2858  * d) Compact disposition
    2859  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
    2860  * f) Setting tooltip
    2861  * g) Validation data pointer, will be passed to the validation callback method.
    2862  * h) Validation callback method (Can be NULL. Every entry will be valid then.)
    2863  * use following prototype:
    2864  * gboolean mysetting_validator_method(gpointer key, gpointer value,
    2865  * gpointer validator_data);
    2866  * gpointer key is a gchar* containing the setting's name,
    2867  * gpointer value contains the value which should be validated,
    2868  * gpointer validator_data contains your passed data.
    2869  */
    2871 {
    2872  { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
    2873  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
    2874  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
    2875  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
    2876  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
    2877  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
    2878  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
    2879  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
    2880  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
    2881  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
    2882  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
    2883  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
    2884  { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
    2885  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
    2886  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
    2887  { REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
    2888  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
    2889 };
    2890 
    2891 /* Array of RemminaProtocolSetting for advanced settings.
    2892  * Each item is composed by:
    2893  * a) RemminaProtocolSettingType for setting type
    2894  * b) Setting name
    2895  * c) Setting description
    2896  * d) Compact disposition
    2897  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
    2898  * f) Setting Tooltip
    2899  */
    2901 {
    2902  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "quality", N_("Quality"), FALSE, quality_list, NULL },
    2903  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "security", N_("Security protocol negotiation"), FALSE, security_list, NULL },
    2904  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "gwtransp", N_("Gateway transport type"), FALSE, gwtransp_list, NULL },
    2905  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "tls-seclevel", N_("TLS Security Level"), FALSE, tls_seclevel, NULL },
    2906  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "freerdp_log_level", N_("FreeRDP log level"), FALSE, log_level, NULL },
    2907  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "freerdp_log_filters", N_("FreeRDP log filters"), FALSE, NULL, N_("tag:level[,tag:level[,…]]") },
    2908  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Audio output mode"), FALSE, sound_list, NULL },
    2909  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip },
    2910  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "microphone", N_("Redirect local microphone"), TRUE, NULL, microphone_tooltip },
    2911  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "timeout", N_("Connection timeout in ms"), TRUE, NULL, timeout_tooltip },
    2912  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL },
    2913  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_username", N_("Remote Desktop Gateway username"), FALSE, NULL, NULL },
    2914  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "gateway_password", N_("Remote Desktop Gateway password"), FALSE, NULL, NULL },
    2915  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_domain", N_("Remote Desktop Gateway domain"), FALSE, NULL, NULL },
    2916  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL },
    2917  { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip },
    2918  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Start-up program"), FALSE, NULL, NULL },
    2919  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL },
    2920  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL },
    2921  // TRANSLATORS: Do not use typographic quotation marks, these must stay as "double quote", also know as “Typewriter ("programmer's") quote, ambidextrous.”
    2922  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "printer_overrides", N_("Override printer drivers"), FALSE, NULL, N_("\"Samsung_CLX-3300_Series\":\"Samsung CLX-3300 Series PS\";\"Canon MF410\":\"Canon MF410 Series UFR II\"") },
    2923  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "usb", N_("USB device redirection"), TRUE, NULL, usb_tooltip },
    2924  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialname", N_("Local serial name"), FALSE, NULL, N_("COM1, COM2, etc.") },
    2925  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialdriver", N_("Local serial driver"), FALSE, NULL, N_("Serial") },
    2926  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialpath", N_("Local serial path"), FALSE, NULL, N_("/dev/ttyS0, /dev/ttyS1, etc.") },
    2927  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelname", N_("Local parallel name"), FALSE, NULL, NULL },
    2928  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelpath", N_("Local parallel device"), FALSE, NULL, NULL },
    2929  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "smartcardname", N_("Name of smart card"), FALSE, NULL, NULL },
    2930  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "dvc", N_("Dynamic virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
    2931  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "vc", N_("Static virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
    2932  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp2tcp", N_("TCP redirection"), FALSE, NULL, N_("/PATH/TO/rdp2tcp") },
    2933  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp_reconnect_attempts", N_("Reconnect attempts number"), FALSE, NULL, N_("The maximum number of reconnect attempts upon an RDP disconnect (default: 20)") },
    2934  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "rdp_mouse_jitter", N_("Move mouse when connection is idle"), FALSE, mouse_jitter_list, NULL },
    2935 
    2936  { REMMINA_PROTOCOL_SETTING_TYPE_ASSISTANCE, "assistance_mode", N_("Attempt to connect in assistance mode"), TRUE, NULL },
    2937  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "preferipv6", N_("Prefer IPv6 AAAA record over IPv4 A record"), TRUE, NULL, NULL },
    2938  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareprinter", N_("Share printers"), TRUE, NULL, NULL },
    2939  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareserial", N_("Share serial ports"), TRUE, NULL, NULL },
    2940  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "serialpermissive", N_("(SELinux) permissive mode for serial ports"), TRUE, NULL, NULL },
    2941  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareparallel", N_("Share parallel ports"), TRUE, NULL, NULL },
    2942  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sharesmartcard", N_("Share a smart card"), TRUE, NULL, NULL },
    2943  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("Turn off clipboard sync"), TRUE, NULL, NULL },
    2944  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "cert_ignore", N_("Ignore certificate"), TRUE, NULL, NULL },
    2945  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "old-license", N_("Use the old license workflow"), TRUE, NULL, N_("It disables CAL and hwId is set to 0") },
    2946  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
    2947  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "console", N_("Attach to console (2003/2003 R2)"), TRUE, NULL, NULL },
    2948  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable_fastpath", N_("Turn off fast-path"), TRUE, NULL, NULL },
    2949  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gateway_usage", N_("Server detection using Remote Desktop Gateway"), TRUE, NULL, NULL },
    2950 #if defined(PROXY_TYPE_IGNORE)
    2951  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "useproxyenv", N_("Use system proxy settings"), TRUE, NULL, NULL },
    2952 #endif
    2953  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableautoreconnect", N_("Turn off automatic reconnection"), TRUE, NULL, NULL },
    2954  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL },
    2955  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL },
    2956  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") },
    2957  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL },
    2958 #if FREERDP_CHECK_VERSION(2, 3, 1)
    2959  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "websockets", N_("Enable Gateway websockets support"), TRUE, NULL, NULL },
    2960 #endif
    2961  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "no-suppress", N_("Update framebuffer even when not visible"), TRUE, NULL },
    2962  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
    2963 };
    2964 
    2965 /* Array for available features.
    2966  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
    2968 {
    2969  { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, REMMINA_RDP_FEATURE_VIEWONLY, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "viewonly",
    2970  N_("View only") },
    2971  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL },
    2972  { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL },
    2973  { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL },
    2974  { REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_RDP_FEATURE_MULTIMON, NULL, NULL, NULL },
    2975  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL },
    2976  { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL },
    2977  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
    2978 };
    2979 
    2980 /* This will be filled with version info string */
    2982 
    2983 /* Protocol plugin definition and features */
    2985 {
    2987  "RDP", // Name
    2988  N_("RDP - Remote Desktop Protocol"), // Description
    2989  GETTEXT_PACKAGE, // Translation domain
    2990  remmina_plugin_rdp_version, // Version number
    2991  "org.remmina.Remmina-rdp-symbolic", // Icon for normal connection
    2992  "org.remmina.Remmina-rdp-ssh-symbolic", // Icon for SSH connection
    2993  remmina_rdp_basic_settings, // Array for basic settings
    2994  remmina_rdp_advanced_settings, // Array for advanced settings
    2995  REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type
    2996  remmina_rdp_features, // Array for available features
    2997  remmina_rdp_init, // Plugin initialization
    2998  remmina_rdp_open_connection, // Plugin open connection
    2999  remmina_rdp_close_connection, // Plugin close connection
    3000  remmina_rdp_query_feature, // Query for available features
    3001  remmina_rdp_call_feature, // Call a feature
    3002  remmina_rdp_keystroke, // Send a keystroke
    3003  remmina_rdp_get_screenshot, // Screenshot
    3004  remmina_rdp_event_on_map, // RCW map event
    3005  remmina_rdp_event_on_unmap // RCW unmap event
    3006 };
    3007 
    3008 /* File plugin definition and features */
    3010 {
    3011  REMMINA_PLUGIN_TYPE_FILE, // Type
    3012  "RDPF", // Name
    3013  N_("RDP - RDP File Handler"), // Description
    3014  GETTEXT_PACKAGE, // Translation domain
    3015  remmina_plugin_rdp_version, // Version number
    3016  remmina_rdp_file_import_test, // Test import function
    3017  remmina_rdp_file_import, // Import function
    3018  remmina_rdp_file_export_test, // Test export function
    3019  remmina_rdp_file_export, // Export function
    3020  NULL
    3021 };
    3022 
    3023 /* Preferences plugin definition and features */
    3025 {
    3026  REMMINA_PLUGIN_TYPE_PREF, // Type
    3027  "RDPS", // Name
    3028  N_("RDP - Preferences"), // Description
    3029  GETTEXT_PACKAGE, // Translation domain
    3030  remmina_plugin_rdp_version, // Version number
    3031  "RDP", // Label
    3032  remmina_rdp_settings_new // Preferences body function
    3033 };
    3034 
    3035 static char *buildconfig_strstr(const char *bc, const char *option)
    3036 {
    3037  TRACE_CALL(__func__);
    3038 
    3039  char *p, *n;
    3040 
    3041  p = strcasestr(bc, option);
    3042  if (p == NULL)
    3043  return NULL;
    3044 
    3045  if (p > bc && *(p - 1) > ' ')
    3046  return NULL;
    3047 
    3048  n = p + strlen(option);
    3049  if (*n > ' ')
    3050  return NULL;
    3051 
    3052  return p;
    3053 }
    3054 
    3055 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
    3056 {
    3057  int vermaj, vermin, verrev;
    3058 
    3059  TRACE_CALL(__func__);
    3060  remmina_plugin_service = service;
    3061 
    3062  /* Check that we are linked to the correct version of libfreerdp */
    3063 
    3064  freerdp_get_version(&vermaj, &vermin, &verrev);
    3065  if (vermaj < FREERDP_REQUIRED_MAJOR ||
    3066  (vermaj == FREERDP_REQUIRED_MAJOR && (vermin < FREERDP_REQUIRED_MINOR ||
    3067  (vermin == FREERDP_REQUIRED_MINOR && verrev < FREERDP_REQUIRED_REVISION)))) {
    3068  g_printf("Upgrade your FreeRDP library version from %d.%d.%d to at least libfreerdp %d.%d.%d "
    3069  "to run the RDP plugin.\n",
    3070  vermaj, vermin, verrev,
    3071  FREERDP_REQUIRED_MAJOR, FREERDP_REQUIRED_MINOR, FREERDP_REQUIRED_REVISION);
    3072  return FALSE;
    3073  }
    3074 
    3075  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
    3076  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
    3077 
    3078  if (!service->register_plugin((RemminaPlugin *)&remmina_rdp))
    3079  return FALSE;
    3080 
    3081  remmina_rdpf.export_hints = _("Export connection in Windows .rdp file format");
    3082 
    3083  if (!service->register_plugin((RemminaPlugin *)&remmina_rdpf))
    3084  return FALSE;
    3085 
    3086  if (!service->register_plugin((RemminaPlugin *)&remmina_rdps))
    3087  return FALSE;
    3088 
    3089  if (buildconfig_strstr(freerdp_get_build_config(), "WITH_GFX_H264=ON")) {
    3090  gfx_h264_available = TRUE;
    3091  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    3092  } else {
    3093  gfx_h264_available = FALSE;
    3094  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    3095  /* Remove values 65 and 66 from colordepth_list array by shifting it */
    3096  gpointer *src, *dst;
    3097  dst = src = colordepth_list;
    3098  while (*src) {
    3099  if (strcmp(*src, "66") != 0 && strcmp(*src, "65") != 0) {
    3100  if (dst != src) {
    3101  *dst = *src;
    3102  *(dst + 1) = *(src + 1);
    3103  }
    3104  dst += 2;
    3105  }
    3106  src += 2;
    3107  }
    3108  *dst = NULL;
    3109  }
    3110 
    3112  "RDP plugin: %s (Git %s), Compiled with libfreerdp %s (%s), Running with libfreerdp %s (rev %s), H.264 %s",
    3113  VERSION, REMMINA_GIT_REVISION,
    3114 #ifdef WITH_FREERDP3
    3115  FREERDP_VERSION_FULL, FREERDP_GIT_REVISION,
    3116 #else
    3117  FREERDP_VERSION_FULL, GIT_REVISION,
    3118 #endif
    3119  freerdp_get_version_string(),
    3120  freerdp_get_build_revision(),
    3121  gfx_h264_available ? "Yes" : "No"
    3122  );
    3123 
    3125 
    3126  return TRUE;
    3127 }
    CliprdrClientContext * context
    Definition: rdp_plugin.h:135
    -
    gint w
    Definition: rdp_plugin.h:262
    +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-2022 Antenore Gatta, Giovanni Panozzo
    6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
    7  *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    16  * GNU General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
    21  * Boston, MA 02110-1301, USA.
    22  *
    23  * In addition, as a special exception, the copyright holders give
    24  * permission to link the code of portions of this program with the
    25  * OpenSSL library under certain conditions as described in each
    26  * individual source file, and distribute linked combinations
    27  * including the two.
    28  * You must obey the GNU General Public License in all respects
    29  * for all of the code used other than OpenSSL. * If you modify
    30  * file(s) with this exception, you may extend this exception to your
    31  * version of the file(s), but you are not obligated to do so. * If you
    32  * do not wish to do so, delete this exception statement from your
    33  * version. * If you delete this exception statement from all source
    34  * files in the program, then also delete it here.
    35  *
    36  */
    37 
    38 
    39 #define _GNU_SOURCE
    40 
    41 #include "remmina/plugin.h"
    42 #include "rdp_plugin.h"
    43 #include "rdp_event.h"
    44 #include "rdp_graphics.h"
    45 #include "rdp_file.h"
    46 #include "rdp_settings.h"
    47 #include "rdp_cliprdr.h"
    48 #include "rdp_monitor.h"
    49 #include "rdp_channels.h"
    50 
    51 #include <errno.h>
    52 #include <pthread.h>
    53 #include <time.h>
    54 #include <sys/time.h>
    55 #ifdef GDK_WINDOWING_X11
    56 #include <cairo/cairo-xlib.h>
    57 #else
    58 #include <cairo/cairo.h>
    59 #endif
    60 #include <freerdp/addin.h>
    61 #include <freerdp/assistance.h>
    62 #include <freerdp/settings.h>
    63 #include <freerdp/freerdp.h>
    64 #include <freerdp/constants.h>
    65 #include <freerdp/client/cliprdr.h>
    66 #include <freerdp/client/channels.h>
    67 #include <freerdp/client/cmdline.h>
    68 #include <freerdp/error.h>
    69 #include <freerdp/event.h>
    70 #include <winpr/memory.h>
    71 #include <winpr/cmdline.h>
    72 #include <ctype.h>
    73 
    74 #ifdef HAVE_CUPS
    75 #include <cups/cups.h>
    76 #endif
    77 
    78 #include <unistd.h>
    79 #include <string.h>
    80 
    81 #ifdef GDK_WINDOWING_X11
    82 #include <X11/Xlib.h>
    83 #include <X11/XKBlib.h>
    84 #include <gdk/gdkx.h>
    85 #elif defined(GDK_WINDOWING_WAYLAND)
    86 #include <gdk/gdkwayland.h>
    87 #endif
    88 
    89 #if defined(__FreeBSD__)
    90 #include <pthread_np.h>
    91 #endif
    92 
    93 #include <freerdp/locale/keyboard.h>
    94 
    95 #define REMMINA_RDP_FEATURE_TOOL_REFRESH 1
    96 #define REMMINA_RDP_FEATURE_SCALE 2
    97 #define REMMINA_RDP_FEATURE_UNFOCUS 3
    98 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4
    99 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5
    100 #define REMMINA_RDP_FEATURE_MULTIMON 6
    101 #define REMMINA_RDP_FEATURE_VIEWONLY 7
    102 
    103 #define REMMINA_CONNECTION_TYPE_NONE 0
    104 
    105 #ifdef WITH_FREERDP3
    106  #define CLPARAM const char
    107 #else
    108  #define CLPARAM char
    109 #endif
    110 
    111 
    113 
    114 static BOOL gfx_h264_available = FALSE;
    115 // keep track of last interaction time for keep alive
    116 static time_t last_time;
    117 
    118 /* Compatibility: these functions have been introduced with https://github.com/FreeRDP/FreeRDP/commit/8c5d96784d
    119  * and are missing on older FreeRDP, so we add them here.
    120  * They should be removed from here after all distributed versions of FreeRDP (libwinpr) will have
    121  * CommandLineParseCommaSeparatedValuesEx() onboard.
    122  *
    123  * (C) Copyright goes to the FreeRDP authors.
    124  */
    125 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
    126 {
    127  TRACE_CALL(__func__);
    128 #if FREERDP_CHECK_VERSION(2, 0, 0)
    129  return (CLPARAM **)CommandLineParseCommaSeparatedValuesEx(name, list, count);
    130 #else
    131  char **p;
    132  char *str;
    133  size_t nArgs;
    134  size_t index;
    135  size_t nCommas;
    136  size_t prefix, len;
    137 
    138  nCommas = 0;
    139 
    140  if (count == NULL)
    141  return NULL;
    142 
    143  *count = 0;
    144 
    145  if (!list) {
    146  if (name) {
    147  size_t len = strlen(name);
    148  p = (char **)calloc(2UL + len, sizeof(char *));
    149 
    150  if (p) {
    151  char *dst = (char *)&p[1];
    152  p[0] = dst;
    153  sprintf_s(dst, len + 1, "%s", name);
    154  *count = 1;
    155  return p;
    156  }
    157  }
    158 
    159  return NULL;
    160  }
    161 
    162  {
    163  const char *it = list;
    164 
    165  while ((it = strchr(it, ',')) != NULL) {
    166  it++;
    167  nCommas++;
    168  }
    169  }
    170 
    171  nArgs = nCommas + 1;
    172 
    173  if (name)
    174  nArgs++;
    175 
    176  prefix = (nArgs + 1UL) * sizeof(char *);
    177  len = strlen(list);
    178  p = (char **)calloc(len + prefix + 1, sizeof(char *));
    179 
    180  if (!p)
    181  return NULL;
    182 
    183  str = &((char *)p)[prefix];
    184  memcpy(str, list, len);
    185 
    186  if (name)
    187  p[0] = (char *)name;
    188 
    189  for (index = name ? 1 : 0; index < nArgs; index++) {
    190  char *comma = strchr(str, ',');
    191  p[index] = str;
    192 
    193  if (comma) {
    194  str = comma + 1;
    195  *comma = '\0';
    196  }
    197  }
    198 
    199  *count = nArgs;
    200  return p;
    201 #endif
    202 }
    203 
    204 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
    205 {
    206  TRACE_CALL(__func__);
    207  return remmina_rdp_CommandLineParseCommaSeparatedValuesEx(NULL, list, count);
    208 }
    209 
    210 /*
    211  * End of CommandLineParseCommaSeparatedValuesEx() compatibility and copyright
    212  */
    214 {
    215  TRACE_CALL(__func__);
    216  UINT16 flags;
    217  rdpInput *input;
    218  rfContext *rfi = GET_PLUGIN_DATA(gp);
    219  RemminaPluginRdpEvent *event;
    220  DISPLAY_CONTROL_MONITOR_LAYOUT *dcml;
    221  CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
    222  RemminaFile *remminafile;
    223 
    224  if (rfi->event_queue == NULL)
    225  return true;
    226 
    227  input = rfi->instance->input;
    228 
    229  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    230 
    231  while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) {
    232  time(&last_time); //update last user interaction time
    233  switch (event->type) {
    235 
    236  if (event->key_event.extended1){
    237  flags = KBD_FLAGS_EXTENDED1;
    238  }
    239  else{
    240  flags = event->key_event.extended ? KBD_FLAGS_EXTENDED : 0;
    241  }
    242  flags |= event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
    243  input->KeyboardEvent(input, flags, event->key_event.key_code);
    244  break;
    245 
    247  /*
    248  * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx
    249  */
    250  flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
    251  input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code);
    252  break;
    253 
    255  if (event->mouse_event.extended)
    256  input->ExtendedMouseEvent(input, event->mouse_event.flags,
    257  event->mouse_event.x, event->mouse_event.y);
    258  else
    259  input->MouseEvent(input, event->mouse_event.flags,
    260  event->mouse_event.x, event->mouse_event.y);
    261  break;
    262 
    264  rfi->clipboard.context->ClientFormatList(rfi->clipboard.context, event->clipboard_formatlist.pFormatList);
    265  free(event->clipboard_formatlist.pFormatList);
    266  break;
    267 
    269  response.msgFlags = (event->clipboard_formatdataresponse.data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
    270  response.dataLen = event->clipboard_formatdataresponse.size;
    271  response.requestedFormatData = event->clipboard_formatdataresponse.data;
    272  rfi->clipboard.context->ClientFormatDataResponse(rfi->clipboard.context, &response);
    273  break;
    274 
    276  REMMINA_PLUGIN_DEBUG("Sending client FormatDataRequest to server");
    277  gettimeofday(&(rfi->clipboard.clientformatdatarequest_tv), NULL);
    278  rfi->clipboard.context->ClientFormatDataRequest(rfi->clipboard.context, event->clipboard_formatdatarequest.pFormatDataRequest);
    279  free(event->clipboard_formatdatarequest.pFormatDataRequest);
    280  break;
    281 
    283  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    284  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    285  /* TODO Add an option for this */
    286  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    287  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    288  /* got some crashes with g_malloc0, to be investigated */
    289  dcml = calloc(freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
    290  REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:");
    291  if (!dcml)
    292  break;
    293 
    294  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    295  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
    296  const rdpMonitor *current = &base[i];
    297  REMMINA_PLUGIN_DEBUG("Sending display layout for monitor n° %d", i);
    298  dcml[i].Flags = (current->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
    299  REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags);
    300  dcml[i].Left = current->x;
    301  REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left);
    302  dcml[i].Top = current->y;
    303  REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top);
    304  dcml[i].Width = current->width;
    305  REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width);
    306  dcml[i].Height = current->height;
    307  REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height);
    308  dcml[i].PhysicalWidth = current->attributes.physicalWidth;
    309  REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth);
    310  dcml[i].PhysicalHeight = current->attributes.physicalHeight;
    311  REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight);
    312  if (current->attributes.orientation)
    313  dcml[i].Orientation = current->attributes.orientation;
    314  else
    315  dcml[i].Orientation = event->monitor_layout.desktopOrientation;
    316  REMMINA_PLUGIN_DEBUG("Monitor %d orientation: %d", i, dcml[i].Orientation);
    317  dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
    318  dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
    319  }
    320  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), dcml);
    321  g_free(dcml);
    322  } else {
    323  dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
    324  if (dcml) {
    325  dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
    326  dcml->Width = event->monitor_layout.width;
    327  dcml->Height = event->monitor_layout.height;
    328  dcml->Orientation = event->monitor_layout.desktopOrientation;
    329  dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
    330  dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
    331  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml);
    332  g_free(dcml); \
    333  }
    334  }
    335  break;
    337  /* Disconnect requested via GUI (i.e: tab destroy/close) */
    338  freerdp_abort_connect(rfi->instance);
    339  break;
    340  }
    341 
    342  g_free(event);
    343  }
    344 
    345  return true;
    346 }
    347 
    349 {
    350  TRACE_CALL(__func__);
    351 
    352  /* Opens the optional SSH tunnel if needed.
    353  * Used also when reopening the same tunnel for a FreeRDP reconnect.
    354  * Returns TRUE if all OK, and setups correct rfi->Settings values
    355  * with connection and certificate parameters */
    356 
    357  gchar *hostport;
    358  gchar *s;
    359  gchar *host;
    360  gchar *cert_host;
    361  gint cert_port;
    362  gint port;
    363 
    364  rfContext *rfi = GET_PLUGIN_DATA(gp);
    365 
    366  REMMINA_PLUGIN_DEBUG("Tunnel init");
    367  hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 3389, FALSE);
    368  if (hostport == NULL)
    369  return FALSE;
    370 
    371  remmina_plugin_service->get_server_port(hostport, 3389, &host, &port);
    372 
    373  if (host[0] == 0)
    374  return FALSE;
    375 
    376  REMMINA_PLUGIN_DEBUG("protocol_plugin_start_direct_tunnel() returned %s", hostport);
    377 
    378  cert_host = host;
    379  cert_port = port;
    380 
    381  if (!rfi->is_reconnecting) {
    382  /* settings->CertificateName and settings->ServerHostname is created
    383  * only on 1st connect, not on reconnections */
    384 
    385  freerdp_settings_set_string(rfi->settings, FreeRDP_ServerHostname, host);
    386 
    387  if (cert_port == 3389) {
    388  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, cert_host);
    389  } else {
    390  s = g_strdup_printf("%s:%d", cert_host, cert_port);
    391  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, s);
    392  g_free(s);
    393  }
    394  }
    395 
    396  REMMINA_PLUGIN_DEBUG("Tunnel has been optionally initialized. Now connecting to %s:%d", host, port);
    397 
    398  if (cert_host != host) g_free(cert_host);
    399  g_free(host);
    400  g_free(hostport);
    401 
    402  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ServerPort, port);
    403 
    404  return TRUE;
    405 }
    406 
    407 static BOOL rf_auto_reconnect(rfContext *rfi)
    408 {
    409  TRACE_CALL(__func__);
    410  rdpSettings *settings = rfi->instance->settings;
    412  time_t treconn;
    413  gchar *cval;
    414  gint maxattempts;
    415 
    417  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    418 
    419  rfi->is_reconnecting = TRUE;
    420  rfi->stop_reconnecting_requested = FALSE;
    421 
    422  /* Get the value set in FreeRDP_AutoReconnectMaxRetries (20) */
    423  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
    424  REMMINA_PLUGIN_DEBUG("maxattempts from default: %d", maxattempts);
    425  /* Get the value from the global preferences if any */
    426  if ((cval = remmina_plugin_service->pref_get_value("rdp_reconnect_attempts")) != NULL)
    427  maxattempts = atoi(cval);
    428  REMMINA_PLUGIN_DEBUG("maxattempts from general preferences: %d", maxattempts);
    429  /* Get the value from the profile if any, otherwise uses the value of maxattempts */
    430  maxattempts = remmina_plugin_service->file_get_int(remminafile, "rdp_reconnect_attempts", maxattempts);
    431  REMMINA_PLUGIN_DEBUG("maxattempts from general plugin: %d", maxattempts);
    432  /* If maxattemps is <= 0, we get the value from FreeRDP_AutoReconnectMaxRetries (20) */
    433  if (maxattempts <= 0)
    434  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
    435  freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, maxattempts);
    436  REMMINA_PLUGIN_DEBUG("maxattempts set to: %d", maxattempts);
    437 
    438  rfi->reconnect_maxattempts = maxattempts;
    439  rfi->reconnect_nattempt = 0;
    440 
    441  /* Only auto reconnect on network disconnects. */
    442  switch (freerdp_error_info(rfi->instance)) {
    443  case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
    444  /* Disconnected by server hitting a bug or resource limit */
    445  break;
    446  case ERRINFO_SUCCESS:
    447  /* A network disconnect was detected */
    448  break;
    449  default:
    450  rfi->is_reconnecting = FALSE;
    451  return FALSE;
    452  }
    453 
    454  if (!freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled)) {
    455  /* No auto-reconnect - just quit */
    456  rfi->is_reconnecting = FALSE;
    457  return FALSE;
    458  }
    459 
    460  /* A network disconnect was detected and we should try to reconnect */
    461  REMMINA_PLUGIN_DEBUG("[%s] network disconnection detected, initiating reconnection attempt",
    462  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    463 
    464  ui = g_new0(RemminaPluginRdpUiObject, 1);
    467 
    468  /* Sleep half a second to allow:
    469  * - processing of the UI event we just pushed on the queue
    470  * - better network conditions
    471  * Remember: We hare on a thread, so the main gui won’t lock */
    472  usleep(500000);
    473 
    474  /* Perform an auto-reconnect. */
    475  while (TRUE) {
    476  /* Quit retrying if max retries has been exceeded */
    477  if (rfi->reconnect_nattempt++ >= rfi->reconnect_maxattempts) {
    478  REMMINA_PLUGIN_DEBUG("[%s] maximum number of reconnection attempts exceeded.",
    479  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    480  break;
    481  }
    482 
    483  if (rfi->stop_reconnecting_requested) {
    484  REMMINA_PLUGIN_DEBUG("[%s] reconnect request loop interrupted by user.",
    485  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    486  break;
    487  }
    488 
    489  /* Attempt the next reconnect */
    490  REMMINA_PLUGIN_DEBUG("[%s] reconnection, attempt #%d of %d",
    491  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname), rfi->reconnect_nattempt, rfi->reconnect_maxattempts);
    492 
    493  ui = g_new0(RemminaPluginRdpUiObject, 1);
    496 
    497  treconn = time(NULL);
    498 
    499  /* Reconnect the SSH tunnel, if needed */
    501  REMMINA_PLUGIN_DEBUG("[%s] unable to recreate tunnel with remmina_rdp_tunnel_init.",
    502  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    503  } else {
    504  if (freerdp_reconnect(rfi->instance)) {
    505  /* Reconnection is successful */
    506  REMMINA_PLUGIN_DEBUG("[%s] reconnected.", freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    507  rfi->is_reconnecting = FALSE;
    508  return TRUE;
    509  }
    510  }
    511 
    512  /* Wait until 5 secs have elapsed from last reconnect attempt, while checking for rfi->stop_reconnecting_requested */
    513  while (time(NULL) - treconn < 5) {
    515  break;
    516  usleep(200000); // 200ms sleep
    517  }
    518  }
    519 
    520  rfi->is_reconnecting = FALSE;
    521  return FALSE;
    522 }
    523 
    524 static BOOL rf_begin_paint(rdpContext *context)
    525 {
    526  TRACE_CALL(__func__);
    527  rdpGdi *gdi;
    528 
    529  if (!context)
    530  return FALSE;
    531 
    532  gdi = context->gdi;
    533  if (!gdi || !gdi->primary || !gdi->primary->hdc || !gdi->primary->hdc->hwnd)
    534  return FALSE;
    535 
    536  return TRUE;
    537 }
    538 
    539 static BOOL rf_end_paint(rdpContext *context)
    540 {
    541  TRACE_CALL(__func__);
    542  rdpGdi *gdi;
    543  rfContext *rfi;
    545  int i, ninvalid;
    546  region *reg;
    547  HGDI_RGN cinvalid;
    548 
    549  gdi = context->gdi;
    550  rfi = (rfContext *)context;
    551 
    552  if (gdi == NULL || gdi->primary == NULL || gdi->primary->hdc == NULL || gdi->primary->hdc->hwnd == NULL)
    553  return TRUE;
    554 
    555  if (gdi->primary->hdc->hwnd->invalid->null)
    556  return TRUE;
    557 
    558  if (gdi->primary->hdc->hwnd->ninvalid < 1)
    559  return TRUE;
    560 
    561  ninvalid = gdi->primary->hdc->hwnd->ninvalid;
    562  cinvalid = gdi->primary->hdc->hwnd->cinvalid;
    563  reg = (region *)g_malloc(sizeof(region) * ninvalid);
    564  for (i = 0; i < ninvalid; i++) {
    565  reg[i].x = cinvalid[i].x;
    566  reg[i].y = cinvalid[i].y;
    567  reg[i].w = cinvalid[i].w;
    568  reg[i].h = cinvalid[i].h;
    569  }
    570 
    571  ui = g_new0(RemminaPluginRdpUiObject, 1);
    573  ui->reg.ninvalid = ninvalid;
    574  ui->reg.ureg = reg;
    575 
    577 
    578 
    579  gdi->primary->hdc->hwnd->invalid->null = TRUE;
    580  gdi->primary->hdc->hwnd->ninvalid = 0;
    581 
    582 
    583  return TRUE;
    584 }
    585 
    586 static BOOL rf_desktop_resize(rdpContext *context)
    587 {
    588  TRACE_CALL(__func__);
    589  rfContext *rfi;
    592  UINT32 w, h;
    593 
    594  rfi = (rfContext *)context;
    595  gp = rfi->protocol_widget;
    596 
    597  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    598  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
    599  remmina_plugin_service->protocol_plugin_set_width(gp, w);
    600  remmina_plugin_service->protocol_plugin_set_height(gp, h);
    601 
    602  ui = g_new0(RemminaPluginRdpUiObject, 1);
    606 
    607  /* Tell libfreerdp to change its internal GDI bitmap width and heigt,
    608  * this will also destroy gdi->primary_buffer, making our rfi->surface invalid */
    609  gdi_resize(((rdpContext *)rfi)->gdi, w, h);
    610 
    611  /* Call to remmina_rdp_event_update_scale(gp) on the main UI thread,
    612  * this will recreate rfi->surface from gdi->primary_buffer */
    613 
    614  ui = g_new0(RemminaPluginRdpUiObject, 1);
    618 
    619  remmina_plugin_service->protocol_plugin_desktop_resize(gp);
    620 
    621  return TRUE;
    622 }
    623 
    624 static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
    625 {
    626  TRACE_CALL(__func__);
    627  rfContext *rfi;
    629  GdkDisplay *disp;
    630 
    631  rfi = (rfContext *)context;
    632  gp = rfi->protocol_widget;
    633 
    634  disp = gtk_widget_get_display(GTK_WIDGET(gp));
    635  gdk_display_beep(disp);
    636 
    637  return TRUE;
    638 }
    639 
    640 static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
    641 {
    642  TRACE_CALL(__func__);
    643  rfContext *rfi;
    645  GdkDisplay *disp;
    646 
    647  rfi = (rfContext *)context;
    648  gp = rfi->protocol_widget;
    649  disp = gtk_widget_get_display(GTK_WIDGET(gp));
    650 
    651 #ifdef GDK_WINDOWING_X11
    652  if (GDK_IS_X11_DISPLAY(disp)) {
    653  /* TODO: We are not on the main thread. Will X.Org complain? */
    654  Display *x11_display;
    655  x11_display = gdk_x11_display_get_xdisplay(disp);
    656  XkbLockModifiers(x11_display, XkbUseCoreKbd,
    657  LockMask | Mod2Mask,
    658  ((led_flags & KBD_SYNC_CAPS_LOCK) ? LockMask : 0) |
    659  ((led_flags & KBD_SYNC_NUM_LOCK) ? Mod2Mask : 0)
    660  );
    661 
    662  /* TODO: Add support to KANA_LOCK and SCROLL_LOCK */
    663  }
    664 #endif
    665 
    666  return TRUE;
    667 }
    668 
    669 static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState,
    670  UINT32 imeConvMode)
    671 {
    672  TRACE_CALL(__func__);
    673  if (!context)
    674  return FALSE;
    675 
    676  /* Unimplemented, we ignore it */
    677 
    678  return TRUE;
    679 }
    680 
    681 static BOOL remmina_rdp_pre_connect(freerdp *instance)
    682 {
    683  TRACE_CALL(__func__);
    684  rdpChannels *channels;
    685  rdpSettings *settings;
    686  rdpContext *context = instance->context;
    687 
    688  settings = instance->settings;
    689  channels = context->channels;
    690  freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX);
    691  freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
    692  freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE);
    693  freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 1);
    694 
    695  PubSub_SubscribeChannelConnected(instance->context->pubSub,
    697  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
    699 
    700  if (!freerdp_client_load_addins(channels, settings))
    701  return FALSE;
    702 
    703  return true;
    704 }
    705 
    706 static BOOL remmina_rdp_post_connect(freerdp *instance)
    707 {
    708  TRACE_CALL(__func__);
    709  rfContext *rfi;
    712  UINT32 freerdp_local_color_format;
    713 
    714  rfi = (rfContext *)instance->context;
    715  gp = rfi->protocol_widget;
    716  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK;
    717 
    718  rfi->attempt_interactive_authentication = FALSE; // We authenticated!
    719 
    720  rfi->srcBpp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth);
    721 
    722  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) == FALSE)
    723  rfi->sw_gdi = TRUE;
    724 
    725  rf_register_graphics(instance->context->graphics);
    726 
    727  REMMINA_PLUGIN_DEBUG("bpp: %d", rfi->bpp);
    728  switch (rfi->bpp) {
    729  case 24:
    730  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
    731  freerdp_local_color_format = PIXEL_FORMAT_BGRX32;
    732  rfi->cairo_format = CAIRO_FORMAT_RGB24;
    733  break;
    734  case 32:
    739  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
    740  freerdp_local_color_format = PIXEL_FORMAT_BGRA32;
    741  rfi->cairo_format = CAIRO_FORMAT_RGB24;
    742  break;
    743  default:
    744  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB16_565");
    745  freerdp_local_color_format = PIXEL_FORMAT_RGB16;
    746  rfi->cairo_format = CAIRO_FORMAT_RGB16_565;
    747  break;
    748  }
    749 
    750  if (!gdi_init(instance, freerdp_local_color_format)) {
    751  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_GDI_INIT;
    752  return FALSE;
    753  }
    754 
    755  if (instance->context->codecs->h264 == NULL && freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
    756  gdi_free(instance);
    757  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_NO_H264;
    758  return FALSE;
    759  }
    760 
    761  // pointer_cache_register_callbacks(instance->update);
    762 
    763  instance->update->BeginPaint = rf_begin_paint;
    764  instance->update->EndPaint = rf_end_paint;
    765  instance->update->DesktopResize = rf_desktop_resize;
    766 
    767  instance->update->PlaySound = rf_play_sound;
    768  instance->update->SetKeyboardIndicators = rf_keyboard_set_indicators;
    769  instance->update->SetKeyboardImeStatus = rf_keyboard_set_ime_status;
    770 
    772  rfi->connected = true;
    773 
    774  ui = g_new0(RemminaPluginRdpUiObject, 1);
    777 
    778  return TRUE;
    779 }
    780 
    781 static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
    782 {
    783  TRACE_CALL(__func__);
    784  gchar *s_username, *s_password, *s_domain;
    785  gint ret;
    786  rfContext *rfi;
    788  gboolean save;
    789  gboolean disablepasswordstoring;
    790  RemminaFile *remminafile;
    791 
    792  rfi = (rfContext *)instance->context;
    793  gp = rfi->protocol_widget;
    794  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    795  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
    796 
    797  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    799  _("Enter RDP authentication credentials"),
    800  remmina_plugin_service->file_get_string(remminafile, "username"),
    801  remmina_plugin_service->file_get_string(remminafile, "password"),
    802  remmina_plugin_service->file_get_string(remminafile, "domain"),
    803  NULL);
    804  if (ret == GTK_RESPONSE_OK) {
    805  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
    806  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_Username, s_username);
    807 
    808  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
    809  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s_password);
    810 
    811  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
    812  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, s_domain);
    813 
    814  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
    815  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
    816 
    817  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
    818  if (save) {
    819  // User has requested to save credentials. We put the password
    820  // into remminafile->settings. It will be saved later, on successful connection, by
    821  // rcw.c
    822  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
    823  } else {
    824  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
    825  }
    826 
    827 
    828  if (s_username) g_free(s_username);
    829  if (s_password) g_free(s_password);
    830  if (s_domain) g_free(s_domain);
    831 
    832  return TRUE;
    833  } else {
    834  return FALSE;
    835  }
    836 
    837  return TRUE;
    838 }
    839 
    840 static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
    841 {
    842  TRACE_CALL(__func__);
    843  gchar *s_username, *s_password, *s_domain;
    844  gint ret;
    845  rfContext *rfi;
    847  gboolean save;
    848  gboolean disablepasswordstoring;
    849  gboolean basecredforgw;
    850  RemminaFile *remminafile;
    851 
    852  rfi = (rfContext *)instance->context;
    853  gp = rfi->protocol_widget;
    854  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    855 
    856  if (!remmina_plugin_service->file_get_string(remminafile, "gateway_server"))
    857  return false;
    858  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
    859  basecredforgw = remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE);
    860 
    861  if (basecredforgw) {
    862  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    864  _("Enter RDP authentication credentials"),
    865  remmina_plugin_service->file_get_string(remminafile, "username"),
    866  remmina_plugin_service->file_get_string(remminafile, "password"),
    867  remmina_plugin_service->file_get_string(remminafile, "domain"),
    868  NULL);
    869  } else {
    870  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
    872  _("Enter RDP gateway authentication credentials"),
    873  remmina_plugin_service->file_get_string(remminafile, "gateway_username"),
    874  remmina_plugin_service->file_get_string(remminafile, "gateway_password"),
    875  remmina_plugin_service->file_get_string(remminafile, "gateway_domain"),
    876  NULL);
    877  }
    878 
    879 
    880  if (ret == GTK_RESPONSE_OK) {
    881  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
    882  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, s_username);
    883 
    884  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
    885  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s_password);
    886 
    887  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
    888  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, s_domain);
    889 
    890  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
    891 
    892  if (basecredforgw) {
    893  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
    894  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
    895  if (save)
    896  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
    897  else
    898  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
    899  } else {
    900  remmina_plugin_service->file_set_string(remminafile, "gateway_username", s_username);
    901  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", s_domain);
    902  if (save)
    903  remmina_plugin_service->file_set_string(remminafile, "gateway_password", s_password);
    904  else
    905  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
    906  }
    907 
    908  if (s_username) g_free(s_username);
    909  if (s_password) g_free(s_password);
    910  if (s_domain) g_free(s_domain);
    911 
    912  return true;
    913  } else {
    914  return false;
    915  }
    916 
    917  return true;
    918 }
    919 
    920 static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
    921  const char *common_name, const char *subject,
    922  const char *issuer, const char *fingerprint, DWORD flags)
    923 {
    924  TRACE_CALL(__func__);
    925  gint status;
    926  rfContext *rfi;
    928 
    929  rfi = (rfContext *)instance->context;
    930  gp = rfi->protocol_widget;
    931 
    932  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
    933 
    934  if (status == GTK_RESPONSE_OK)
    935  return 1;
    936 
    937  return 0;
    938 }
    939 
    940 static DWORD
    941 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__ ((unused));
    942 static DWORD
    943 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
    944  const char *issuer, const char *fingerprint, BOOL host_mismatch)
    945 {
    946  TRACE_CALL(__func__);
    947  gint status;
    948  rfContext *rfi;
    950 
    951  rfi = (rfContext *)instance->context;
    952  gp = rfi->protocol_widget;
    953 
    954  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
    955 
    956  if (status == GTK_RESPONSE_OK)
    957  return 1;
    958 
    959  return 0;
    960 }
    961 
    962 static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
    963  const char *common_name, const char *subject,
    964  const char *issuer, const char *fingerprint,
    965  const char *old_subject, const char *old_issuer,
    966  const char *old_fingerprint, DWORD flags)
    967 {
    968  TRACE_CALL(__func__);
    969  gint status;
    970  rfContext *rfi;
    972 
    973  rfi = (rfContext *)instance->context;
    974  gp = rfi->protocol_widget;
    975 
    976  status = remmina_plugin_service->protocol_plugin_changed_certificate(gp, subject, issuer, fingerprint, old_fingerprint);
    977 
    978  if (status == GTK_RESPONSE_OK)
    979  return 1;
    980 
    981  return 0;
    982 }
    983 
    984 static void remmina_rdp_post_disconnect(freerdp *instance)
    985 {
    986  TRACE_CALL(__func__);
    987 
    988  if (!instance || !instance->context)
    989  return;
    990 
    991  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
    993  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
    995 
    996  /* The remaining cleanup will be continued on main thread by complete_cleanup_on_main_thread() */
    997 }
    998 
    1000 {
    1001  TRACE_CALL(__func__);
    1002  DWORD status;
    1003  gchar buf[100];
    1004  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1005  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1006  time_t cur_time, time_diff;
    1007 
    1008  int jitter_time = remmina_plugin_service->file_get_int(remminafile, "rdp_mouse_jitter", 0);
    1009  time(&last_time);
    1010  while (!freerdp_shall_disconnect(rfi->instance)) {
    1011  //move mouse if we've been idle and option is selected
    1012  time(&cur_time);
    1013  time_diff = cur_time - last_time;
    1014  if (jitter_time > 0 && time_diff > jitter_time){
    1015  last_time = cur_time;
    1017  }
    1018 
    1019  HANDLE handles[64]={0};
    1020  DWORD nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64);
    1021  if (rfi->event_handle)
    1022  handles[nCount++] = rfi->event_handle;
    1023 
    1024  handles[nCount++] = rfi->instance->context->abortEvent;
    1025 
    1026  if (nCount == 0) {
    1027  fprintf(stderr, "freerdp_get_event_handles failed\n");
    1028  break;
    1029  }
    1030 
    1031  status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
    1032 
    1033  if (status == WAIT_FAILED) {
    1034  fprintf(stderr, "WaitForMultipleObjects failed with %lu\n", (unsigned long)status);
    1035  break;
    1036  }
    1037 
    1038  if (rfi->event_handle && WaitForSingleObject(rfi->event_handle, 0) == WAIT_OBJECT_0) {
    1039  if (!rf_process_event_queue(gp)) {
    1040  fprintf(stderr, "Could not process local keyboard/mouse event queue\n");
    1041  break;
    1042  }
    1043  if (read(rfi->event_pipe[0], buf, sizeof(buf))) {
    1044  }
    1045  }
    1046 
    1047  /* Check if a processed event called freerdp_abort_connect() and exit if true */
    1048  if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0)
    1049  /* Session disconnected by local user action */
    1050  break;
    1051 
    1052  if (!freerdp_check_event_handles(rfi->instance->context)) {
    1053  if (rf_auto_reconnect(rfi)) {
    1054  /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */
    1055  remmina_plugin_service->protocol_plugin_set_error(gp, NULL);
    1056  continue;
    1057  }
    1058  if (freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS)
    1059  fprintf(stderr, "Could not check FreeRDP file descriptor\n");
    1060  break;
    1061  }
    1062  }
    1063  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
    1064  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    1065  REMMINA_PLUGIN_AUDIT(_("Disconnected from %s via RDP"), host);
    1066  freerdp_disconnect(rfi->instance);
    1067  REMMINA_PLUGIN_DEBUG("RDP client disconnected");
    1068 }
    1069 
    1070 static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
    1071 {
    1072  TRACE_CALL(__func__);
    1073  PVIRTUALCHANNELENTRY entry = NULL;
    1074  PVIRTUALCHANNELENTRYEX entryEx = NULL;
    1075 
    1076  entryEx = (PVIRTUALCHANNELENTRYEX)(void *)freerdp_load_channel_addin_entry(
    1077  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
    1078 
    1079  if (!entryEx)
    1080  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
    1081 
    1082  if (entryEx) {
    1083  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0) {
    1084  fprintf(stderr, "loading channel %s\n", name);
    1085  return TRUE;
    1086  }
    1087  } else if (entry) {
    1088  if (freerdp_channels_client_load(channels, settings, entry, data) == 0) {
    1089  fprintf(stderr, "loading channel %s\n", name);
    1090  return TRUE;
    1091  }
    1092  }
    1093 
    1094  return FALSE;
    1095 }
    1096 
    1097 static gchar *remmina_rdp_find_prdriver(char *smap, char *prn)
    1098 {
    1099  char c, *p, *dr;
    1100  int matching;
    1101  size_t sz;
    1102 
    1103  enum { S_WAITPR,
    1104  S_INPRINTER,
    1105  S_WAITCOLON,
    1106  S_WAITDRIVER,
    1107  S_INDRIVER,
    1108  S_WAITSEMICOLON } state = S_WAITPR;
    1109 
    1110  matching = 0;
    1111  while ((c = *smap++) != 0) {
    1112  switch (state) {
    1113  case S_WAITPR:
    1114  if (c != '\"') return NULL;
    1115  state = S_INPRINTER;
    1116  p = prn;
    1117  matching = 1;
    1118  break;
    1119  case S_INPRINTER:
    1120  if (matching && c == *p && *p != 0) {
    1121  p++;
    1122  } else if (c == '\"') {
    1123  if (*p != 0)
    1124  matching = 0;
    1125  state = S_WAITCOLON;
    1126  } else {
    1127  matching = 0;
    1128  }
    1129  break;
    1130  case S_WAITCOLON:
    1131  if (c != ':')
    1132  return NULL;
    1133  state = S_WAITDRIVER;
    1134  break;
    1135  case S_WAITDRIVER:
    1136  if (c != '\"')
    1137  return NULL;
    1138  state = S_INDRIVER;
    1139  dr = smap;
    1140  break;
    1141  case S_INDRIVER:
    1142  if (c == '\"') {
    1143  if (matching)
    1144  goto found;
    1145  else
    1146  state = S_WAITSEMICOLON;
    1147  }
    1148  break;
    1149  case S_WAITSEMICOLON:
    1150  if (c != ';')
    1151  return NULL;
    1152  state = S_WAITPR;
    1153  break;
    1154  }
    1155  }
    1156  return NULL;
    1157 
    1158 found:
    1159  sz = smap - dr;
    1160  p = (char *)malloc(sz);
    1161  memcpy(p, dr, sz);
    1162  p[sz - 1] = 0;
    1163  return p;
    1164 }
    1165 
    1166 #ifdef HAVE_CUPS
    1167 
    1172 static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
    1173 {
    1174  rfContext *rfi = (rfContext *)user_data;
    1176 
    1191  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1192  const gchar *s = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
    1193 
    1194  RDPDR_PRINTER *printer;
    1195  printer = (RDPDR_PRINTER *)calloc(1, sizeof(RDPDR_PRINTER));
    1196 
    1197 #ifdef WITH_FREERDP3
    1198  RDPDR_DEVICE *pdev;
    1199  pdev = &(printer->device);
    1200 #else
    1201  RDPDR_PRINTER *pdev;
    1202  pdev = printer;
    1203 #endif
    1204 
    1205  pdev->Type = RDPDR_DTYP_PRINT;
    1206  REMMINA_PLUGIN_DEBUG("Printer Type: %d", pdev->Type);
    1207 
    1208  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectPrinters, TRUE);
    1209  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    1210 
    1211  REMMINA_PLUGIN_DEBUG("Destination: %s", dest->name);
    1212  if (!(pdev->Name = _strdup(dest->name))) {
    1213  free(printer);
    1214  return 1;
    1215  }
    1216 
    1217  REMMINA_PLUGIN_DEBUG("Printer Name: %s", pdev->Name);
    1218 
    1219  if (s) {
    1220  gchar *d = remmina_rdp_find_prdriver(strdup(s), pdev->Name);
    1221  if (d) {
    1222  printer->DriverName = strdup(d);
    1223  REMMINA_PLUGIN_DEBUG("Printer DriverName set to: %s", printer->DriverName);
    1224  g_free(d);
    1225  } else {
    1231  free(pdev->Name);
    1232  free(printer);
    1233  return 1;
    1234  }
    1235  } else {
    1236  /* We set to a default driver*/
    1237  printer->DriverName = _strdup("MS Publisher Imagesetter");
    1238  }
    1239 
    1240  REMMINA_PLUGIN_DEBUG("Printer Driver: %s", printer->DriverName);
    1241  if (!freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)printer)) {
    1242  free(printer->DriverName);
    1243  free(pdev->Name);
    1244  free(printer);
    1245  return 1;
    1246  }
    1247 
    1248  return 1;
    1249 }
    1250 #endif /* HAVE_CUPS */
    1251 
    1252 /* Send Ctrl+Alt+Del keystrokes to the plugin drawing_area widget */
    1254 {
    1255  TRACE_CALL(__func__);
    1256  guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
    1257  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1258 
    1259  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
    1260  keys, G_N_ELEMENTS(keys), GDK_KEY_PRESS | GDK_KEY_RELEASE);
    1261 }
    1262 
    1263 static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
    1264 {
    1265  freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type);
    1266 
    1267  if (type == CONNECTION_TYPE_MODEM) {
    1268  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1269  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1270  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
    1271  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1272  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1273  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, TRUE);
    1274  } else if (type == CONNECTION_TYPE_BROADBAND_LOW) {
    1275  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1276  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1277  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
    1278  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1279  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1280  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1281  } else if (type == CONNECTION_TYPE_SATELLITE) {
    1282  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1283  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1284  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1285  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1286  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1287  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1288  } else if (type == CONNECTION_TYPE_BROADBAND_HIGH) {
    1289  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
    1290  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
    1291  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1292  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
    1293  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
    1294  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1295  } else if (type == CONNECTION_TYPE_WAN) {
    1296  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1297  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1298  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1299  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1300  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1301  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1302  } else if (type == CONNECTION_TYPE_LAN) {
    1303  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1304  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1305  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1306  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1307  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1308  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1309  } else if (type == CONNECTION_TYPE_AUTODETECT) {
    1310  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
    1311  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
    1312  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
    1313  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
    1314  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
    1315  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
    1316  freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE);
    1317 
    1318  /* Automatically activate GFX and RFX codec support */
    1319 #ifdef WITH_GFX_H264
    1320  freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1321  freerdp_settings_set_bool(settings, FreeRDP_GfxH264, gfx_h264_available);
    1322 #endif
    1323  freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE);
    1324  freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1325  } else if (type == REMMINA_CONNECTION_TYPE_NONE) {
    1326  return FALSE;
    1327  } else {
    1328  return FALSE;
    1329  }
    1330 
    1331  return TRUE;
    1332 }
    1333 
    1334 #ifdef GDK_WINDOWING_X11
    1335 #if FREERDP_CHECK_VERSION(2, 3, 0)
    1336 static gchar *remmina_get_rdp_kbd_remap(const gchar *keymap)
    1337 {
    1338  TRACE_CALL(__func__);
    1339  guint *table;
    1340  gchar keys[20];
    1341  gchar *rdp_kbd_remap = NULL;
    1342  gint i;
    1343  Display *display;
    1344 
    1345  table = remmina_plugin_service->pref_keymap_get_table(keymap);
    1346  if (!table)
    1347  return rdp_kbd_remap;
    1348  rdp_kbd_remap = g_malloc0(512);
    1349  display = XOpenDisplay(0);
    1350  for (i = 0; table[i] > 0; i += 2) {
    1351  g_snprintf(keys, sizeof(keys), "0x%02x=0x%02x", freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i])),
    1352  freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i + 1])));
    1353  if (i > 0)
    1354  g_strlcat(rdp_kbd_remap, ",", 512);
    1355  g_strlcat(rdp_kbd_remap, keys, 512);
    1356  }
    1357  XCloseDisplay(display);
    1358 
    1359  return rdp_kbd_remap;
    1360 }
    1361 #endif
    1362 #endif
    1363 
    1365 {
    1366  TRACE_CALL(__func__);
    1367  const gchar *s;
    1368  gchar *sm;
    1369  gchar *value;
    1370  const gchar *cs;
    1371  RemminaFile *remminafile;
    1372  rfContext *rfi = GET_PLUGIN_DATA(gp);
    1373  rdpChannels *channels;
    1374  gchar *gateway_host;
    1375  gint gateway_port;
    1376  gchar *datapath = NULL;
    1377  gboolean status = TRUE;
    1378 #ifdef GDK_WINDOWING_X11
    1379  gchar *rdp_kbd_remap;
    1380 #endif
    1381  gint i;
    1382 
    1383  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
    1384 
    1385  channels = rfi->instance->context->channels;
    1386 
    1387  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    1388 
    1389  datapath = g_build_path("/",
    1390  remmina_plugin_service->file_get_user_datadir(),
    1391  "RDP",
    1392  NULL);
    1393  REMMINA_PLUGIN_DEBUG("RDP data path is %s", datapath);
    1394 
    1395  if ((datapath != NULL) && (datapath[0] != '\0'))
    1396  if (access(datapath, W_OK) == 0)
    1397  freerdp_settings_set_string(rfi->settings, FreeRDP_ConfigPath, datapath);
    1398  g_free(datapath);
    1399 
    1400  if (remmina_plugin_service->file_get_int(remminafile, "assistance_mode", 0)){
    1401  rdpAssistanceFile* file = freerdp_assistance_file_new();
    1402  if (!file){
    1403  REMMINA_PLUGIN_DEBUG("Could not allocate assistance file structure");
    1404  return FALSE;
    1405  }
    1406 
    1407  if (remmina_plugin_service->file_get_string(remminafile, "assistance_file") == NULL ||
    1408  remmina_plugin_service->file_get_string(remminafile, "assistance_pass") == NULL ){
    1409 
    1410  REMMINA_PLUGIN_DEBUG("Assistance file and password are not set while assistance mode is on");
    1411  return FALSE;
    1412  }
    1413 
    1414  status = freerdp_assistance_parse_file(file,
    1415  remmina_plugin_service->file_get_string(remminafile, "assistance_file"),
    1416  remmina_plugin_service->file_get_string(remminafile, "assistance_pass"));
    1417 
    1418  if (status < 0){
    1419  REMMINA_PLUGIN_DEBUG("Could not parse assistance file");
    1420  return FALSE;
    1421  }
    1422 
    1423 
    1424  if (!freerdp_assistance_populate_settings_from_assistance_file(file, rfi->settings)){
    1425  REMMINA_PLUGIN_DEBUG("Could not populate settings from assistance file");
    1426  return FALSE;
    1427  }
    1428  }
    1429 
    1430 
    1431 #if defined(PROXY_TYPE_IGNORE)
    1432  if (!remmina_plugin_service->file_get_int(remminafile, "useproxyenv", FALSE) ? TRUE : FALSE) {
    1433  REMMINA_PLUGIN_DEBUG("Not using system proxy settings");
    1434  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
    1435  }
    1436 #endif
    1437 
    1438  if (!remmina_rdp_tunnel_init(gp))
    1439  return FALSE;
    1440 
    1441  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, (remmina_plugin_service->file_get_int(remminafile, "disableautoreconnect", FALSE) ? FALSE : TRUE));
    1442  /* Disable RDP auto reconnection when SSH tunnel is enabled */
    1443  if (remmina_plugin_service->file_get_int(remminafile, "ssh_tunnel_enabled", FALSE))
    1444  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, FALSE);
    1445 
    1446  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, remmina_plugin_service->file_get_int(remminafile, "colordepth", 99));
    1447 
    1448  freerdp_settings_set_bool(rfi->settings, FreeRDP_SoftwareGdi, TRUE);
    1449  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    1450 
    1451  /* Avoid using H.264 modes if they are not available on libfreerdp */
    1452  if (!gfx_h264_available && (freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth) == 65 || freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth == 66)))
    1453  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 64); // Fallback to GFX RFX
    1454 
    1455  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 0) {
    1456  /* RFX (Win7)*/
    1457  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1458  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, FALSE);
    1459  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1460  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 63) {
    1461  /* /gfx (RFX Progressive) (Win8) */
    1462  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1463  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1464  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
    1465  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1466  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 64) {
    1467  /* /gfx:rfx (Win8) */
    1468  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1469  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1470  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1471  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
    1472  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1473  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 65) {
    1474  /* /gfx:avc420 (Win8.1) */
    1475  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1476  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1477  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1478  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
    1479  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 66) {
    1480  /* /gfx:avc444 (Win10) */
    1481  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1482  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1483  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1484  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1485  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 99) {
    1486  /* Automatic (Let the server choose its best format) */
    1487  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1488  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
    1489  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
    1490  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
    1491  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
    1492  }
    1493 
    1494  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) ||
    1495  freerdp_settings_get_bool(rfi->settings, FreeRDP_NSCodec) ||
    1496  freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
    1497  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
    1498  freerdp_settings_set_bool(rfi->settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
    1499  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
    1500  rfi->bpp = 32;
    1501  }
    1502 
    1503  gint w = remmina_plugin_service->get_profile_remote_width(gp);
    1504  gint h = remmina_plugin_service->get_profile_remote_height(gp);
    1505  /* multiple of 4 */
    1506  w = (w + 3) & ~0x3;
    1507  h = (h + 3) & ~0x3;
    1508  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, w);
    1509  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, h);
    1510  REMMINA_PLUGIN_DEBUG("Resolution set by the user: %dx%d", w, h);
    1511 
    1512  /* Workaround for FreeRDP issue #5417: in GFX AVC modes we can't go under
    1513  * AVC_MIN_DESKTOP_WIDTH x AVC_MIN_DESKTOP_HEIGHT */
    1514  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline) &&
    1515  freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
    1516  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) <
    1517  AVC_MIN_DESKTOP_WIDTH)
    1518  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth,
    1519  AVC_MIN_DESKTOP_WIDTH);
    1520  if (freerdp_settings_get_uint32(rfi->settings,
    1521  FreeRDP_DesktopHeight) <
    1522  AVC_MIN_DESKTOP_HEIGHT)
    1523  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight,
    1524  AVC_MIN_DESKTOP_HEIGHT);
    1525  }
    1526 
    1527  /* Workaround for FreeRDP issue #5119. This will make our horizontal resolution
    1528  * an even value, but it will add a vertical black 1 pixel line on the
    1529  * right of the desktop */
    1530  if ((freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) & 1) != 0) {
    1531  UINT32 tmp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    1532  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, tmp - 1);
    1533  }
    1534 
    1535  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
    1536  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    1537 
    1538  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
    1539  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
    1540  REMMINA_PLUGIN_DEBUG("Resolution set after workarounds: %dx%d", w, h);
    1541 
    1542 
    1543  if (remmina_plugin_service->file_get_string(remminafile, "username"))
    1544  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, remmina_plugin_service->file_get_string(remminafile, "username"));
    1545 
    1546  if (remmina_plugin_service->file_get_string(remminafile, "domain"))
    1547  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, remmina_plugin_service->file_get_string(remminafile, "domain"));
    1548 
    1549  s = remmina_plugin_service->file_get_string(remminafile, "password");
    1550  if (s) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s);
    1551 
    1552  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoLogonEnabled, TRUE);
    1553 
    1558  gchar *proxy_type = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_type"));
    1559  gchar *proxy_username = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_username"));
    1560  gchar *proxy_password = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_password"));
    1561  gchar *proxy_hostname = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_hostname"));
    1562  gint proxy_port = remmina_plugin_service->file_get_int(remminafile, "proxy_port", 80);
    1563  REMMINA_PLUGIN_DEBUG("proxy_type: %s", proxy_type);
    1564  REMMINA_PLUGIN_DEBUG("proxy_username: %s", proxy_username);
    1565  REMMINA_PLUGIN_DEBUG("proxy_password: %s", proxy_password);
    1566  REMMINA_PLUGIN_DEBUG("proxy_hostname: %s", proxy_hostname);
    1567  REMMINA_PLUGIN_DEBUG("proxy_port: %d", proxy_port);
    1568  if (proxy_type && proxy_hostname) {
    1569  if (g_strcmp0(proxy_type, "no_proxy") == 0)
    1570  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
    1571  else if (g_strcmp0(proxy_type, "http") == 0)
    1572  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP);
    1573  else if (g_strcmp0(proxy_type, "socks5") == 0)
    1574  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS);
    1575  else
    1576  g_warning("Invalid proxy protocol, at the moment only no_proxy, HTTP and SOCKS5 are supported");
    1577  REMMINA_PLUGIN_DEBUG("ProxyType set to: %" PRIu32, freerdp_settings_get_uint32(rfi->settings, FreeRDP_ProxyType));
    1578  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyHostname, proxy_hostname);
    1579  if (proxy_username)
    1580  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyUsername, proxy_username);
    1581  if (proxy_password)
    1582  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyPassword, proxy_password);
    1583  if (proxy_port)
    1584  freerdp_settings_set_uint16(rfi->settings, FreeRDP_ProxyPort, proxy_port);
    1585  }
    1586  g_free(proxy_hostname);
    1587  g_free(proxy_username);
    1588  g_free(proxy_password);
    1589 
    1590  if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)) {
    1591  // Reset gateway credentials
    1592  remmina_plugin_service->file_set_string(remminafile, "gateway_username", NULL);
    1593  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", NULL);
    1594  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
    1595  }
    1596 
    1597  /* Remote Desktop Gateway server address */
    1598  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, FALSE);
    1599  s = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
    1600  if (s) {
    1601  cs = remmina_plugin_service->file_get_string(remminafile, "gwtransp");
    1602 #if FREERDP_CHECK_VERSION(2, 3, 1)
    1603  if (remmina_plugin_service->file_get_int(remminafile, "websockets", FALSE))
    1604  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, TRUE);
    1605  else
    1606  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, FALSE);
    1607 #endif
    1608  if (g_strcmp0(cs, "http") == 0) {
    1609  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, FALSE);
    1610  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
    1611  } else if (g_strcmp0(cs, "rpc") == 0) {
    1612  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
    1613  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, FALSE);
    1614  } else if (g_strcmp0(cs, "auto") == 0) {
    1615  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
    1616  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
    1617  }
    1618  remmina_plugin_service->get_server_port(s, 443, &gateway_host, &gateway_port);
    1619  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayHostname, gateway_host);
    1620  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GatewayPort, gateway_port);
    1621  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, TRUE);
    1622  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, TRUE);
    1623  }
    1624  /* Remote Desktop Gateway domain */
    1625  if (remmina_plugin_service->file_get_string(remminafile, "gateway_domain")) {
    1626  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, remmina_plugin_service->file_get_string(remminafile, "gateway_domain"));
    1627  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1628  }
    1629  /* Remote Desktop Gateway username */
    1630  if (remmina_plugin_service->file_get_string(remminafile, "gateway_username")) {
    1631  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, remmina_plugin_service->file_get_string(remminafile, "gateway_username"));
    1632  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1633  }
    1634  /* Remote Desktop Gateway password */
    1635  s = remmina_plugin_service->file_get_string(remminafile, "gateway_password");
    1636  if (s) {
    1637  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s);
    1638  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    1639  }
    1640  /* If no different credentials were provided for the Remote Desktop Gateway
    1641  * use the same authentication credentials for the host */
    1642  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled) && freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials)) {
    1643  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, freerdp_settings_get_string(rfi->settings, FreeRDP_Domain));
    1644  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, freerdp_settings_get_string(rfi->settings, FreeRDP_Username));
    1645  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, freerdp_settings_get_string(rfi->settings, FreeRDP_Password));
    1646  }
    1647  /* Remote Desktop Gateway usage */
    1648  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled))
    1649  freerdp_set_gateway_usage_method(rfi->settings,
    1650  remmina_plugin_service->file_get_int(remminafile, "gateway_usage", FALSE) ? TSC_PROXY_MODE_DETECT : TSC_PROXY_MODE_DIRECT);
    1651 
    1652  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayAccessToken,
    1653  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
    1654 
    1655  freerdp_settings_set_uint32(rfi->settings, FreeRDP_AuthenticationLevel, remmina_plugin_service->file_get_int(
    1656  remminafile, "authentication level", freerdp_settings_get_uint32(rfi->settings, FreeRDP_AuthenticationLevel)));
    1657 
    1658  /* Certificate ignore */
    1659  freerdp_settings_set_bool(rfi->settings, FreeRDP_IgnoreCertificate, remmina_plugin_service->file_get_int(remminafile, "cert_ignore", 0));
    1660  freerdp_settings_set_bool(rfi->settings, FreeRDP_OldLicenseBehaviour, remmina_plugin_service->file_get_int(remminafile, "old-license", 0));
    1661  freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowUnanouncedOrdersFromServer, remmina_plugin_service->file_get_int(remminafile, "relax-order-checks", 0));
    1662  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GlyphSupportLevel, (remmina_plugin_service->file_get_int(remminafile, "glyph-cache", 0) ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE));
    1663 
    1664  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientname")))
    1665  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, cs);
    1666  else
    1667  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, g_get_host_name());
    1668 
    1669  /* Client Build number is optional, if not specified defaults to 0, allow for comments to appear after number */
    1670  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientbuild"))) {
    1671  if (*cs) {
    1672  UINT32 val = strtoul(cs, NULL, 0);
    1673  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ClientBuild, val);
    1674  }
    1675  }
    1676 
    1677 
    1678  if (remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo")) {
    1679  char *tmp = strdup(remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo"));
    1680  rfi->settings->LoadBalanceInfo = (BYTE *)tmp;
    1681 
    1682  freerdp_settings_set_uint32(rfi->settings, FreeRDP_LoadBalanceInfoLength, strlen(tmp));
    1683  }
    1684 
    1685  if (remmina_plugin_service->file_get_string(remminafile, "exec"))
    1686  freerdp_settings_set_string(rfi->settings, FreeRDP_AlternateShell, remmina_plugin_service->file_get_string(remminafile, "exec"));
    1687 
    1688  if (remmina_plugin_service->file_get_string(remminafile, "execpath"))
    1689  freerdp_settings_set_string(rfi->settings, FreeRDP_ShellWorkingDirectory, remmina_plugin_service->file_get_string(remminafile, "execpath"));
    1690 
    1691  sm = g_strdup_printf("rdp_quality_%i", remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0));
    1692  value = remmina_plugin_service->pref_get_value(sm);
    1693  g_free(sm);
    1694 
    1695  if (value && value[0]) {
    1696  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, strtoul(value, NULL, 16));
    1697  } else {
    1698  switch (remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0)) {
    1699  case 9:
    1700  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_9);
    1701  break;
    1702 
    1703  case 2:
    1704  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_2);
    1705  break;
    1706 
    1707  case 1:
    1708  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_1);
    1709  break;
    1710 
    1711  case 0:
    1712  default:
    1713  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_0);
    1714  break;
    1715  }
    1716  }
    1717  g_free(value);
    1718 
    1719  if ((cs = remmina_plugin_service->file_get_string(remminafile, "network"))) {
    1720  guint32 type = 0;
    1721 
    1722  if (g_strcmp0(cs, "modem") == 0)
    1723  type = CONNECTION_TYPE_MODEM;
    1724  else if (g_strcmp0(cs, "broadband") == 0)
    1725  type = CONNECTION_TYPE_BROADBAND_HIGH;
    1726  else if (g_strcmp0(cs, "broadband-low") == 0)
    1727  type = CONNECTION_TYPE_BROADBAND_LOW;
    1728  else if (g_strcmp0(cs, "broadband-high") == 0)
    1729  type = CONNECTION_TYPE_BROADBAND_HIGH;
    1730  else if (g_strcmp0(cs, "wan") == 0)
    1731  type = CONNECTION_TYPE_WAN;
    1732  else if (g_strcmp0(cs, "lan") == 0)
    1733  type = CONNECTION_TYPE_LAN;
    1734  else if ((g_strcmp0(cs, "autodetect") == 0))
    1735  type = CONNECTION_TYPE_AUTODETECT;
    1736  else if ((g_strcmp0(cs, "none") == 0))
    1737  type = REMMINA_CONNECTION_TYPE_NONE;
    1738  else
    1739  type = REMMINA_CONNECTION_TYPE_NONE;
    1740 
    1741  if (!remmina_rdp_set_connection_type(rfi->settings, type))
    1742  REMMINA_PLUGIN_DEBUG("Network settings not set");
    1743  }
    1744 
    1745  /* PerformanceFlags bitmask need also to be splitted into BOOL variables
    1746  * like freerdp_settings_set_bool(rfi->settings, FreeRDP_DisableWallpaper, freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowFontSmoothing…
    1747  * or freerdp_get_param_bool() function will return the wrong value
    1748  */
    1749  freerdp_performance_flags_split(rfi->settings);
    1750 
    1751 #ifdef GDK_WINDOWING_X11
    1752 #if FREERDP_CHECK_VERSION(2, 3, 0)
    1753  rdp_kbd_remap = remmina_get_rdp_kbd_remap(remmina_plugin_service->file_get_string(remminafile, "keymap"));
    1754  if (rdp_kbd_remap != NULL) {
    1755  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, rdp_kbd_remap);
    1756  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
    1757  g_free(rdp_kbd_remap);
    1758  }
    1759  else {
    1760  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, remmina_plugin_service->pref_get_value("rdp_kbd_remap"));
    1761  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
    1762  }
    1763 #endif
    1764 #endif
    1765 
    1766  freerdp_settings_set_uint32(rfi->settings, FreeRDP_KeyboardLayout, remmina_rdp_settings_get_keyboard_layout());
    1767 
    1768  if (remmina_plugin_service->file_get_int(remminafile, "console", FALSE))
    1769  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1770 
    1771  if (remmina_plugin_service->file_get_int(remminafile, "restricted-admin", FALSE)) {
    1772  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1773  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
    1774  }
    1775 
    1776  if (remmina_plugin_service->file_get_string(remminafile, "pth")) {
    1777  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
    1778  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
    1779  freerdp_settings_set_string(rfi->settings, FreeRDP_PasswordHash, remmina_plugin_service->file_get_string(remminafile, "pth"));
    1780  remmina_plugin_service->file_set_int(remminafile, "restricted-admin", TRUE);
    1781  }
    1782 
    1783  cs = remmina_plugin_service->file_get_string(remminafile, "security");
    1784  if (g_strcmp0(cs, "rdp") == 0) {
    1785  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, TRUE);
    1786  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1787  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1788  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1789  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseRdpSecurityLayer, TRUE);
    1790  } else if (g_strcmp0(cs, "tls") == 0) {
    1791  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1792  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, TRUE);
    1793  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1794  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1795  } else if (g_strcmp0(cs, "nla") == 0) {
    1796  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1797  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1798  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, TRUE);
    1799  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
    1800  } else if (g_strcmp0(cs, "ext") == 0) {
    1801  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
    1802  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
    1803  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
    1804  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, TRUE);
    1805  } else {
    1806  /* This is "-nego" switch of xfreerdp */
    1807  freerdp_settings_set_bool(rfi->settings, FreeRDP_NegotiateSecurityLayer, TRUE);
    1808  }
    1809 
    1810  cs = remmina_plugin_service->file_get_string(remminafile, "tls-seclevel");
    1811  if (cs && g_strcmp0(cs,"")!=0) {
    1812  i = atoi(cs);
    1813  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TlsSecLevel, i);
    1814  }
    1815 
    1816  freerdp_settings_set_bool(rfi->settings, FreeRDP_CompressionEnabled, TRUE);
    1817  if (remmina_plugin_service->file_get_int(remminafile, "disable_fastpath", FALSE)) {
    1818  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, FALSE);
    1819  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, FALSE);
    1820  } else {
    1821  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, TRUE);
    1822  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
    1823  }
    1824 
    1825  /* Orientation and scaling settings */
    1826  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
    1827 
    1828  freerdp_settings_set_uint16(rfi->settings, FreeRDP_DesktopOrientation, desktopOrientation);
    1829  if (desktopScaleFactor != 0 && deviceScaleFactor != 0) {
    1830  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopScaleFactor, desktopScaleFactor);
    1831  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DeviceScaleFactor, deviceScaleFactor);
    1832  }
    1833 
    1834  /* Try to enable "Display Control Virtual Channel Extension", needed to
    1835  * dynamically resize remote desktop. This will automatically open
    1836  * the "disp" dynamic channel, if available */
    1837  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportDisplayControl, TRUE);
    1838 
    1839  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportDisplayControl)) {
    1840  CLPARAM *d[1];
    1841  int dcount;
    1842 
    1843  dcount = 1;
    1844  d[0] = "disp";
    1845  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
    1846  }
    1847 
    1848  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
    1849  CLPARAM *d[1];
    1850 
    1851  int dcount;
    1852 
    1853  dcount = 1;
    1854  d[0] = "rdpgfx";
    1855  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
    1856  }
    1857 
    1858  /* Sound settings */
    1859  cs = remmina_plugin_service->file_get_string(remminafile, "sound");
    1860  if (g_strcmp0(cs, "remote") == 0) {
    1861  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, TRUE);
    1862  } else if (g_str_has_prefix(cs, "local")) {
    1863  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, TRUE);
    1864  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
    1865  } else {
    1866  /* Disable sound */
    1867  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, FALSE);
    1868  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, FALSE);
    1869  }
    1870 
    1871  cs = remmina_plugin_service->file_get_string(remminafile, "microphone");
    1872  if (cs != NULL && cs[0] != '\0') {
    1873  if (g_strcmp0(cs, "0") == 0) {
    1874  REMMINA_PLUGIN_DEBUG("“microphone” was set to 0, setting to \"\"");
    1875  remmina_plugin_service->file_set_string(remminafile, "microphone", "");
    1876  } else {
    1877  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
    1878  REMMINA_PLUGIN_DEBUG("“microphone” set to “%s”", cs);
    1879  CLPARAM **p;
    1880  size_t count;
    1881 
    1882  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("audin", g_strdup(cs), &count);
    1883 
    1884  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1885  g_free(p);
    1886  }
    1887  }
    1888 
    1889  cs = remmina_plugin_service->file_get_string(remminafile, "audio-output");
    1890  if (cs != NULL && cs[0] != '\0') {
    1891  REMMINA_PLUGIN_DEBUG("audio output set to %s", cs);
    1892  CLPARAM **p;
    1893  size_t count;
    1894 
    1895  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("rdpsnd", g_strdup(cs), &count);
    1896  status = freerdp_client_add_static_channel(rfi->settings, count, p);
    1897  if (status)
    1898  status = freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1899  g_free(p);
    1900  }
    1901 
    1902 
    1903  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_level");
    1904  if (cs != NULL && cs[0] != '\0')
    1905  REMMINA_PLUGIN_DEBUG("Log level set to to %s", cs);
    1906  else
    1907  cs = g_strdup("INFO");
    1908  wLog *root = WLog_GetRoot();
    1909  WLog_SetStringLogLevel(root, cs);
    1910 
    1911  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_filters");
    1912  if (cs != NULL && cs[0] != '\0') {
    1913  REMMINA_PLUGIN_DEBUG("Log filters set to to %s", cs);
    1914  WLog_AddStringLogFilters(cs);
    1915  } else {
    1916  WLog_AddStringLogFilters(NULL);
    1917  }
    1918 
    1919 
    1920  cs = remmina_plugin_service->file_get_string(remminafile, "usb");
    1921  if (cs != NULL && cs[0] != '\0') {
    1922  CLPARAM **p;
    1923  size_t count;
    1924  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("urbdrc", g_strdup(cs), &count);
    1925  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1926  g_free(p);
    1927  }
    1928 
    1929  cs = remmina_plugin_service->file_get_string(remminafile, "vc");
    1930  if (cs != NULL && cs[0] != '\0') {
    1931  CLPARAM **p;
    1932  size_t count;
    1933  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
    1934  freerdp_client_add_static_channel(rfi->settings, count, p);
    1935  g_free(p);
    1936  }
    1937 
    1938  cs = remmina_plugin_service->file_get_string(remminafile, "dvc");
    1939  if (cs != NULL && cs[0] != '\0') {
    1940  CLPARAM **p;
    1941  size_t count;
    1942  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
    1943  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
    1944  g_free(p);
    1945  }
    1946 
    1947  cs = remmina_plugin_service->file_get_string(remminafile, "rdp2tcp");
    1948  if (cs != NULL && cs[0] != '\0') {
    1949  g_free(rfi->settings->RDP2TCPArgs);
    1950  rfi->settings->RDP2TCPArgs = g_strdup(cs);
    1951  REMMINA_PLUGIN_DEBUG("rdp2tcp set to %s", rfi->settings->RDP2TCPArgs);
    1952  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdp2tcp", rfi->settings->RDP2TCPArgs);
    1953  }
    1954 
    1955  int vermaj, vermin, verrev;
    1956  freerdp_get_version(&vermaj, &vermin, &verrev);
    1957 
    1958 #if FREERDP_CHECK_VERSION(2, 1, 0)
    1959  cs = remmina_plugin_service->file_get_string(remminafile, "timeout");
    1960  if (cs != NULL && cs[0] != '\0') {
    1961  const gchar *endptr = NULL;
    1962  guint64 val = g_ascii_strtoull(cs, (gchar **)&endptr, 10);
    1963  if (val > 600000 || val <= 0)
    1964  val = 600000;
    1965  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TcpAckTimeout, (UINT32)val);
    1966  }
    1967 #endif
    1968 
    1969  if (remmina_plugin_service->file_get_int(remminafile, "preferipv6", FALSE) ? TRUE : FALSE)
    1970  freerdp_settings_set_bool(rfi->settings, FreeRDP_PreferIPv6OverIPv4, TRUE);
    1971 
    1972  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectClipboard, remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE) ? FALSE : TRUE);
    1973 
    1974  cs = remmina_plugin_service->file_get_string(remminafile, "sharefolder");
    1975  if (cs != NULL && cs[0] != '\0') {
    1976  gchar *ccs = g_strdup(cs);
    1977  REMMINA_PLUGIN_DEBUG("[Deprecated->migrating] - Old sharefolder %s to \"drive \"", ccs);
    1978  if (!remmina_plugin_service->file_get_string(remminafile, "drive")) {
    1979  remmina_plugin_service->file_set_string(remminafile, "drive", g_strdup(ccs));
    1980  remmina_plugin_service->file_set_string(remminafile, "sharefolder", NULL);
    1981  REMMINA_PLUGIN_DEBUG("[Deprecated->migrated] - drive set to %s", g_strdup(ccs));
    1982  }
    1983  g_free(ccs);
    1984  //CLPARAM **p;
    1985  //size_t count;
    1986  //p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(cs), &count);
    1987  //status = freerdp_client_add_device_channel(rfi->settings, count, p);
    1988  //g_free(p);
    1989  }
    1990  cs = remmina_plugin_service->file_get_string(remminafile, "drive");
    1991  if (cs != NULL && cs[0] != '\0') {
    1992  REMMINA_PLUGIN_DEBUG("Redirect directory set to %s", cs);
    1993  CLPARAM **p;
    1994  size_t count;
    1995 
    1996  gchar **folders = g_strsplit(cs, ";", -1);
    1997  for (i = 0; folders[i] != NULL; i++) {
    1998  REMMINA_PLUGIN_DEBUG("Parsing folder %s", folders[i]);
    1999  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(folders[i]), &count);
    2000  status = freerdp_client_add_device_channel(rfi->settings, count, p);
    2001  g_free(p);
    2002  }
    2003  g_strfreev(folders);
    2004  }
    2005 
    2006  if (remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE)) {
    2007 #ifdef HAVE_CUPS
    2008  REMMINA_PLUGIN_DEBUG("Sharing printers");
    2009  const gchar *po = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
    2010  if (po && po[0] != 0) {
    2011  /* Fallback to remmina code to override print drivers */
    2012  if (cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, remmina_rdp_set_printers, rfi))
    2013  REMMINA_PLUGIN_DEBUG("All printers have been shared");
    2014  else
    2015  REMMINA_PLUGIN_DEBUG("Cannot share printers, are there any available?");
    2016  } else {
    2017  /* Use libfreerdp code to map all printers */
    2018  CLPARAM *d[1];
    2019  int dcount;
    2020  dcount = 1;
    2021  d[0] = "printer";
    2022  freerdp_client_add_device_channel(rfi->settings, dcount, d);
    2023  }
    2024 #endif /* HAVE_CUPS */
    2025  }
    2026 
    2027  if (remmina_plugin_service->file_get_int(remminafile, "span", FALSE)) {
    2028  freerdp_settings_set_bool(rfi->settings, FreeRDP_SpanMonitors, TRUE);
    2029  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2030  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2031  remmina_plugin_service->file_set_int(remminafile, "multimon", 1);
    2032  }
    2033 
    2034  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    2035  guint32 maxwidth = 0;
    2036  guint32 maxheight = 0;
    2037  gchar *monitorids;
    2038  guint32 i;
    2039  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2040  /* TODO Add an option for this */
    2041  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    2042  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2043 
    2044  gchar *monitorids_string = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids"));
    2045  /* Otherwise we get all the attached monitors
    2046  * monitorids may contains desktop orientation values.
    2047  * But before we check if there are orientation attributes
    2048  */
    2049  if (monitorids_string != NULL && monitorids_string[0] != '\0') {
    2050  if (g_strstr_len(monitorids_string, -1, ",") != NULL) {
    2051  if (g_strstr_len(monitorids_string, -1, ":") != NULL) {
    2052  rdpMonitor *base = (rdpMonitor *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
    2053  /* We have an ID and an orientation degree */
    2054  gchar **temp_items;
    2055  gchar **rot_items;
    2056  temp_items = g_strsplit(monitorids_string, ",", -1);
    2057  for (i = 0; i < g_strv_length(temp_items); i++) {
    2058  rot_items = g_strsplit(temp_items[i], ":", -1);
    2059  rdpMonitor *current = &base[atoi(rot_items[0])];
    2060  if (i == 0)
    2061  monitorids = g_strdup(rot_items[0]);
    2062  else
    2063  monitorids = g_strdup_printf("%s,%s", monitorids, rot_items[0]);
    2064  current->attributes.orientation = atoi(rot_items[1]);
    2065  REMMINA_PLUGIN_DEBUG("Monitor n %d orientation: %d", i, current->attributes.orientation);
    2066  }
    2067  } else {
    2068  monitorids = g_strdup(monitorids_string);
    2069  }
    2070  } else {
    2071  monitorids = g_strdup(monitorids_string);
    2072  }
    2073  } else {
    2074  monitorids = g_strdup(monitorids_string);
    2075  }
    2076  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
    2077  if (monitorids != NULL && monitorids[0] != '\0') {
    2078  UINT32 *base = (UINT32 *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorIds);
    2079  gchar **items;
    2080  items = g_strsplit(monitorids, ",", -1);
    2081  freerdp_settings_set_uint32(rfi->settings, FreeRDP_NumMonitorIds, g_strv_length(items));
    2082  REMMINA_PLUGIN_DEBUG("NumMonitorIds: %d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_NumMonitorIds));
    2083  for (i = 0; i < g_strv_length(items); i++) {
    2084  UINT32 *current = &base[i];
    2085  *current = atoi(items[i]);
    2086  REMMINA_PLUGIN_DEBUG("Added monitor with ID %" PRIu32, *current);
    2087  }
    2088  g_free(monitorids);
    2089  g_strfreev(items);
    2090  }
    2091  if (maxwidth && maxheight) {
    2092  REMMINA_PLUGIN_DEBUG("Setting DesktopWidth and DesktopHeight to: %dx%d", maxwidth, maxheight);
    2093  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, maxwidth);
    2094  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, maxheight);
    2095  REMMINA_PLUGIN_DEBUG("DesktopWidth and DesktopHeight set to: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2096  } else {
    2097  REMMINA_PLUGIN_DEBUG("Cannot set Desktop Size, we are using the previously set values: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2098  }
    2099  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
    2100  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
    2101  }
    2102 
    2103  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "smartcardname");
    2104  if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE) ||
    2105  (sn != NULL && sn[0] != '\0')) {
    2106  RDPDR_SMARTCARD *smartcard;
    2107  smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD));
    2108 
    2109 #ifdef WITH_FREERDP3
    2110  RDPDR_DEVICE *sdev;
    2111  sdev = &(smartcard->device);
    2112 #else
    2113  RDPDR_SMARTCARD *sdev;
    2114  sdev = smartcard;
    2115 #endif
    2116 
    2117  sdev->Type = RDPDR_DTYP_SMARTCARD;
    2118 
    2119  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2120 
    2121  if (sn != NULL && sn[0] != '\0')
    2122  sdev->Name = _strdup(sn);
    2123 
    2124  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSmartCards, TRUE);
    2125 
    2126  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)smartcard);
    2127  }
    2128 
    2129  if (remmina_plugin_service->file_get_int(remminafile, "passwordispin", FALSE))
    2130  /* Option works only combined with Username and Domain, because FreeRDP
    2131  * doesn’t know anything about info on smart card */
    2132  freerdp_settings_set_bool(rfi->settings, FreeRDP_PasswordIsSmartcardPin, TRUE);
    2133 
    2134  /* /serial[:<name>[,<path>[,<driver>[,permissive]]]] */
    2135  if (remmina_plugin_service->file_get_int(remminafile, "shareserial", FALSE)) {
    2136  RDPDR_SERIAL *serial;
    2137  serial = (RDPDR_SERIAL *)calloc(1, sizeof(RDPDR_SERIAL));
    2138 
    2139 #ifdef WITH_FREERDP3
    2140  RDPDR_DEVICE *sdev;
    2141  sdev = &(serial->device);
    2142 #else
    2143  RDPDR_SERIAL *sdev;
    2144  sdev = serial;
    2145 #endif
    2146 
    2147  sdev->Type = RDPDR_DTYP_SERIAL;
    2148 
    2149  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2150 
    2151  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "serialname");
    2152  if (sn != NULL && sn[0] != '\0')
    2153  sdev->Name = _strdup(sn);
    2154 
    2155  const gchar *sd = remmina_plugin_service->file_get_string(remminafile, "serialdriver");
    2156  if (sd != NULL && sd[0] != '\0')
    2157  serial->Driver = _strdup(sd);
    2158 
    2159  const gchar *sp = remmina_plugin_service->file_get_string(remminafile, "serialpath");
    2160  if (sp != NULL && sp[0] != '\0')
    2161  serial->Path = _strdup(sp);
    2162 
    2163  if (remmina_plugin_service->file_get_int(remminafile, "serialpermissive", FALSE))
    2164  serial->Permissive = _strdup("permissive");
    2165 
    2166  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSerialPorts, TRUE);
    2167 
    2168  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)serial);
    2169  }
    2170 
    2171  if (remmina_plugin_service->file_get_int(remminafile, "shareparallel", FALSE)) {
    2172  RDPDR_PARALLEL *parallel;
    2173  parallel = (RDPDR_PARALLEL *)calloc(1, sizeof(RDPDR_PARALLEL));
    2174 
    2175 #ifdef WITH_FREERDP3
    2176  RDPDR_DEVICE *pdev;
    2177  pdev = &(parallel->device);
    2178 #else
    2179  RDPDR_PARALLEL *pdev;
    2180  pdev = parallel;
    2181 #endif
    2182 
    2183  pdev->Type = RDPDR_DTYP_PARALLEL;
    2184 
    2185  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2186 
    2187  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectParallelPorts, TRUE);
    2188 
    2189  const gchar *pn = remmina_plugin_service->file_get_string(remminafile, "parallelname");
    2190  if (pn != NULL && pn[0] != '\0')
    2191  pdev->Name = _strdup(pn);
    2192  const gchar *dp = remmina_plugin_service->file_get_string(remminafile, "parallelpath");
    2193  if (dp != NULL && dp[0] != '\0')
    2194  parallel->Path = _strdup(dp);
    2195 
    2196  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel);
    2197  }
    2198 
    2202  if (remmina_plugin_service->file_get_int(remminafile, "multitransport", FALSE)) {
    2203  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
    2204  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportMultitransport, TRUE);
    2205  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags,
    2206  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED));
    2207  } else {
    2208  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags, 0);
    2209  }
    2210 
    2211  /* If needed, force interactive authentication by deleting all authentication fields,
    2212  * forcing libfreerdp to call our callbacks for authentication.
    2213  * This usually happens from a second attempt of connection, never on the 1st one. */
    2215  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, NULL);
    2216  freerdp_settings_set_string(rfi->settings, FreeRDP_Password, NULL);
    2217  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, NULL);
    2218 
    2219  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, NULL);
    2220  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, NULL);
    2221  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, NULL);
    2222 
    2223  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
    2224  }
    2225 
    2226  gboolean orphaned;
    2227 
    2228  if (!freerdp_connect(rfi->instance)) {
    2229  orphaned = (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL);
    2230  if (!orphaned) {
    2231  UINT32 e;
    2232 
    2233  e = freerdp_get_last_error(rfi->instance->context);
    2234 
    2235  switch (e) {
    2236  case FREERDP_ERROR_AUTHENTICATION_FAILED:
    2237  case STATUS_LOGON_FAILURE: // wrong return code from FreeRDP introduced at the end of July 2016? (fixed with b86c0ba)
    2238 #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
    2239  case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
    2240 #endif
    2241  /* Logon failure, will retry with interactive authentication */
    2243  break;
    2244  case STATUS_ACCOUNT_LOCKED_OUT:
    2245 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
    2246  case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
    2247 #endif
    2248  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount locked out."),
    2249  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2250  break;
    2251  case STATUS_ACCOUNT_EXPIRED:
    2252 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
    2253  case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
    2254 #endif
    2255  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount expired."),
    2256  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2257  break;
    2258  case STATUS_PASSWORD_EXPIRED:
    2259 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED
    2260  case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
    2261 #endif
    2262  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nPassword expired."),
    2263  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2264  break;
    2265  case STATUS_ACCOUNT_DISABLED:
    2266 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
    2267  case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
    2268 #endif
    2269  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount disabled."),
    2270  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2271  break;
    2272 #ifdef FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES
    2273  /* https://msdn.microsoft.com/en-us/library/ee392247.aspx */
    2274  case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
    2275  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nInsufficient user privileges."),
    2276  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2277  break;
    2278 #endif
    2279  case STATUS_ACCOUNT_RESTRICTION:
    2280 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
    2281  case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
    2282 #endif
    2283  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount restricted."),
    2284  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2285  break;
    2286 
    2287  case STATUS_PASSWORD_MUST_CHANGE:
    2288 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
    2289  case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
    2290 #endif
    2291  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nChange user password before connecting."),
    2292  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2293  break;
    2294 
    2295  case FREERDP_ERROR_CONNECT_FAILED:
    2296  remmina_plugin_service->protocol_plugin_set_error(gp, _("Lost connection to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2297  break;
    2298  case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
    2299  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not find the address for the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2300  break;
    2301  case FREERDP_ERROR_TLS_CONNECT_FAILED:
    2302  remmina_plugin_service->protocol_plugin_set_error(gp,
    2303  _("Could not connect to the RDP server “%s” via TLS. See the DEBUG traces from a terminal for more information."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2304  break;
    2305  case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
    2306  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
    2307  remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to establish a connection to the RDP server “%s”. Check “Security protocol negotiation”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2308  break;
    2309 #ifdef FREERDP_ERROR_POST_CONNECT_FAILED
    2310  case FREERDP_ERROR_POST_CONNECT_FAILED:
    2311  /* remmina_rdp_post_connect() returned FALSE to libfreerdp. We saved the error on rfi->postconnect_error */
    2312  switch (rfi->postconnect_error) {
    2313  case REMMINA_POSTCONNECT_ERROR_OK:
    2314  /* We should never come here */
    2315  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2316  break;
    2317  case REMMINA_POSTCONNECT_ERROR_GDI_INIT:
    2318  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not start libfreerdp-gdi."));
    2319  break;
    2320  case REMMINA_POSTCONNECT_ERROR_NO_H264:
    2321  remmina_plugin_service->protocol_plugin_set_error(gp, _("You requested a H.264 GFX mode for the server “%s”, but your libfreerdp does not support H.264. Please use a non-AVC colour depth setting."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2322  break;
    2323  }
    2324  break;
    2325 #endif
    2326 #ifdef FREERDP_ERROR_SERVER_DENIED_CONNECTION
    2327  case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
    2328  remmina_plugin_service->protocol_plugin_set_error(gp, _("The “%s” server refused the connection."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2329  break;
    2330 #endif
    2331  case 0x800759DB:
    2332  // E_PROXY_NAP_ACCESSDENIED https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/84cd92e4-592c-4219-95d8-18021ac654b0
    2333  remmina_plugin_service->protocol_plugin_set_error(gp, _("The Remote Desktop Gateway “%s” denied the user “%s\\%s” access due to policy."),
    2334  freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayHostname), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayDomain), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayUsername));
    2335  break;
    2336 
    2337  case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
    2338  rfi->user_cancelled = TRUE;
    2339  break;
    2340 
    2341  default:
    2342  g_printf("libfreerdp returned code is %08X\n", e);
    2343  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the “%s” RDP server."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
    2344  break;
    2345  }
    2346  }
    2347 
    2348  return FALSE;
    2349  }
    2350 
    2351  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = true; else orphaned = false;
    2352  if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled)
    2354 
    2355  return TRUE;
    2356 }
    2357 
    2358 static void rfi_uninit(rfContext *rfi)
    2359 {
    2360  freerdp *instance;
    2361 
    2362  instance = rfi->instance;
    2363 
    2364  if (rfi->remmina_plugin_thread) {
    2365  rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run
    2366  pthread_cancel(rfi->remmina_plugin_thread);
    2367  if (rfi->remmina_plugin_thread)
    2368  pthread_join(rfi->remmina_plugin_thread, NULL);
    2369  }
    2370 
    2371  if (instance) {
    2372  if (rfi->connected) {
    2373  freerdp_abort_connect(instance);
    2374  rfi->connected = false;
    2375  }
    2376  }
    2377 
    2378  if (instance) {
    2379  RDP_CLIENT_ENTRY_POINTS *pEntryPoints = instance->pClientEntryPoints;
    2380  if (pEntryPoints)
    2381  IFCALL(pEntryPoints->GlobalUninit);
    2382  free(instance->pClientEntryPoints);
    2383  freerdp_context_free(instance); /* context is rfContext* rfi */
    2384  freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */
    2385  }
    2386 }
    2387 
    2388 static gboolean complete_cleanup_on_main_thread(gpointer data)
    2389 {
    2390  TRACE_CALL(__func__);
    2391 
    2392  gboolean orphaned;
    2393  rfContext *rfi = (rfContext *)data;
    2395 
    2397 
    2398  gdi_free(rfi->instance);
    2399 
    2400  gp = rfi->protocol_widget;
    2401  if (GET_PLUGIN_DATA(gp) == NULL) orphaned = true; else orphaned = false;
    2402 
    2404  if (!orphaned) remmina_rdp_event_uninit(gp);
    2405 
    2406  if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data");
    2407 
    2408  rfi_uninit(rfi);
    2409 
    2410  /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface
    2411  * can be removed */
    2412  if (!orphaned)
    2413  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
    2414 
    2415  return G_SOURCE_REMOVE;
    2416 }
    2417 
    2418 static gpointer remmina_rdp_main_thread(gpointer data)
    2419 {
    2420  TRACE_CALL(__func__);
    2422  rfContext *rfi;
    2423 
    2424  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    2425  CANCEL_ASYNC
    2426 
    2427  gp = (RemminaProtocolWidget *)data;
    2428 
    2429  rfi = GET_PLUGIN_DATA(gp);
    2430 
    2432  do
    2433  remmina_rdp_main(gp);
    2434  while (!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled);
    2435 
    2436  rfi->remmina_plugin_thread = 0;
    2437 
    2438  /* cleanup */
    2439  g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi);
    2440 
    2441 
    2442  return NULL;
    2443 }
    2444 
    2446 {
    2447  TRACE_CALL(__func__);
    2448  freerdp *instance;
    2449  rfContext *rfi;
    2450 
    2451  instance = freerdp_new();
    2452  instance->PreConnect = remmina_rdp_pre_connect;
    2453  instance->PostConnect = remmina_rdp_post_connect;
    2454  instance->PostDisconnect = remmina_rdp_post_disconnect;
    2455  instance->Authenticate = remmina_rdp_authenticate;
    2456  instance->GatewayAuthenticate = remmina_rdp_gw_authenticate;
    2457  //instance->VerifyCertificate = remmina_rdp_verify_certificate;
    2458  instance->VerifyCertificateEx = remmina_rdp_verify_certificate_ex;
    2459  //instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate;
    2460  instance->VerifyChangedCertificateEx = remmina_rdp_verify_changed_certificate_ex;
    2461 
    2462  instance->ContextSize = sizeof(rfContext);
    2463  freerdp_context_new(instance);
    2464  rfi = (rfContext *)instance->context;
    2465 
    2466  g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free);
    2467 
    2468  rfi->protocol_widget = gp;
    2469  rfi->instance = instance;
    2470  rfi->settings = instance->settings;
    2471  rfi->connected = false;
    2472  rfi->is_reconnecting = false;
    2473  rfi->stop_reconnecting_requested = false;
    2474  rfi->user_cancelled = FALSE;
    2475  rfi->last_x = 0;
    2476  rfi->last_y = 0;
    2477 
    2478  freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
    2479 
    2481 }
    2482 
    2484 {
    2485  TRACE_CALL(__func__);
    2486  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2487  RemminaFile *remminafile;
    2488  const gchar *profile_name, *p;
    2489  gchar thname[16], c;
    2490  gint nthname = 0;
    2491 
    2492  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
    2493 
    2494  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    2495 
    2496 
    2497  if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) {
    2498  remmina_plugin_service->protocol_plugin_set_error(gp, "%s",
    2499  "Could not start pthread.");
    2500 
    2501  rfi->remmina_plugin_thread = 0;
    2502 
    2503  return FALSE;
    2504  }
    2505 
    2506  /* Generate a thread name to be used with pthread_setname_np() for debugging */
    2507  profile_name = remmina_plugin_service->file_get_string(remminafile, "name");
    2508  p = profile_name;
    2509  strcpy(thname, "RemmRDP:");
    2510  if (p) {
    2511  nthname = strlen(thname);
    2512  while ((c = *p) != 0 && nthname < sizeof(thname) - 1) {
    2513  if (isalnum(c))
    2514  thname[nthname++] = c;
    2515  p++;
    2516  }
    2517  } else {
    2518  strcat(thname, "<NONAM>");
    2519  nthname = strlen(thname);
    2520  }
    2521  thname[nthname] = 0;
    2522 #if defined(__linux__)
    2523  pthread_setname_np(rfi->remmina_plugin_thread, thname);
    2524 #elif defined(__FreeBSD__)
    2525  pthread_set_name_np(rfi->remmina_plugin_thread, thname);
    2526 #endif
    2527 
    2528  return TRUE;
    2529 }
    2530 
    2532 {
    2533  TRACE_CALL(__func__);
    2534 
    2535  REMMINA_PLUGIN_DEBUG("Requesting to close the connection");
    2536  RemminaPluginRdpEvent rdp_event = { 0 };
    2537  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2538 
    2539  if (!remmina_plugin_service->is_main_thread())
    2540  g_warning("WARNING: %s called on a subthread, which may not work or crash Remmina.", __func__);
    2541 
    2542  if (rfi && !rfi->connected) {
    2543  /* libfreerdp is attempting to connect, we cannot interrupt our main thread
    2544  * in the connect phase.
    2545  * So we remove "plugin-data" from gp, so our rfi remains "orphan"
    2546  */
    2548  g_object_steal_data(G_OBJECT(gp), "plugin-data");
    2549  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
    2550  return FALSE;
    2551  }
    2552 
    2553 
    2554  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
    2555  REMMINA_PLUGIN_DEBUG("[RDP] requesting clipboard transfer to abort");
    2556  /* Allow clipboard transfer from server to terminate */
    2557  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
    2558  usleep(100000);
    2559  }
    2560 
    2561  if (rfi->is_reconnecting) {
    2562  /* Special case: window closed when attempting to reconnect */
    2563  rfi->stop_reconnecting_requested = TRUE;
    2564  return FALSE;
    2565  }
    2566 
    2567  rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT;
    2568  remmina_rdp_event_event_push(gp, &rdp_event);
    2569 
    2570  return FALSE;
    2571 }
    2572 
    2574 {
    2575  TRACE_CALL(__func__);
    2576  return TRUE;
    2577 }
    2578 
    2580 {
    2581  TRACE_CALL(__func__);
    2582  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2583 
    2584  switch (feature->id) {
    2585  case REMMINA_RDP_FEATURE_UNFOCUS:
    2587  break;
    2588 
    2589  case REMMINA_RDP_FEATURE_SCALE:
    2590  if (rfi) {
    2591  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
    2593  } else {
    2594  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_SCALE");
    2595  }
    2596  break;
    2597 
    2598  case REMMINA_RDP_FEATURE_MULTIMON:
    2599  if (rfi) {
    2600  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
    2601  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
    2602  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
    2603  /* TODO Add an option for this */
    2604  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
    2605  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
    2607  }
    2608  } else {
    2609  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_MULTIMON");
    2610  }
    2611  break;
    2612 
    2613  case REMMINA_RDP_FEATURE_DYNRESUPDATE:
    2614  break;
    2615 
    2616  case REMMINA_RDP_FEATURE_TOOL_REFRESH:
    2617  if (rfi)
    2618  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0,
    2619  remmina_plugin_service->protocol_plugin_get_width(gp),
    2620  remmina_plugin_service->protocol_plugin_get_height(gp));
    2621  else
    2622  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_TOOL_REFRESH");
    2623  break;
    2624 
    2625  case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL:
    2627  break;
    2628 
    2629  default:
    2630  break;
    2631  }
    2632 }
    2633 
    2634 /* Send a keystroke to the plugin window */
    2635 static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    2636 {
    2637  TRACE_CALL(__func__);
    2638  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2639 
    2640  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
    2641  keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
    2642  return;
    2643 }
    2644 
    2646 {
    2647  rfContext *rfi = GET_PLUGIN_DATA(gp);
    2648  rdpGdi *gdi;
    2649  size_t szmem;
    2650 
    2651  UINT32 bytesPerPixel;
    2652  UINT32 bitsPerPixel;
    2653 
    2654  if (!rfi)
    2655  return FALSE;
    2656 
    2657  gdi = ((rdpContext *)rfi)->gdi;
    2658 
    2659  bytesPerPixel = GetBytesPerPixel(gdi->hdc->format);
    2660  bitsPerPixel = GetBitsPerPixel(gdi->hdc->format);
    2661 
    2665  szmem = gdi->width * gdi->height * bytesPerPixel;
    2666 
    2667  REMMINA_PLUGIN_DEBUG("allocating %zu bytes for a full screenshot", szmem);
    2668  rpsd->buffer = malloc(szmem);
    2669  if (!rpsd->buffer) {
    2670  REMMINA_PLUGIN_DEBUG("could not set aside %zu bytes for a full screenshot", szmem);
    2671  return FALSE;
    2672  }
    2673  rpsd->width = gdi->width;
    2674  rpsd->height = gdi->height;
    2675  rpsd->bitsPerPixel = bitsPerPixel;
    2676  rpsd->bytesPerPixel = bytesPerPixel;
    2677 
    2678  memcpy(rpsd->buffer, gdi->primary_buffer, szmem);
    2679 
    2680  /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
    2681  return TRUE;
    2682 }
    2683 
    2684 /* Array of key/value pairs for colour depths */
    2685 static gpointer colordepth_list[] =
    2686 {
    2687  /* 1st one is the default in a new install */
    2688  "99", N_("Automatic (32 bpp) (Server chooses its best format)"),
    2689  "66", N_("GFX AVC444 (32 bpp)"),
    2690  "65", N_("GFX AVC420 (32 bpp)"),
    2691  "64", N_("GFX RFX (32 bpp)"),
    2692  "63", N_("GFX RFX Progressive (32 bpp)"),
    2693  "0", N_("RemoteFX (32 bpp)"),
    2694  "32", N_("True colour (32 bpp)"),
    2695  "24", N_("True colour (24 bpp)"),
    2696  "16", N_("High colour (16 bpp)"),
    2697  "15", N_("High colour (15 bpp)"),
    2698  "8", N_("256 colours (8 bpp)"),
    2699  NULL
    2700 };
    2701 
    2702 /* Array of key/value pairs for the FreeRDP logging level */
    2703 static gpointer log_level[] =
    2704 {
    2705  "INFO", "INFO",
    2706  "FATAL", "FATAL",
    2707  "ERROR", "ERROR",
    2708  "WARN", "WARN",
    2709  "DEBUG", "DEBUG",
    2710  "TRACE", "TRACE",
    2711  "OFF", "OFF",
    2712  NULL
    2713 };
    2714 
    2715 
    2716 /* Array of key/value pairs for quality selection */
    2717 static gpointer quality_list[] =
    2718 {
    2719  "0", N_("Poor (fastest)"),
    2720  "1", N_("Medium"),
    2721  "2", N_("Good"),
    2722  "9", N_("Best (slowest)"),
    2723  NULL
    2724 };
    2725 
    2726 /* Array of key/value pairs for quality selection */
    2727 static gpointer network_list[] =
    2728 {
    2729  "none", N_("None"),
    2730  "autodetect", N_("Auto-detect"),
    2731  "modem", N_("Modem"),
    2732  "broadband-low", N_("Low performance broadband"),
    2733  "satellite", N_("Satellite"),
    2734  "broadband-high", N_("High performance broadband"),
    2735  "wan", N_("WAN"),
    2736  "lan", N_("LAN"),
    2737  NULL
    2738 };
    2739 
    2740 /* Array of key/value pairs for sound options */
    2741 static gpointer sound_list[] =
    2742 {
    2743  "off", N_("Off"),
    2744  "local", N_("Local"),
    2745  "remote", N_("Remote"),
    2746  NULL
    2747 };
    2748 
    2749 /* Array of key/value pairs for security */
    2750 static gpointer security_list[] =
    2751 {
    2752  "", N_("Automatic negotiation"),
    2753  "nla", N_("NLA protocol security"),
    2754  "tls", N_("TLS protocol security"),
    2755  "rdp", N_("RDP protocol security"),
    2756  "ext", N_("NLA extended protocol security"),
    2757  NULL
    2758 };
    2759 
    2760 /* Array of key/value pairs for mouse movement */
    2761 static gpointer mouse_jitter_list[] =
    2762 {
    2763  "No", N_("No"),
    2764  "60", N_("Every 1 min"),
    2765  "180", N_("Every 3 min"),
    2766  "300", N_("Every 5 min"),
    2767  "600", N_("Every 10 min"),
    2768  NULL
    2769 };
    2770 
    2771 static gpointer gwtransp_list[] =
    2772 {
    2773  "http", "HTTP",
    2774  "rpc", "RPC",
    2775  "auto", "Auto",
    2776  NULL
    2777 };
    2778 
    2779 static gpointer tls_seclevel[] =
    2780 {
    2781  "", N_("Default"),
    2782  "0", N_("0 — Windows 7 compatible"),
    2783  "1", N_("1"),
    2784  "2", N_("2"),
    2785  "3", N_("3"),
    2786  "4", N_("4"),
    2787  "5", N_("5"),
    2788  NULL
    2789 };
    2790 
    2791 static gchar clientbuild_list[] =
    2792  N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)");
    2793 
    2794 static gchar clientbuild_tooltip[] =
    2795  N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
    2796  " • < 4034: Windows XP base smart card functions\n"
    2797  " • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
    2798  " SCardWriteCache(), SCardGetTransmitCount()\n"
    2799  " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
    2800  " SCardGetDeviceTypeId()");
    2801 
    2802 static gchar microphone_tooltip[] =
    2803  N_("Options for redirection of audio input:\n"
    2804  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    2805  " [channel:<channel>] Audio input (microphone)\n"
    2806  " • sys:pulse\n"
    2807  " • format:1\n"
    2808  " • sys:oss,dev:1,format:1\n"
    2809  " • sys:alsa");
    2810 
    2811 static gchar audio_tooltip[] =
    2812  N_("Options for redirection of audio output:\n"
    2813  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
    2814  " [channel:<channel>] Audio output\n"
    2815  " • sys:pulse\n"
    2816  " • format:1\n"
    2817  " • sys:oss,dev:1,format:1\n"
    2818  " • sys:alsa");
    2819 
    2820 
    2821 static gchar usb_tooltip[] =
    2822  N_("Options for redirection of USB device:\n"
    2823  " • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
    2824  " • auto\n"
    2825  " • id:054c:0268#4669:6e6b,addr:04:0c");
    2826 
    2827 static gchar timeout_tooltip[] =
    2828  N_("Advanced setting for high latency links:\n"
    2829  "Adjusts the connection timeout. Use if your connection times out.\n"
    2830  "The highest possible value is 600000 ms (10 minutes).\n");
    2831 
    2832 static gchar network_tooltip[] =
    2833  N_("Performance optimisations based on the network connection type:\n"
    2834  "Using auto-detection is advised.\n"
    2835  "If “Auto-detect” fails, choose the most appropriate option in the list.\n");
    2836 
    2837 static gchar monitorids_tooltip[] =
    2838  N_("Comma-separated list of monitor IDs and desktop orientations:\n"
    2839  " • [<id>:<orientation-in-degrees>,]\n"
    2840  " • 0,1,2,3\n"
    2841  " • 0:270,1:90\n"
    2842  "Orientations are specified in degrees, valid values are:\n"
    2843  " • 0 (landscape)\n"
    2844  " • 90 (portrait)\n"
    2845  " • 180 (landscape flipped)\n"
    2846  " • 270 (portrait flipped)\n"
    2847  "\n");
    2848 
    2849 static gchar drive_tooltip[] =
    2850  N_("Redirect directory <path> as named share <name>.\n"
    2851  " • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
    2852  " • MyHome,/home/remminer\n"
    2853  " • /home/remminer\n"
    2854  " • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
    2855  "Hotplug support is enabled with:\n"
    2856  " • hotplug,*\n"
    2857  "\n");
    2858 
    2859 /* Array of RemminaProtocolSetting for basic settings.
    2860  * Each item is composed by:
    2861  * a) RemminaProtocolSettingType for setting type
    2862  * b) Setting name
    2863  * c) Setting description
    2864  * d) Compact disposition
    2865  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
    2866  * f) Setting tooltip
    2867  * g) Validation data pointer, will be passed to the validation callback method.
    2868  * h) Validation callback method (Can be NULL. Every entry will be valid then.)
    2869  * use following prototype:
    2870  * gboolean mysetting_validator_method(gpointer key, gpointer value,
    2871  * gpointer validator_data);
    2872  * gpointer key is a gchar* containing the setting's name,
    2873  * gpointer value contains the value which should be validated,
    2874  * gpointer validator_data contains your passed data.
    2875  */
    2877 {
    2878  { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
    2879  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
    2880  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
    2881  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
    2882  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
    2883  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
    2884  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
    2885  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
    2886  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
    2887  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
    2888  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
    2889  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
    2890  { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
    2891  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
    2892  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
    2893  { REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
    2894  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
    2895 };
    2896 
    2897 /* Array of RemminaProtocolSetting for advanced settings.
    2898  * Each item is composed by:
    2899  * a) RemminaProtocolSettingType for setting type
    2900  * b) Setting name
    2901  * c) Setting description
    2902  * d) Compact disposition
    2903  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
    2904  * f) Setting Tooltip
    2905  */
    2907 {
    2908  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "quality", N_("Quality"), FALSE, quality_list, NULL },
    2909  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "security", N_("Security protocol negotiation"), FALSE, security_list, NULL },
    2910  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "gwtransp", N_("Gateway transport type"), FALSE, gwtransp_list, NULL },
    2911  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "tls-seclevel", N_("TLS Security Level"), FALSE, tls_seclevel, NULL },
    2912  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "freerdp_log_level", N_("FreeRDP log level"), FALSE, log_level, NULL },
    2913  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "freerdp_log_filters", N_("FreeRDP log filters"), FALSE, NULL, N_("tag:level[,tag:level[,…]]") },
    2914  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Audio output mode"), FALSE, sound_list, NULL },
    2915  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip },
    2916  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "microphone", N_("Redirect local microphone"), TRUE, NULL, microphone_tooltip },
    2917  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "timeout", N_("Connection timeout in ms"), TRUE, NULL, timeout_tooltip },
    2918  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL },
    2919  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_username", N_("Remote Desktop Gateway username"), FALSE, NULL, NULL },
    2920  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "gateway_password", N_("Remote Desktop Gateway password"), FALSE, NULL, NULL },
    2921  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_domain", N_("Remote Desktop Gateway domain"), FALSE, NULL, NULL },
    2922  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL },
    2923  { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip },
    2924  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Start-up program"), FALSE, NULL, NULL },
    2925  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL },
    2926  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL },
    2927  // TRANSLATORS: Do not use typographic quotation marks, these must stay as "double quote", also know as “Typewriter ("programmer's") quote, ambidextrous.”
    2928  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "printer_overrides", N_("Override printer drivers"), FALSE, NULL, N_("\"Samsung_CLX-3300_Series\":\"Samsung CLX-3300 Series PS\";\"Canon MF410\":\"Canon MF410 Series UFR II\"") },
    2929  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "usb", N_("USB device redirection"), TRUE, NULL, usb_tooltip },
    2930  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialname", N_("Local serial name"), FALSE, NULL, N_("COM1, COM2, etc.") },
    2931  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialdriver", N_("Local serial driver"), FALSE, NULL, N_("Serial") },
    2932  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialpath", N_("Local serial path"), FALSE, NULL, N_("/dev/ttyS0, /dev/ttyS1, etc.") },
    2933  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelname", N_("Local parallel name"), FALSE, NULL, NULL },
    2934  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelpath", N_("Local parallel device"), FALSE, NULL, NULL },
    2935  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "smartcardname", N_("Name of smart card"), FALSE, NULL, NULL },
    2936  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "dvc", N_("Dynamic virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
    2937  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "vc", N_("Static virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
    2938  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp2tcp", N_("TCP redirection"), FALSE, NULL, N_("/PATH/TO/rdp2tcp") },
    2939  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp_reconnect_attempts", N_("Reconnect attempts number"), FALSE, NULL, N_("The maximum number of reconnect attempts upon an RDP disconnect (default: 20)") },
    2940  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "rdp_mouse_jitter", N_("Move mouse when connection is idle"), FALSE, mouse_jitter_list, NULL },
    2941 
    2942  { REMMINA_PROTOCOL_SETTING_TYPE_ASSISTANCE, "assistance_mode", N_("Attempt to connect in assistance mode"), TRUE, NULL },
    2943  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "preferipv6", N_("Prefer IPv6 AAAA record over IPv4 A record"), TRUE, NULL, NULL },
    2944  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareprinter", N_("Share printers"), TRUE, NULL, NULL },
    2945  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareserial", N_("Share serial ports"), TRUE, NULL, NULL },
    2946  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "serialpermissive", N_("(SELinux) permissive mode for serial ports"), TRUE, NULL, NULL },
    2947  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareparallel", N_("Share parallel ports"), TRUE, NULL, NULL },
    2948  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sharesmartcard", N_("Share a smart card"), TRUE, NULL, NULL },
    2949  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("Turn off clipboard sync"), TRUE, NULL, NULL },
    2950  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "cert_ignore", N_("Ignore certificate"), TRUE, NULL, NULL },
    2951  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "old-license", N_("Use the old license workflow"), TRUE, NULL, N_("It disables CAL and hwId is set to 0") },
    2952  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
    2953  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "console", N_("Attach to console (2003/2003 R2)"), TRUE, NULL, NULL },
    2954  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable_fastpath", N_("Turn off fast-path"), TRUE, NULL, NULL },
    2955  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gateway_usage", N_("Server detection using Remote Desktop Gateway"), TRUE, NULL, NULL },
    2956 #if defined(PROXY_TYPE_IGNORE)
    2957  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "useproxyenv", N_("Use system proxy settings"), TRUE, NULL, NULL },
    2958 #endif
    2959  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableautoreconnect", N_("Turn off automatic reconnection"), TRUE, NULL, NULL },
    2960  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL },
    2961  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL },
    2962  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") },
    2963  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL },
    2964 #if FREERDP_CHECK_VERSION(2, 3, 1)
    2965  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "websockets", N_("Enable Gateway websockets support"), TRUE, NULL, NULL },
    2966 #endif
    2967  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "no-suppress", N_("Update framebuffer even when not visible"), TRUE, NULL },
    2968  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
    2969 };
    2970 
    2971 /* Array for available features.
    2972  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
    2974 {
    2975  { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, REMMINA_RDP_FEATURE_VIEWONLY, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "viewonly",
    2976  N_("View only") },
    2977  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL },
    2978  { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL },
    2979  { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL },
    2980  { REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_RDP_FEATURE_MULTIMON, NULL, NULL, NULL },
    2981  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL },
    2982  { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL },
    2983  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
    2984 };
    2985 
    2986 /* This will be filled with version info string */
    2988 
    2989 /* Protocol plugin definition and features */
    2991 {
    2993  "RDP", // Name
    2994  N_("RDP - Remote Desktop Protocol"), // Description
    2995  GETTEXT_PACKAGE, // Translation domain
    2996  remmina_plugin_rdp_version, // Version number
    2997  "org.remmina.Remmina-rdp-symbolic", // Icon for normal connection
    2998  "org.remmina.Remmina-rdp-ssh-symbolic", // Icon for SSH connection
    2999  remmina_rdp_basic_settings, // Array for basic settings
    3000  remmina_rdp_advanced_settings, // Array for advanced settings
    3001  REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type
    3002  remmina_rdp_features, // Array for available features
    3003  remmina_rdp_init, // Plugin initialization
    3004  remmina_rdp_open_connection, // Plugin open connection
    3005  remmina_rdp_close_connection, // Plugin close connection
    3006  remmina_rdp_query_feature, // Query for available features
    3007  remmina_rdp_call_feature, // Call a feature
    3008  remmina_rdp_keystroke, // Send a keystroke
    3009  remmina_rdp_get_screenshot, // Screenshot
    3010  remmina_rdp_event_on_map, // RCW map event
    3011  remmina_rdp_event_on_unmap // RCW unmap event
    3012 };
    3013 
    3014 /* File plugin definition and features */
    3016 {
    3017  REMMINA_PLUGIN_TYPE_FILE, // Type
    3018  "RDPF", // Name
    3019  N_("RDP - RDP File Handler"), // Description
    3020  GETTEXT_PACKAGE, // Translation domain
    3021  remmina_plugin_rdp_version, // Version number
    3022  remmina_rdp_file_import_test, // Test import function
    3023  remmina_rdp_file_import, // Import function
    3024  remmina_rdp_file_export_test, // Test export function
    3025  remmina_rdp_file_export, // Export function
    3026  NULL
    3027 };
    3028 
    3029 /* Preferences plugin definition and features */
    3031 {
    3032  REMMINA_PLUGIN_TYPE_PREF, // Type
    3033  "RDPS", // Name
    3034  N_("RDP - Preferences"), // Description
    3035  GETTEXT_PACKAGE, // Translation domain
    3036  remmina_plugin_rdp_version, // Version number
    3037  "RDP", // Label
    3038  remmina_rdp_settings_new // Preferences body function
    3039 };
    3040 
    3041 static char *buildconfig_strstr(const char *bc, const char *option)
    3042 {
    3043  TRACE_CALL(__func__);
    3044 
    3045  char *p, *n;
    3046 
    3047  p = strcasestr(bc, option);
    3048  if (p == NULL)
    3049  return NULL;
    3050 
    3051  if (p > bc && *(p - 1) > ' ')
    3052  return NULL;
    3053 
    3054  n = p + strlen(option);
    3055  if (*n > ' ')
    3056  return NULL;
    3057 
    3058  return p;
    3059 }
    3060 
    3061 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
    3062 {
    3063  int vermaj, vermin, verrev;
    3064 
    3065  TRACE_CALL(__func__);
    3066  remmina_plugin_service = service;
    3067 
    3068  /* Check that we are linked to the correct version of libfreerdp */
    3069 
    3070  freerdp_get_version(&vermaj, &vermin, &verrev);
    3071  if (vermaj < FREERDP_REQUIRED_MAJOR ||
    3072  (vermaj == FREERDP_REQUIRED_MAJOR && (vermin < FREERDP_REQUIRED_MINOR ||
    3073  (vermin == FREERDP_REQUIRED_MINOR && verrev < FREERDP_REQUIRED_REVISION)))) {
    3074  g_printf("Upgrade your FreeRDP library version from %d.%d.%d to at least libfreerdp %d.%d.%d "
    3075  "to run the RDP plugin.\n",
    3076  vermaj, vermin, verrev,
    3077  FREERDP_REQUIRED_MAJOR, FREERDP_REQUIRED_MINOR, FREERDP_REQUIRED_REVISION);
    3078  return FALSE;
    3079  }
    3080 
    3081  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
    3082  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
    3083 
    3084  if (!service->register_plugin((RemminaPlugin *)&remmina_rdp))
    3085  return FALSE;
    3086 
    3087  remmina_rdpf.export_hints = _("Export connection in Windows .rdp file format");
    3088 
    3089  if (!service->register_plugin((RemminaPlugin *)&remmina_rdpf))
    3090  return FALSE;
    3091 
    3092  if (!service->register_plugin((RemminaPlugin *)&remmina_rdps))
    3093  return FALSE;
    3094 
    3095  if (buildconfig_strstr(freerdp_get_build_config(), "WITH_GFX_H264=ON")) {
    3096  gfx_h264_available = TRUE;
    3097  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    3098  } else {
    3099  gfx_h264_available = FALSE;
    3100  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
    3101  /* Remove values 65 and 66 from colordepth_list array by shifting it */
    3102  gpointer *src, *dst;
    3103  dst = src = colordepth_list;
    3104  while (*src) {
    3105  if (strcmp(*src, "66") != 0 && strcmp(*src, "65") != 0) {
    3106  if (dst != src) {
    3107  *dst = *src;
    3108  *(dst + 1) = *(src + 1);
    3109  }
    3110  dst += 2;
    3111  }
    3112  src += 2;
    3113  }
    3114  *dst = NULL;
    3115  }
    3116 
    3118  "RDP plugin: %s (Git %s), Compiled with libfreerdp %s (%s), Running with libfreerdp %s (rev %s), H.264 %s",
    3119  VERSION, REMMINA_GIT_REVISION,
    3120 #ifdef WITH_FREERDP3
    3121  FREERDP_VERSION_FULL, FREERDP_GIT_REVISION,
    3122 #else
    3123  FREERDP_VERSION_FULL, GIT_REVISION,
    3124 #endif
    3125  freerdp_get_version_string(),
    3126  freerdp_get_build_revision(),
    3127  gfx_h264_available ? "Yes" : "No"
    3128  );
    3129 
    3131 
    3132  return TRUE;
    3133 }
    CliprdrClientContext * context
    Definition: rdp_plugin.h:135
    +
    gint w
    Definition: rdp_plugin.h:263
    struct remmina_plugin_rdp_event::@42::@45 mouse_event
    -
    gboolean thread_cancelled
    Definition: rdp_plugin.h:332
    +
    gboolean thread_cancelled
    Definition: rdp_plugin.h:333
    -
    gboolean is_reconnecting
    Definition: rdp_plugin.h:344
    -
    static gpointer tls_seclevel[]
    Definition: rdp_plugin.c:2773
    -
    static gchar network_tooltip[]
    Definition: rdp_plugin.c:2826
    -
    gint y
    Definition: rdp_plugin.h:262
    +
    gboolean is_reconnecting
    Definition: rdp_plugin.h:345
    +
    static gpointer tls_seclevel[]
    Definition: rdp_plugin.c:2779
    +
    static gchar network_tooltip[]
    Definition: rdp_plugin.c:2832
    +
    gint y
    Definition: rdp_plugin.h:263
    RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
    Definition: plugin.h:172
    -
    static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
    Definition: rdp_plugin.c:1064
    -
    static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2477
    -
    gboolean user_cancelled
    Definition: rdp_plugin.h:331
    -
    static gpointer quality_list[]
    Definition: rdp_plugin.c:2711
    - -
    static void remmina_rdp_send_ctrlaltdel(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:1247
    -
    gboolean attempt_interactive_authentication
    Definition: rdp_plugin.h:390
    +
    static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
    Definition: rdp_plugin.c:1070
    +
    static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2483
    +
    gboolean user_cancelled
    Definition: rdp_plugin.h:332
    +
    static gpointer quality_list[]
    Definition: rdp_plugin.c:2717
    + +
    static void remmina_rdp_send_ctrlaltdel(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:1253
    +
    gboolean attempt_interactive_authentication
    Definition: rdp_plugin.h:391
    void(* protocol_plugin_set_error)(RemminaProtocolWidget *gp, const gchar *fmt,...)
    Definition: plugin.h:176
    -
    gint event_pipe[2]
    Definition: rdp_plugin.h:381
    +
    gint event_pipe[2]
    Definition: rdp_plugin.h:382
    void(* file_set_int)(RemminaFile *remminafile, const gchar *setting, gint value)
    Definition: plugin.h:221
    - -
    static RemminaProtocolPlugin remmina_rdp
    Definition: rdp_plugin.c:2984
    + +
    static RemminaProtocolPlugin remmina_rdp
    Definition: rdp_plugin.c:2990
    gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:74
    gboolean remmina_rdp_file_export_test(RemminaFilePlugin *plugin, RemminaFile *remminafile)
    Definition: rdp_file.c:205
    -
    static gpointer log_level[]
    Definition: rdp_plugin.c:2697
    +
    static gpointer log_level[]
    Definition: rdp_plugin.c:2703
    gchar *(* file_get_user_datadir)(void)
    Definition: plugin.h:214
    -
    static BOOL rf_auto_reconnect(rfContext *rfi)
    Definition: rdp_plugin.c:401
    +
    static BOOL rf_auto_reconnect(rfContext *rfi)
    Definition: rdp_plugin.c:407
    typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
    Definition: types.h:44
    -
    pthread_t remmina_plugin_thread
    Definition: rdp_plugin.h:329
    +
    pthread_t remmina_plugin_thread
    Definition: rdp_plugin.h:330
    const gchar * export_hints
    Definition: plugin.h:111
    void remmina_rdp_cliprdr_detach_owner(RemminaProtocolWidget *gp)
    Definition: rdp_cliprdr.c:898
    struct remmina_plugin_rdp_ui_object::@50::@52 reg
    void(* protocol_plugin_set_width)(RemminaProtocolWidget *gp, gint width)
    Definition: plugin.h:169
    - +
    static BOOL gfx_h264_available
    Definition: rdp_plugin.c:114
    void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
    Definition: rdp_settings.c:707
    - -
    static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2567
    + +
    static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2573
    -
    static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
    Definition: rdp_plugin.c:914
    +
    static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
    Definition: rdp_plugin.c:920
    - -
    static gchar microphone_tooltip[]
    Definition: rdp_plugin.c:2796
    + +
    static gchar microphone_tooltip[]
    Definition: rdp_plugin.c:2802
    gint(* protocol_plugin_init_certificate)(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
    Definition: plugin.h:192
    -
    static BOOL rf_desktop_resize(rdpContext *context)
    Definition: rdp_plugin.c:580
    +
    static BOOL rf_desktop_resize(rdpContext *context)
    Definition: rdp_plugin.c:586
    static CLPARAM ** remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
    Definition: rdp_plugin.c:204
    void rf_register_graphics(rdpGraphics *graphics)
    Definition: rdp_graphics.c:381
    -
    gint h
    Definition: rdp_plugin.h:262
    +
    gint h
    Definition: rdp_plugin.h:263
    void remmina_rdp_settings_init(void)
    Definition: rdp_settings.c:57
    -
    static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
    Definition: rdp_plugin.c:775
    +
    static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
    Definition: rdp_plugin.c:781
    static time_t last_time
    Definition: rdp_plugin.c:116
    -
    static gboolean complete_cleanup_on_main_thread(gpointer data)
    Definition: rdp_plugin.c:2382
    -
    static gboolean remmina_rdp_main(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:1358
    +
    static gboolean complete_cleanup_on_main_thread(gpointer data)
    Definition: rdp_plugin.c:2388
    +
    static gboolean remmina_rdp_main(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:1364
    void remmina_rdp_clipboard_init(rfContext *rfi)
    Definition: rdp_cliprdr.c:934
    -
    static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
    Definition: rdp_plugin.c:2900
    -
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:323
    -
    int reconnect_nattempt
    Definition: rdp_plugin.h:352
    -
    static gpointer network_list[]
    Definition: rdp_plugin.c:2721
    +
    static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
    Definition: rdp_plugin.c:2906
    +
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:324
    +
    int reconnect_nattempt
    Definition: rdp_plugin.h:353
    +
    static gpointer network_list[]
    Definition: rdp_plugin.c:2727
    void remmina_rdp_OnChannelConnectedEventHandler(void *context, ChannelConnectedEventArgs *e)
    Definition: rdp_channels.c:46
    void(* protocol_plugin_send_keys_signals)(GtkWidget *widget, const guint *keyvals, int length, GdkEventType action)
    Definition: plugin.h:212
    @@ -166,149 +166,149 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
    gint(* protocol_plugin_get_width)(RemminaProtocolWidget *gp)
    Definition: plugin.h:168
    -
    static void remmina_rdp_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2439
    -
    static gchar * remmina_get_rdp_kbd_remap(const gchar *keymap)
    Definition: rdp_plugin.c:1330
    +
    static void remmina_rdp_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2445
    +
    static gchar * remmina_get_rdp_kbd_remap(const gchar *keymap)
    Definition: rdp_plugin.c:1336
    void(* get_server_port)(const gchar *server, gint defaultport, gchar **host, gint *port)
    Definition: plugin.h:249
    gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
    Definition: plugin.h:222
    -
    static void remmina_rdp_post_disconnect(freerdp *instance)
    Definition: rdp_plugin.c:978
    +
    static void remmina_rdp_post_disconnect(freerdp *instance)
    Definition: rdp_plugin.c:984
    -
    static gpointer mouse_jitter_list[]
    Definition: rdp_plugin.c:2755
    +
    static gpointer mouse_jitter_list[]
    Definition: rdp_plugin.c:2761
    -
    int reconnect_maxattempts
    Definition: rdp_plugin.h:351
    +
    int reconnect_maxattempts
    Definition: rdp_plugin.h:352
    gint(* protocol_plugin_changed_certificate)(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *new_fingerprint, const gchar *old_fingerprint)
    Definition: plugin.h:193
    static CLPARAM ** remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
    Definition: rdp_plugin.c:125
    -
    static gchar clientbuild_tooltip[]
    Definition: rdp_plugin.c:2788
    +
    static gchar clientbuild_tooltip[]
    Definition: rdp_plugin.c:2794
    RemminaPluginRdpEventType type
    Definition: rdp_plugin.h:191
    -
    UINT16 last_x
    Definition: rdp_plugin.h:383
    +
    UINT16 last_x
    Definition: rdp_plugin.h:384
    gboolean(* protocol_plugin_init_get_savepassword)(RemminaProtocolWidget *gp)
    Definition: plugin.h:197
    -
    static void rfi_uninit(rfContext *rfi)
    Definition: rdp_plugin.c:2352
    +
    static void rfi_uninit(rfContext *rfi)
    Definition: rdp_plugin.c:2358
    gboolean(* register_plugin)(RemminaPlugin *plugin)
    Definition: plugin.h:166
    - +
    enum rf_context::@59 postconnect_error
    -
    static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
    Callback function used by cupsEnumDests.
    Definition: rdp_plugin.c:1166
    +
    static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
    Callback function used by cupsEnumDests.
    Definition: rdp_plugin.c:1172
    -
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:355
    -
    static gpointer sound_list[]
    Definition: rdp_plugin.c:2735
    -
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:367
    -
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1463
    +
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:356
    +
    static gpointer sound_list[]
    Definition: rdp_plugin.c:2741
    +
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:368
    +
    int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1471
    -
    void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:912
    +
    void remmina_rdp_event_init(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:920
    gboolean(* protocol_plugin_has_error)(RemminaProtocolWidget *gp)
    Definition: plugin.h:175
    gchar *(* pref_get_value)(const gchar *key)
    Definition: plugin.h:227
    -
    UINT16 last_y
    Definition: rdp_plugin.h:384
    -
    static const RemminaProtocolFeature remmina_rdp_features[]
    Definition: rdp_plugin.c:2967
    -
    static RemminaFilePlugin remmina_rdpf
    Definition: rdp_plugin.c:3009
    -
    G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
    Definition: rdp_plugin.c:3055
    -
    static gpointer security_list[]
    Definition: rdp_plugin.c:2744
    +
    UINT16 last_y
    Definition: rdp_plugin.h:385
    +
    static const RemminaProtocolFeature remmina_rdp_features[]
    Definition: rdp_plugin.c:2973
    +
    static RemminaFilePlugin remmina_rdpf
    Definition: rdp_plugin.c:3015
    +
    G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
    Definition: rdp_plugin.c:3061
    +
    static gpointer security_list[]
    Definition: rdp_plugin.c:2750
    static BOOL rf_process_event_queue(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:213
    -
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1457
    -
    static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    Definition: rdp_plugin.c:2629
    -
    gboolean stop_reconnecting_requested
    Definition: rdp_plugin.h:345
    +
    void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
    Definition: rdp_event.c:1465
    +
    static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
    Definition: rdp_plugin.c:2635
    +
    gboolean stop_reconnecting_requested
    Definition: rdp_plugin.h:346
    struct remmina_plugin_rdp_event::@42::@44 key_event
    gboolean remmina_rdp_file_import_test(RemminaFilePlugin *plugin, const gchar *from_file)
    Definition: rdp_file.c:41
    gboolean remmina_rdp_file_export(RemminaFilePlugin *plugin, RemminaFile *remminafile, const gchar *to_file)
    Definition: rdp_file.c:282
    -
    static gpointer colordepth_list[]
    Definition: rdp_plugin.c:2679
    +
    static gpointer colordepth_list[]
    Definition: rdp_plugin.c:2685
    struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
    -
    static gchar audio_tooltip[]
    Definition: rdp_plugin.c:2805
    +
    static gchar audio_tooltip[]
    Definition: rdp_plugin.c:2811
    gint(* protocol_plugin_get_height)(RemminaProtocolWidget *gp)
    Definition: plugin.h:170
    gint(* protocol_plugin_init_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: plugin.h:191
    -
    static gchar monitorids_tooltip[]
    Definition: rdp_plugin.c:2831
    +
    static gchar monitorids_tooltip[]
    Definition: rdp_plugin.c:2837
    -
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:483
    -
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:380
    -
    static void remmina_rdp_main_loop(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:993
    -
    static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
    Definition: rdp_plugin.c:618
    -
    gint x
    Definition: rdp_plugin.h:262
    -
    rfClipboard clipboard
    Definition: rdp_plugin.h:386
    +
    void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:484
    +
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:381
    +
    static void remmina_rdp_main_loop(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:999
    +
    static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
    Definition: rdp_plugin.c:624
    +
    gint x
    Definition: rdp_plugin.h:263
    +
    rfClipboard clipboard
    Definition: rdp_plugin.h:387
    gint(* get_profile_remote_height)(RemminaProtocolWidget *gp)
    Definition: plugin.h:253
    -
    HANDLE event_handle
    Definition: rdp_plugin.h:382
    -
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1044
    +
    HANDLE event_handle
    Definition: rdp_plugin.h:383
    +
    void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1052
    -
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:561
    +
    void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:562
    RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
    Definition: plugin.h:178
    -
    static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint, DWORD flags)
    Definition: rdp_plugin.c:956
    +
    static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint, DWORD flags)
    Definition: rdp_plugin.c:962
    guint *(* pref_keymap_get_table)(const gchar *keymap)
    Definition: plugin.h:232
    void(* protocol_plugin_desktop_resize)(RemminaProtocolWidget *gp)
    Definition: plugin.h:190
    -
    static BOOL remmina_rdp_post_connect(freerdp *instance)
    Definition: rdp_plugin.c:700
    -
    static gchar usb_tooltip[]
    Definition: rdp_plugin.c:2815
    +
    static BOOL remmina_rdp_post_connect(freerdp *instance)
    Definition: rdp_plugin.c:706
    +
    static gchar usb_tooltip[]
    Definition: rdp_plugin.c:2821
    struct remmina_plugin_rdp_event::@42::@48 clipboard_formatdatarequest
    GtkWidget * remmina_rdp_settings_new(RemminaPrefPlugin *plugin)
    Definition: rdp_settings.c:696
    -
    static RemminaPrefPlugin remmina_rdps
    Definition: rdp_plugin.c:3024
    +
    static RemminaPrefPlugin remmina_rdps
    Definition: rdp_plugin.c:3030
    -
    gint srcBpp
    Definition: rdp_plugin.h:363
    +
    gint srcBpp
    Definition: rdp_plugin.h:364
    gchar *(* protocol_plugin_init_get_username)(RemminaProtocolWidget *gp)
    Definition: plugin.h:194
    -
    static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2525
    +
    static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:2531
    - +
    void remmina_rdp_clipboard_free(rfContext *rfi)
    Definition: rdp_cliprdr.c:939
    gint(* get_profile_remote_width)(RemminaProtocolWidget *gp)
    Definition: plugin.h:252
    -
    gboolean connected
    Definition: rdp_plugin.h:343
    +
    gboolean connected
    Definition: rdp_plugin.h:344
    gchar *(* protocol_plugin_init_get_password)(RemminaProtocolWidget *gp)
    Definition: plugin.h:195
    -
    RemminaScaleMode scale
    Definition: rdp_plugin.h:330
    -
    static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
    Definition: rdp_plugin.c:663
    +
    RemminaScaleMode scale
    Definition: rdp_plugin.h:331
    +
    static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
    Definition: rdp_plugin.c:669
    void remmina_rdp_OnChannelDisconnectedEventHandler(void *context, ChannelDisconnectedEventArgs *e)
    Definition: rdp_channels.c:86
    -
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2981
    -
    freerdp * instance
    Definition: rdp_plugin.h:327
    -
    static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
    Definition: rdp_plugin.c:634
    +
    static char remmina_plugin_rdp_version[256]
    Definition: rdp_plugin.c:2987
    +
    freerdp * instance
    Definition: rdp_plugin.h:328
    +
    static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
    Definition: rdp_plugin.c:640
    -
    static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
    Definition: rdp_plugin.c:834
    -
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:335
    -
    static char * buildconfig_strstr(const char *bc, const char *option)
    Definition: rdp_plugin.c:3035
    -
    static gchar clientbuild_list[]
    Definition: rdp_plugin.c:2785
    +
    static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
    Definition: rdp_plugin.c:840
    +
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:336
    +
    static char * buildconfig_strstr(const char *bc, const char *option)
    Definition: rdp_plugin.c:3041
    +
    static gchar clientbuild_list[]
    Definition: rdp_plugin.c:2791
    -
    static DWORD remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__((unused))
    Definition: rdp_plugin.c:937
    -
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1118
    -
    static BOOL rf_begin_paint(rdpContext *context)
    Definition: rdp_plugin.c:518
    -
    rdpSettings * settings
    Definition: rdp_plugin.h:326
    +
    static DWORD remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__((unused))
    Definition: rdp_plugin.c:943
    +
    void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1126
    +
    static BOOL rf_begin_paint(rdpContext *context)
    Definition: rdp_plugin.c:524
    +
    rdpSettings * settings
    Definition: rdp_plugin.h:327
    void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
    Definition: plugin.h:218
    void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
    Definition: plugin.h:171
    -
    static BOOL rf_end_paint(rdpContext *context)
    Definition: rdp_plugin.c:533
    -
    static gpointer remmina_rdp_main_thread(gpointer data)
    Definition: rdp_plugin.c:2412
    -
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1312
    -
    static BOOL remmina_rdp_pre_connect(freerdp *instance)
    Definition: rdp_plugin.c:675
    +
    static BOOL rf_end_paint(rdpContext *context)
    Definition: rdp_plugin.c:539
    +
    static gpointer remmina_rdp_main_thread(gpointer data)
    Definition: rdp_plugin.c:2418
    +
    void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:1320
    +
    static BOOL remmina_rdp_pre_connect(freerdp *instance)
    Definition: rdp_plugin.c:681
    -
    static gchar * remmina_rdp_find_prdriver(char *smap, char *prn)
    Definition: rdp_plugin.c:1091
    +
    static gchar * remmina_rdp_find_prdriver(char *smap, char *prn)
    Definition: rdp_plugin.c:1097
    -
    static gchar timeout_tooltip[]
    Definition: rdp_plugin.c:2821
    -
    static gboolean remmina_rdp_tunnel_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:342
    +
    static gchar timeout_tooltip[]
    Definition: rdp_plugin.c:2827
    +
    static gboolean remmina_rdp_tunnel_init(RemminaProtocolWidget *gp)
    Definition: rdp_plugin.c:348
    struct remmina_plugin_rdp_ui_object::@50::@57 event
    gchar *(* protocol_plugin_start_direct_tunnel)(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
    Definition: plugin.h:181
    void remmina_rdp_monitor_get(rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
    Set the MonitorIDs, the maxwidth and maxheight.
    Definition: rdp_monitor.c:68
    -
    static const RemminaProtocolSetting remmina_rdp_basic_settings[]
    Definition: rdp_plugin.c:2870
    -
    static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    Definition: rdp_plugin.c:2639
    +
    static const RemminaProtocolSetting remmina_rdp_basic_settings[]
    Definition: rdp_plugin.c:2876
    +
    static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
    Definition: rdp_plugin.c:2645
    void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
    Definition: rdp_event.c:150
    const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
    Definition: plugin.h:219
    -
    static gchar drive_tooltip[]
    Definition: rdp_plugin.c:2843
    +
    static gchar drive_tooltip[]
    Definition: rdp_plugin.c:2849
    RemminaPluginService * remmina_plugin_service
    Definition: rdp_plugin.c:112
    - +
    unsigned char * buffer
    Definition: types.h:84
    gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
    Definition: rdp_event.c:52
    struct timeval clientformatdatarequest_tv
    Definition: rdp_plugin.h:151
    -
    static gpointer gwtransp_list[]
    Definition: rdp_plugin.c:2765
    -
    rdpContext context
    Definition: rdp_plugin.h:320
    -
    static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2573
    +
    static gpointer gwtransp_list[]
    Definition: rdp_plugin.c:2771
    +
    rdpContext context
    Definition: rdp_plugin.h:321
    +
    static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
    Definition: rdp_plugin.c:2579
    gchar *(* protocol_plugin_init_get_domain)(RemminaProtocolWidget *gp)
    Definition: plugin.h:196
    N_("Unable to connect to VNC server")
    Definition: vnc_plugin.c:953
    gboolean(* is_main_thread)(void)
    Definition: plugin.h:250
    @@ -316,12 +316,12 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
    RemminaFile * remmina_rdp_file_import(RemminaFilePlugin *plugin, const gchar *from_file)
    Definition: rdp_file.c:185
    enum rf_clipboard::@41 srv_clip_data_wait
    struct rf_context rfContext
    Definition: rdp_plugin.h:84
    -
    gboolean sw_gdi
    Definition: rdp_plugin.h:354
    -
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:266
    +
    gboolean sw_gdi
    Definition: rdp_plugin.h:355
    +
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:267
    guint remmina_rdp_settings_get_keyboard_layout(void)
    Definition: rdp_settings.c:72
    - - -
    static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
    Definition: rdp_plugin.c:1257
    + + +
    static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
    Definition: rdp_plugin.c:1263
    diff --git a/public/rdp__plugin_8h.html b/public/rdp__plugin_8h.html index f5eb715b7..e56c0b22a 100644 --- a/public/rdp__plugin_8h.html +++ b/public/rdp__plugin_8h.html @@ -216,7 +216,7 @@ Variables
    -

    Definition at line 229 of file rdp_plugin.h.

    +

    Definition at line 230 of file rdp_plugin.h.

    @@ -246,7 +246,7 @@ Variables
    -

    Definition at line 395 of file rdp_plugin.h.

    +

    Definition at line 396 of file rdp_plugin.h.

    @@ -374,7 +374,7 @@ Variables REMMINA_RDP_UI_CLIPBOARD_SET_DATA  -

    Definition at line 241 of file rdp_plugin.h.

    +

    Definition at line 242 of file rdp_plugin.h.

    @@ -394,7 +394,7 @@ Variables REMMINA_RDP_UI_EVENT_DESTROY_CAIRO_SURFACE  -

    Definition at line 256 of file rdp_plugin.h.

    +

    Definition at line 257 of file rdp_plugin.h.

    @@ -418,7 +418,7 @@ Variables REMMINA_RDP_POINTER_SETPOS  -

    Definition at line 247 of file rdp_plugin.h.

    +

    Definition at line 248 of file rdp_plugin.h.

    @@ -443,7 +443,7 @@ Variables REMMINA_RDP_UI_EVENT  -

    Definition at line 231 of file rdp_plugin.h.

    +

    Definition at line 232 of file rdp_plugin.h.

    diff --git a/public/rdp__plugin_8h_source.html b/public/rdp__plugin_8h_source.html index c9095e938..c1fb59c58 100644 --- a/public/rdp__plugin_8h_source.html +++ b/public/rdp__plugin_8h_source.html @@ -86,178 +86,179 @@ $(document).ready(function(){initNavTree('rdp__plugin_8h_source.html','');});
    rdp_plugin.h
    -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 #pragma once
    38 
    39 #include "common/remmina_plugin.h"
    40 #include <freerdp/freerdp.h>
    41 #include <freerdp/version.h>
    42 #include <freerdp/channels/channels.h>
    43 #include <freerdp/codec/color.h>
    44 #include <freerdp/codec/rfx.h>
    45 #include <freerdp/gdi/gdi.h>
    46 #include <freerdp/gdi/dc.h>
    47 #include <freerdp/gdi/region.h>
    48 #include <freerdp/client/cliprdr.h>
    49 #include <freerdp/client/disp.h>
    50 #ifdef GDK_WINDOWING_X11
    51 #include <gdk/gdkx.h>
    52 #elif defined(GDK_WINDOWING_WAYLAND)
    53 #include <gdk/gdkwayland.h>
    54 #endif
    55 
    56 #include <winpr/clipboard.h>
    57 
    69 #define FREERDP_CHECK_VERSION(major,minor,revision) \
    70  (FREERDP_VERSION_MAJOR > (major) || \
    71  (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR > (minor)) || \
    72  (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR == (minor) && \
    73  FREERDP_VERSION_REVISION >= (revision)))
    74 
    81 #define AVC_MIN_DESKTOP_WIDTH 644
    82 #define AVC_MIN_DESKTOP_HEIGHT 480
    83 
    84 typedef struct rf_context rfContext;
    85 
    86 #define GET_PLUGIN_DATA(gp) (rfContext *)g_object_get_data(G_OBJECT(gp), "plugin-data")
    87 
    101 /* Poor (default) - all disabled */
    102 #define DEFAULT_QUALITY_0 0x6f
    103 /* Medium - only THEMING, CURSOR_SHADOW and CURSORSETTINGS enabled, all other disabled */
    104 #define DEFAULT_QUALITY_1 0x07
    105 /* Good - WALLPAPER, FONT_SMOOTHING, DESKTOP_COMPOSITION disabled, all other enabled */
    106 #define DEFAULT_QUALITY_2 0x01
    107 /* Best - DESKTOP_COMPOSITION disabled, all other enabled */
    108 #define DEFAULT_QUALITY_9 0x80
    109 
    111 
    112 #define REMMINA_PLUGIN_INFO(fmt, ...) \
    113  remmina_plugin_service->_remmina_info(__func__, fmt, ##__VA_ARGS__)
    114 
    115 #define REMMINA_PLUGIN_MESSAGE(fmt, ...) \
    116  remmina_plugin_service->_remmina_message(__func, fmt, ##__VA_ARGS__)
    117 
    118 #define REMMINA_PLUGIN_DEBUG(fmt, ...) \
    119  remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__)
    120 
    121 #define REMMINA_PLUGIN_WARNING(fmt, ...) \
    122  remmina_plugin_service->_remmina_warning(__func__, fmt, ##__VA_ARGS__)
    123 
    124 /* This will intentionally crash Remmina */
    125 #define REMMINA_PLUGIN_ERROR(fmt, ...) \
    126  remmina_plugin_service->_remmina_error(__func__, fmt, ##__VA_ARGS__)
    127 
    128 #define REMMINA_PLUGIN_CRITICAL(fmt, ...) \
    129  remmina_plugin_service->_remmina_critical(__func__, fmt, ##__VA_ARGS__)
    130 #define REMMINA_PLUGIN_AUDIT(fmt, ...) \
    131  remmina_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__)
    132 
    133 struct rf_clipboard {
    135  CliprdrClientContext * context;
    136  wClipboard * system;
    138 
    139  UINT32 format;
    141 
    142  pthread_mutex_t transfer_clip_mutex;
    143  pthread_cond_t transfer_clip_cond;
    145  gpointer srv_data;
    146  pthread_mutex_t srv_data_mutex;
    147 
    149 
    150  /* Stats for clipboard download */
    152 };
    153 typedef struct rf_clipboard rfClipboard;
    154 
    155 
    156 struct rf_pointer {
    157  rdpPointer pointer;
    158  GdkCursor * cursor;
    159 };
    160 typedef struct rf_pointer rfPointer;
    161 
    162 #ifdef RF_BITMAP
    163 struct rf_bitmap {
    164  rdpBitmap bitmap;
    165  Pixmap pixmap;
    166  cairo_surface_t * surface;
    167 };
    168 typedef struct rf_bitmap rfBitmap;
    169 #endif
    170 
    171 #ifdef RF_GLYPH
    172 struct rf_glyph {
    173  rdpGlyph glyph;
    174  Pixmap pixmap;
    175 };
    176 typedef struct rf_glyph rfGlyph;
    177 #endif
    178 
    179 typedef enum {
    189 
    192  union {
    193  struct {
    194  BOOL up;
    195  BOOL extended;
    196  UINT8 key_code;
    197  UINT32 unicode_code;
    198  } key_event;
    199  struct {
    200  UINT16 flags;
    201  UINT16 x;
    202  UINT16 y;
    203  BOOL extended;
    204  } mouse_event;
    205  struct {
    206  CLIPRDR_FORMAT_LIST *pFormatList;
    207  } clipboard_formatlist;
    208  struct {
    209  BYTE * data;
    210  int size;
    211  } clipboard_formatdataresponse;
    212  struct {
    213  CLIPRDR_FORMAT_DATA_REQUEST *pFormatDataRequest;
    214  } clipboard_formatdatarequest;
    215  struct {
    216  gint Flags;
    217  gint Left;
    218  gint Top;
    219  gint width;
    220  gint height;
    226  } monitor_layout;
    227  };
    228 };
    230 
    231 typedef enum {
    240 
    241 typedef enum {
    246 
    247 typedef enum {
    255 
    256 typedef enum {
    260 
    261 typedef struct {
    262  gint x, y, w, h;
    263 } region;
    264 
    267  gboolean sync;
    268  gboolean complete;
    269  pthread_mutex_t sync_wait_mutex;
    270  pthread_cond_t sync_wait_cond;
    271  union {
    272  struct {
    274  gint ninvalid;
    275  } reg;
    276  struct {
    277  rdpContext * context;
    280  } cursor;
    281  struct {
    282  gint left;
    283  gint top;
    284  RFX_MESSAGE * message;
    285  } rfx;
    286  struct {
    287  gint left;
    288  gint top;
    289  gint width;
    290  gint height;
    291  UINT8 * bitmap;
    292  } nocodec;
    293  struct {
    295  GtkTargetList * targetlist;
    296  UINT32 format;
    298  gpointer data;
    299  } clipboard;
    300  struct {
    302  } event;
    303  struct {
    304  gint x;
    305  gint y;
    306  } pos;
    307  };
    308  /* We can also return values here, usually integers*/
    309  int retval;
    310  /* Some functions also may return a pointer. */
    311  void * retptr;
    312 };
    313 
    315  unsigned orig_keycode;
    318 
    319 struct rf_context {
    320  rdpContext context;
    321  DEFINE_RDP_CLIENT_COMMON();
    322 
    324 
    325  /* main */
    326  rdpSettings * settings;
    327  freerdp * instance;
    328 
    331  gboolean user_cancelled;
    333 
    334  CliprdrClientContext * cliprdr;
    335  DispClientContext * dispcontext;
    336 
    337  RDP_PLUGIN_DATA rdpdr_data[5];
    338  RDP_PLUGIN_DATA drdynvc_data[5];
    339  gchar rdpsnd_options[20];
    340 
    341  gboolean rdpgfxchan;
    342 
    343  gboolean connected;
    344  gboolean is_reconnecting;
    346  /* orphaned: rf_context has still one or more libfreerdp thread active,
    347  * but no longer maintained by an open RemminaProtocolWidget/tab.
    348  * When the orphaned thread terminates, we must cleanup rf_context.
    349  */
    350  gboolean orphaned;
    353 
    354  gboolean sw_gdi;
    355  GtkWidget * drawing_area;
    358  gdouble scale_x;
    359  gdouble scale_y;
    362 
    363  gint srcBpp;
    364  GdkDisplay * display;
    365  GdkVisual * visual;
    366  cairo_surface_t * surface;
    367  cairo_format_t cairo_format;
    368  gint bpp;
    370  gint * colormap;
    371 
    373  GHashTable * object_table;
    374 
    375  GAsyncQueue * ui_queue;
    376  pthread_mutex_t ui_queue_mutex;
    377  guint ui_handler;
    378 
    379  GArray * pressed_keys;
    380  GAsyncQueue * event_queue;
    381  gint event_pipe[2];
    382  HANDLE event_handle;
    383  UINT16 last_x;
    384  UINT16 last_y;
    385 
    387 
    388  GArray * keymap; /* Array of RemminaPluginRdpKeymapEntry */
    389 
    391 
    392  enum { REMMINA_POSTCONNECT_ERROR_OK = 0, REMMINA_POSTCONNECT_ERROR_GDI_INIT = 1, REMMINA_POSTCONNECT_ERROR_NO_H264 } postconnect_error;
    393 };
    394 
    396 
    399 void rf_get_fds(RemminaProtocolWidget *gp, void **rfds, int *rcount);
    402 
    void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
    Definition: rdp_event.c:150
    +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 #pragma once
    38 
    39 #include "common/remmina_plugin.h"
    40 #include <freerdp/freerdp.h>
    41 #include <freerdp/version.h>
    42 #include <freerdp/channels/channels.h>
    43 #include <freerdp/codec/color.h>
    44 #include <freerdp/codec/rfx.h>
    45 #include <freerdp/gdi/gdi.h>
    46 #include <freerdp/gdi/dc.h>
    47 #include <freerdp/gdi/region.h>
    48 #include <freerdp/client/cliprdr.h>
    49 #include <freerdp/client/disp.h>
    50 #ifdef GDK_WINDOWING_X11
    51 #include <gdk/gdkx.h>
    52 #elif defined(GDK_WINDOWING_WAYLAND)
    53 #include <gdk/gdkwayland.h>
    54 #endif
    55 
    56 #include <winpr/clipboard.h>
    57 
    69 #define FREERDP_CHECK_VERSION(major,minor,revision) \
    70  (FREERDP_VERSION_MAJOR > (major) || \
    71  (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR > (minor)) || \
    72  (FREERDP_VERSION_MAJOR == (major) && FREERDP_VERSION_MINOR == (minor) && \
    73  FREERDP_VERSION_REVISION >= (revision)))
    74 
    81 #define AVC_MIN_DESKTOP_WIDTH 644
    82 #define AVC_MIN_DESKTOP_HEIGHT 480
    83 
    84 typedef struct rf_context rfContext;
    85 
    86 #define GET_PLUGIN_DATA(gp) (rfContext *)g_object_get_data(G_OBJECT(gp), "plugin-data")
    87 
    101 /* Poor (default) - all disabled */
    102 #define DEFAULT_QUALITY_0 0x6f
    103 /* Medium - only THEMING, CURSOR_SHADOW and CURSORSETTINGS enabled, all other disabled */
    104 #define DEFAULT_QUALITY_1 0x07
    105 /* Good - WALLPAPER, FONT_SMOOTHING, DESKTOP_COMPOSITION disabled, all other enabled */
    106 #define DEFAULT_QUALITY_2 0x01
    107 /* Best - DESKTOP_COMPOSITION disabled, all other enabled */
    108 #define DEFAULT_QUALITY_9 0x80
    109 
    111 
    112 #define REMMINA_PLUGIN_INFO(fmt, ...) \
    113  remmina_plugin_service->_remmina_info(__func__, fmt, ##__VA_ARGS__)
    114 
    115 #define REMMINA_PLUGIN_MESSAGE(fmt, ...) \
    116  remmina_plugin_service->_remmina_message(__func, fmt, ##__VA_ARGS__)
    117 
    118 #define REMMINA_PLUGIN_DEBUG(fmt, ...) \
    119  remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__)
    120 
    121 #define REMMINA_PLUGIN_WARNING(fmt, ...) \
    122  remmina_plugin_service->_remmina_warning(__func__, fmt, ##__VA_ARGS__)
    123 
    124 /* This will intentionally crash Remmina */
    125 #define REMMINA_PLUGIN_ERROR(fmt, ...) \
    126  remmina_plugin_service->_remmina_error(__func__, fmt, ##__VA_ARGS__)
    127 
    128 #define REMMINA_PLUGIN_CRITICAL(fmt, ...) \
    129  remmina_plugin_service->_remmina_critical(__func__, fmt, ##__VA_ARGS__)
    130 #define REMMINA_PLUGIN_AUDIT(fmt, ...) \
    131  remmina_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__)
    132 
    133 struct rf_clipboard {
    135  CliprdrClientContext * context;
    136  wClipboard * system;
    138 
    139  UINT32 format;
    141 
    142  pthread_mutex_t transfer_clip_mutex;
    143  pthread_cond_t transfer_clip_cond;
    145  gpointer srv_data;
    146  pthread_mutex_t srv_data_mutex;
    147 
    149 
    150  /* Stats for clipboard download */
    152 };
    153 typedef struct rf_clipboard rfClipboard;
    154 
    155 
    156 struct rf_pointer {
    157  rdpPointer pointer;
    158  GdkCursor * cursor;
    159 };
    160 typedef struct rf_pointer rfPointer;
    161 
    162 #ifdef RF_BITMAP
    163 struct rf_bitmap {
    164  rdpBitmap bitmap;
    165  Pixmap pixmap;
    166  cairo_surface_t * surface;
    167 };
    168 typedef struct rf_bitmap rfBitmap;
    169 #endif
    170 
    171 #ifdef RF_GLYPH
    172 struct rf_glyph {
    173  rdpGlyph glyph;
    174  Pixmap pixmap;
    175 };
    176 typedef struct rf_glyph rfGlyph;
    177 #endif
    178 
    179 typedef enum {
    189 
    192  union {
    193  struct {
    194  BOOL up;
    195  BOOL extended;
    196  UINT8 key_code;
    197  UINT32 unicode_code;
    198  BOOL extended1;
    199  } key_event;
    200  struct {
    201  UINT16 flags;
    202  UINT16 x;
    203  UINT16 y;
    204  BOOL extended;
    205  } mouse_event;
    206  struct {
    207  CLIPRDR_FORMAT_LIST *pFormatList;
    208  } clipboard_formatlist;
    209  struct {
    210  BYTE * data;
    211  int size;
    212  } clipboard_formatdataresponse;
    213  struct {
    214  CLIPRDR_FORMAT_DATA_REQUEST *pFormatDataRequest;
    215  } clipboard_formatdatarequest;
    216  struct {
    217  gint Flags;
    218  gint Left;
    219  gint Top;
    220  gint width;
    221  gint height;
    227  } monitor_layout;
    228  };
    229 };
    231 
    232 typedef enum {
    241 
    242 typedef enum {
    247 
    248 typedef enum {
    256 
    257 typedef enum {
    261 
    262 typedef struct {
    263  gint x, y, w, h;
    264 } region;
    265 
    268  gboolean sync;
    269  gboolean complete;
    270  pthread_mutex_t sync_wait_mutex;
    271  pthread_cond_t sync_wait_cond;
    272  union {
    273  struct {
    275  gint ninvalid;
    276  } reg;
    277  struct {
    278  rdpContext * context;
    281  } cursor;
    282  struct {
    283  gint left;
    284  gint top;
    285  RFX_MESSAGE * message;
    286  } rfx;
    287  struct {
    288  gint left;
    289  gint top;
    290  gint width;
    291  gint height;
    292  UINT8 * bitmap;
    293  } nocodec;
    294  struct {
    296  GtkTargetList * targetlist;
    297  UINT32 format;
    299  gpointer data;
    300  } clipboard;
    301  struct {
    303  } event;
    304  struct {
    305  gint x;
    306  gint y;
    307  } pos;
    308  };
    309  /* We can also return values here, usually integers*/
    310  int retval;
    311  /* Some functions also may return a pointer. */
    312  void * retptr;
    313 };
    314 
    316  unsigned orig_keycode;
    319 
    320 struct rf_context {
    321  rdpContext context;
    322  DEFINE_RDP_CLIENT_COMMON();
    323 
    325 
    326  /* main */
    327  rdpSettings * settings;
    328  freerdp * instance;
    329 
    332  gboolean user_cancelled;
    334 
    335  CliprdrClientContext * cliprdr;
    336  DispClientContext * dispcontext;
    337 
    338  RDP_PLUGIN_DATA rdpdr_data[5];
    339  RDP_PLUGIN_DATA drdynvc_data[5];
    340  gchar rdpsnd_options[20];
    341 
    342  gboolean rdpgfxchan;
    343 
    344  gboolean connected;
    345  gboolean is_reconnecting;
    347  /* orphaned: rf_context has still one or more libfreerdp thread active,
    348  * but no longer maintained by an open RemminaProtocolWidget/tab.
    349  * When the orphaned thread terminates, we must cleanup rf_context.
    350  */
    351  gboolean orphaned;
    354 
    355  gboolean sw_gdi;
    356  GtkWidget * drawing_area;
    359  gdouble scale_x;
    360  gdouble scale_y;
    363 
    364  gint srcBpp;
    365  GdkDisplay * display;
    366  GdkVisual * visual;
    367  cairo_surface_t * surface;
    368  cairo_format_t cairo_format;
    369  gint bpp;
    371  gint * colormap;
    372 
    374  GHashTable * object_table;
    375 
    376  GAsyncQueue * ui_queue;
    377  pthread_mutex_t ui_queue_mutex;
    378  guint ui_handler;
    379 
    380  GArray * pressed_keys;
    381  GAsyncQueue * event_queue;
    382  gint event_pipe[2];
    383  HANDLE event_handle;
    384  UINT16 last_x;
    385  UINT16 last_y;
    386 
    388 
    389  GArray * keymap; /* Array of RemminaPluginRdpKeymapEntry */
    390 
    392 
    393  enum { REMMINA_POSTCONNECT_ERROR_OK = 0, REMMINA_POSTCONNECT_ERROR_GDI_INIT = 1, REMMINA_POSTCONNECT_ERROR_NO_H264 } postconnect_error;
    394 };
    395 
    397 
    400 void rf_get_fds(RemminaProtocolWidget *gp, void **rfds, int *rcount);
    403 
    void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
    Definition: rdp_event.c:150
    CliprdrClientContext * context
    Definition: rdp_plugin.h:135
    - - - -
    gboolean thread_cancelled
    Definition: rdp_plugin.h:332
    - - -
    gboolean is_reconnecting
    Definition: rdp_plugin.h:344
    + + + +
    gboolean thread_cancelled
    Definition: rdp_plugin.h:333
    + + +
    gboolean is_reconnecting
    Definition: rdp_plugin.h:345
    gulong clipboard_handler
    Definition: rdp_plugin.h:140
    -
    RemminaPluginRdpUiClipboardType type
    Definition: rdp_plugin.h:294
    -
    gint y
    Definition: rdp_plugin.h:262
    +
    RemminaPluginRdpUiClipboardType type
    Definition: rdp_plugin.h:295
    +
    gint y
    Definition: rdp_plugin.h:263
    Pixmap pixmap
    Definition: rdp_plugin.h:165
    -
    guint delayed_monitor_layout_handler
    Definition: rdp_plugin.h:360
    -
    RemminaPluginRdpUiEeventType
    Definition: rdp_plugin.h:256
    - -
    gboolean user_cancelled
    Definition: rdp_plugin.h:331
    - -
    CLIPRDR_FORMAT_LIST * pFormatList
    Definition: rdp_plugin.h:206
    -
    gboolean attempt_interactive_authentication
    Definition: rdp_plugin.h:390
    - -
    gdouble scale_y
    Definition: rdp_plugin.h:359
    - - - - +
    guint delayed_monitor_layout_handler
    Definition: rdp_plugin.h:361
    +
    RemminaPluginRdpUiEeventType
    Definition: rdp_plugin.h:257
    + +
    gboolean user_cancelled
    Definition: rdp_plugin.h:332
    + +
    CLIPRDR_FORMAT_LIST * pFormatList
    Definition: rdp_plugin.h:207
    +
    gboolean attempt_interactive_authentication
    Definition: rdp_plugin.h:391
    + +
    gdouble scale_y
    Definition: rdp_plugin.h:360
    + + + + -
    RemminaPluginRdpUiType
    Definition: rdp_plugin.h:231
    +
    RemminaPluginRdpUiType
    Definition: rdp_plugin.h:232
    -
    cairo_surface_t * surface
    Definition: rdp_plugin.h:366
    +
    cairo_surface_t * surface
    Definition: rdp_plugin.h:367
    -
    pthread_t remmina_plugin_thread
    Definition: rdp_plugin.h:329
    +
    pthread_t remmina_plugin_thread
    Definition: rdp_plugin.h:330
    RemminaPluginService * remmina_plugin_service
    Definition: rdp_plugin.c:112
    pthread_mutex_t transfer_clip_mutex
    Definition: rdp_plugin.h:142
    -
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:341
    +
    gboolean rdpgfxchan
    Definition: rdp_plugin.h:342
    - +
    int requestedFormatId
    Definition: rdp_plugin.h:137
    - -
    guint ui_handler
    Definition: rdp_plugin.h:377
    + +
    guint ui_handler
    Definition: rdp_plugin.h:378
    - +
    pthread_mutex_t srv_data_mutex
    Definition: rdp_plugin.h:146
    void rf_object_free(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
    - - -
    GdkDisplay * display
    Definition: rdp_plugin.h:364
    -
    GAsyncQueue * ui_queue
    Definition: rdp_plugin.h:375
    + + +
    GdkDisplay * display
    Definition: rdp_plugin.h:365
    +
    GAsyncQueue * ui_queue
    Definition: rdp_plugin.h:376
    RemminaPluginRdpEventType
    Definition: rdp_plugin.h:179
    -
    pthread_mutex_t sync_wait_mutex
    Definition: rdp_plugin.h:269
    - - +
    pthread_mutex_t sync_wait_mutex
    Definition: rdp_plugin.h:270
    + + -
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:323
    -
    int reconnect_nattempt
    Definition: rdp_plugin.h:352
    +
    RemminaProtocolWidget * protocol_widget
    Definition: rdp_plugin.h:324
    +
    int reconnect_nattempt
    Definition: rdp_plugin.h:353
    void rf_init(RemminaProtocolWidget *gp)
    rfContext * rfi
    Definition: rdp_plugin.h:134
    - -
    GdkVisual * visual
    Definition: rdp_plugin.h:365
    - - + +
    GdkVisual * visual
    Definition: rdp_plugin.h:366
    + + - -
    gdouble scale_x
    Definition: rdp_plugin.h:358
    + +
    gdouble scale_x
    Definition: rdp_plugin.h:359
    gpointer srv_data
    Definition: rdp_plugin.h:145
    rdpBitmap bitmap
    Definition: rdp_plugin.h:164
    -
    GtkTargetList * targetlist
    Definition: rdp_plugin.h:295
    +
    GtkTargetList * targetlist
    Definition: rdp_plugin.h:296
    BOOL rf_check_fds(RemminaProtocolWidget *gp)
    - -
    int reconnect_maxattempts
    Definition: rdp_plugin.h:351
    + +
    int reconnect_maxattempts
    Definition: rdp_plugin.h:352
    RemminaPluginRdpEventType type
    Definition: rdp_plugin.h:191
    - -
    UINT16 last_x
    Definition: rdp_plugin.h:383
    -
    RemminaPluginRdpUiPointerType type
    Definition: rdp_plugin.h:279
    + +
    UINT16 last_x
    Definition: rdp_plugin.h:384
    +
    RemminaPluginRdpUiPointerType type
    Definition: rdp_plugin.h:280
    pthread_cond_t transfer_clip_cond
    Definition: rdp_plugin.h:143
    - + - +
    rdpPointer pointer
    Definition: rdp_plugin.h:157
    - +
    Pixmap pixmap
    Definition: rdp_plugin.h:174
    - - - -
    unsigned translated_keycode
    Definition: rdp_plugin.h:316
    + + + +
    unsigned translated_keycode
    Definition: rdp_plugin.h:317
    -
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:355
    -
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:367
    - - -
    RemminaPluginRdpUiClipboardType
    Definition: rdp_plugin.h:241
    -
    gboolean use_client_keymap
    Definition: rdp_plugin.h:361
    +
    GtkWidget * drawing_area
    Definition: rdp_plugin.h:356
    +
    cairo_format_t cairo_format
    Definition: rdp_plugin.h:368
    + + +
    RemminaPluginRdpUiClipboardType
    Definition: rdp_plugin.h:242
    +
    gboolean use_client_keymap
    Definition: rdp_plugin.h:362
    -
    GArray * keymap
    Definition: rdp_plugin.h:388
    -
    RemminaPluginRdpUiPointerType
    Definition: rdp_plugin.h:247
    -
    gint scanline_pad
    Definition: rdp_plugin.h:369
    -
    UINT16 last_y
    Definition: rdp_plugin.h:384
    -
    unsigned orig_keycode
    Definition: rdp_plugin.h:315
    +
    GArray * keymap
    Definition: rdp_plugin.h:389
    +
    RemminaPluginRdpUiPointerType
    Definition: rdp_plugin.h:248
    +
    gint scanline_pad
    Definition: rdp_plugin.h:370
    +
    UINT16 last_y
    Definition: rdp_plugin.h:385
    +
    unsigned orig_keycode
    Definition: rdp_plugin.h:316
    GdkCursor * cursor
    Definition: rdp_plugin.h:158
    wClipboard * system
    Definition: rdp_plugin.h:136
    void rf_uninit(RemminaProtocolWidget *gp)
    - +
    struct remmina_plugin_rdp_keymap_entry RemminaPluginRdpKeymapEntry
    -
    gboolean stop_reconnecting_requested
    Definition: rdp_plugin.h:345
    - -
    gint * colormap
    Definition: rdp_plugin.h:370
    - +
    gboolean stop_reconnecting_requested
    Definition: rdp_plugin.h:346
    + +
    gint * colormap
    Definition: rdp_plugin.h:371
    +
    void rf_get_fds(RemminaProtocolWidget *gp, void **rfds, int *rcount)
    -
    guint object_id_seq
    Definition: rdp_plugin.h:372
    -
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:380
    -
    pthread_cond_t sync_wait_cond
    Definition: rdp_plugin.h:270
    -
    rfClipboard clipboard
    Definition: rdp_plugin.h:386
    -
    HANDLE event_handle
    Definition: rdp_plugin.h:382
    +
    guint object_id_seq
    Definition: rdp_plugin.h:373
    +
    GAsyncQueue * event_queue
    Definition: rdp_plugin.h:381
    +
    pthread_cond_t sync_wait_cond
    Definition: rdp_plugin.h:271
    +
    rfClipboard clipboard
    Definition: rdp_plugin.h:387
    +
    HANDLE event_handle
    Definition: rdp_plugin.h:383
    - - + + -
    GHashTable * object_table
    Definition: rdp_plugin.h:373
    +
    GHashTable * object_table
    Definition: rdp_plugin.h:374
    RemminaScaleMode
    Definition: types.h:142
    -
    CLIPRDR_FORMAT_DATA_REQUEST * pFormatDataRequest
    Definition: rdp_plugin.h:213
    -
    gint srcBpp
    Definition: rdp_plugin.h:363
    - +
    CLIPRDR_FORMAT_DATA_REQUEST * pFormatDataRequest
    Definition: rdp_plugin.h:214
    +
    gint srcBpp
    Definition: rdp_plugin.h:364
    + + - -
    gboolean connected
    Definition: rdp_plugin.h:343
    - - -
    RemminaScaleMode scale
    Definition: rdp_plugin.h:330
    -
    freerdp * instance
    Definition: rdp_plugin.h:327
    -
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:335
    - - -
    RemminaPluginRdpUiEeventType type
    Definition: rdp_plugin.h:301
    + +
    gboolean connected
    Definition: rdp_plugin.h:344
    + + +
    RemminaScaleMode scale
    Definition: rdp_plugin.h:331
    +
    freerdp * instance
    Definition: rdp_plugin.h:328
    +
    DispClientContext * dispcontext
    Definition: rdp_plugin.h:336
    + + +
    RemminaPluginRdpUiEeventType type
    Definition: rdp_plugin.h:302
    -
    GArray * pressed_keys
    Definition: rdp_plugin.h:379
    -
    rdpSettings * settings
    Definition: rdp_plugin.h:326
    -
    gint scale_height
    Definition: rdp_plugin.h:357
    - -
    Definition: rdp_plugin.h:314
    - - - +
    GArray * pressed_keys
    Definition: rdp_plugin.h:380
    +
    rdpSettings * settings
    Definition: rdp_plugin.h:327
    +
    gint scale_height
    Definition: rdp_plugin.h:358
    + +
    Definition: rdp_plugin.h:315
    + + + - +
    UINT32 format
    Definition: rdp_plugin.h:139
    UINT32 server_html_format_id
    Definition: rdp_plugin.h:148
    - -
    gboolean orphaned
    Definition: rdp_plugin.h:350
    - + +
    gboolean orphaned
    Definition: rdp_plugin.h:351
    +
    struct timeval clientformatdatarequest_tv
    Definition: rdp_plugin.h:151
    rdpGlyph glyph
    Definition: rdp_plugin.h:173
    -
    rdpContext context
    Definition: rdp_plugin.h:320
    +
    rdpContext context
    Definition: rdp_plugin.h:321
    -
    gint scale_width
    Definition: rdp_plugin.h:356
    -
    pthread_mutex_t ui_queue_mutex
    Definition: rdp_plugin.h:376
    - - - +
    gint scale_width
    Definition: rdp_plugin.h:357
    +
    pthread_mutex_t ui_queue_mutex
    Definition: rdp_plugin.h:377
    + + +
    cairo_surface_t * surface
    Definition: rdp_plugin.h:166
    enum rf_clipboard::@41 srv_clip_data_wait
    -
    gboolean sw_gdi
    Definition: rdp_plugin.h:354
    -
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:266
    -
    CliprdrClientContext * cliprdr
    Definition: rdp_plugin.h:334
    - - +
    gboolean sw_gdi
    Definition: rdp_plugin.h:355
    +
    RemminaPluginRdpUiType type
    Definition: rdp_plugin.h:267
    +
    CliprdrClientContext * cliprdr
    Definition: rdp_plugin.h:335
    + +
    diff --git a/public/search/all_14.js b/public/search/all_14.js index f2f1b068f..74cce3524 100644 --- a/public/search/all_14.js +++ b/public/search/all_14.js @@ -43,7 +43,7 @@ var searchData= ['toolbar_5fplacement_5ftop',['TOOLBAR_PLACEMENT_TOP',['../remmina__pref_8h.html#a4caf8d8f829279fba122163d961608a4a069738542d6980f9594299ab57221a7f',1,'remmina_pref.h']]], ['toolbarplace_5fsignal',['TOOLBARPLACE_SIGNAL',['../rcw_8c.html#adf764cbdea00d65edcd07bb9953ad2b7aa9941863b5633ddecb019f793f2f7668',1,'rcw.c']]], ['tooltip',['tooltip',['../struct___remmina_f_t_p_task.html#ac2b00cace6fd885736792664843be667',1,'_RemminaFTPTask']]], - ['top',['top',['../structremmina__plugin__rdp__ui__object.html#a8303068061e16a6a1878be52b6403070',1,'remmina_plugin_rdp_ui_object::top()'],['../structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764',1,'remmina_plugin_rdp_event::Top()']]], + ['top',['Top',['../structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764',1,'remmina_plugin_rdp_event::Top()'],['../structremmina__plugin__rdp__ui__object.html#a8303068061e16a6a1878be52b6403070',1,'remmina_plugin_rdp_ui_object::top()']]], ['transfer_5fclip_5fcond',['transfer_clip_cond',['../structrf__clipboard.html#acf5bf9da1a18e21409c4b10368f8dfd7',1,'rf_clipboard']]], ['transfer_5fclip_5fmutex',['transfer_clip_mutex',['../structrf__clipboard.html#a5c6be1637ed9e2ce72ffde2ed5400205',1,'rf_clipboard']]], ['translated_5fkeycode',['translated_keycode',['../structremmina__plugin__rdp__keymap__entry.html#aa63271d75f6dfda81584ddfb7c60b2a1',1,'remmina_plugin_rdp_keymap_entry']]], diff --git a/public/search/all_5.js b/public/search/all_5.js index 3ab301146..208c8d4b6 100644 --- a/public/search/all_5.js +++ b/public/search/all_5.js @@ -63,6 +63,7 @@ var searchData= ['export_5fhints',['export_hints',['../struct___remmina_file_plugin.html#ac4f2b0118490cede0577aaee9f2e0b5f',1,'_RemminaFilePlugin']]], ['export_5ftest_5ffunc',['export_test_func',['../struct___remmina_file_plugin.html#a0a3d5cd1b41d206d01ba52ab5ea554b6',1,'_RemminaFilePlugin']]], ['extended',['extended',['../structremmina__plugin__rdp__event.html#ae1093ce4f4e4e4b632ca4704ecfa698e',1,'remmina_plugin_rdp_event']]], + ['extended1',['extended1',['../structremmina__plugin__rdp__event.html#ac8c805908d492afeaeb6ef6ce6fad218',1,'remmina_plugin_rdp_event']]], ['extra_5fargs',['extra_args',['../struct___py_g_closure.html#a945c505b2e19499f4465e67bd6e39bda',1,'_PyGClosure']]], ['extrahardening',['extrahardening',['../remmina_8c.html#ae729d4262682c8674b8dd0135014810a',1,'extrahardening(): remmina.c'],['../remmina__pref_8h.html#ae729d4262682c8674b8dd0135014810a',1,'extrahardening(): remmina.c']]], ['entry_2dexample',['Entry-Example',['../md__builds__remmina_remmina-ci__remmina_8wiki__development__plugin-_development__python__entry-_example.html',1,'']]], diff --git a/public/search/variables_13.js b/public/search/variables_13.js index 12551c7b0..58ce55ace 100644 --- a/public/search/variables_13.js +++ b/public/search/variables_13.js @@ -25,7 +25,7 @@ var searchData= ['toolbar_5fplace',['toolbar_place',['../struct___remmina_connection_window_class.html#aeb815c87f3bddad607a61d293eef661d',1,'_RemminaConnectionWindowClass']]], ['toolbar_5fplacement',['toolbar_placement',['../struct___remmina_pref.html#a0242e9fcc63d6d24257f63fc23077133',1,'_RemminaPref']]], ['tooltip',['tooltip',['../struct___remmina_f_t_p_task.html#ac2b00cace6fd885736792664843be667',1,'_RemminaFTPTask']]], - ['top',['top',['../structremmina__plugin__rdp__ui__object.html#a8303068061e16a6a1878be52b6403070',1,'remmina_plugin_rdp_ui_object::top()'],['../structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764',1,'remmina_plugin_rdp_event::Top()']]], + ['top',['Top',['../structremmina__plugin__rdp__event.html#a880c2311bdcc07c03842427490da7764',1,'remmina_plugin_rdp_event::Top()'],['../structremmina__plugin__rdp__ui__object.html#a8303068061e16a6a1878be52b6403070',1,'remmina_plugin_rdp_ui_object::top()']]], ['transfer_5fclip_5fcond',['transfer_clip_cond',['../structrf__clipboard.html#acf5bf9da1a18e21409c4b10368f8dfd7',1,'rf_clipboard']]], ['transfer_5fclip_5fmutex',['transfer_clip_mutex',['../structrf__clipboard.html#a5c6be1637ed9e2ce72ffde2ed5400205',1,'rf_clipboard']]], ['translated_5fkeycode',['translated_keycode',['../structremmina__plugin__rdp__keymap__entry.html#aa63271d75f6dfda81584ddfb7c60b2a1',1,'remmina_plugin_rdp_keymap_entry']]], diff --git a/public/search/variables_5.js b/public/search/variables_5.js index 91b979f51..19e317faf 100644 --- a/public/search/variables_5.js +++ b/public/search/variables_5.js @@ -58,6 +58,7 @@ var searchData= ['export_5fhints',['export_hints',['../struct___remmina_file_plugin.html#ac4f2b0118490cede0577aaee9f2e0b5f',1,'_RemminaFilePlugin']]], ['export_5ftest_5ffunc',['export_test_func',['../struct___remmina_file_plugin.html#a0a3d5cd1b41d206d01ba52ab5ea554b6',1,'_RemminaFilePlugin']]], ['extended',['extended',['../structremmina__plugin__rdp__event.html#ae1093ce4f4e4e4b632ca4704ecfa698e',1,'remmina_plugin_rdp_event']]], + ['extended1',['extended1',['../structremmina__plugin__rdp__event.html#ac8c805908d492afeaeb6ef6ce6fad218',1,'remmina_plugin_rdp_event']]], ['extra_5fargs',['extra_args',['../struct___py_g_closure.html#a945c505b2e19499f4465e67bd6e39bda',1,'_PyGClosure']]], ['extrahardening',['extrahardening',['../remmina_8c.html#ae729d4262682c8674b8dd0135014810a',1,'extrahardening(): remmina.c'],['../remmina__pref_8h.html#ae729d4262682c8674b8dd0135014810a',1,'extrahardening(): remmina.c']]] ]; diff --git a/public/structregion.html b/public/structregion.html index a5f18d3dc..443c1a4fa 100644 --- a/public/structregion.html +++ b/public/structregion.html @@ -104,7 +104,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 261 of file rdp_plugin.h.

    +

    Definition at line 262 of file rdp_plugin.h.

    Field Documentation

    ◆ h

    @@ -118,7 +118,7 @@ Data Fields
    -

    Definition at line 262 of file rdp_plugin.h.

    +

    Definition at line 263 of file rdp_plugin.h.

    @@ -134,7 +134,7 @@ Data Fields
    -

    Definition at line 262 of file rdp_plugin.h.

    +

    Definition at line 263 of file rdp_plugin.h.

    @@ -150,7 +150,7 @@ Data Fields
    -

    Definition at line 262 of file rdp_plugin.h.

    +

    Definition at line 263 of file rdp_plugin.h.

    @@ -166,7 +166,7 @@ Data Fields
    -

    Definition at line 262 of file rdp_plugin.h.

    +

    Definition at line 263 of file rdp_plugin.h.

    diff --git a/public/structremmina__plugin__rdp__event.html b/public/structremmina__plugin__rdp__event.html index 8134ccddb..488dd9efe 100644 --- a/public/structremmina__plugin__rdp__event.html +++ b/public/structremmina__plugin__rdp__event.html @@ -105,6 +105,8 @@ Data Fields         UINT32   unicode_code   +      BOOL   extended1 +     }   key_event      struct { @@ -233,7 +235,7 @@ Data Fields
    -

    Definition at line 209 of file rdp_plugin.h.

    +

    Definition at line 210 of file rdp_plugin.h.

    @@ -249,7 +251,7 @@ Data Fields
    -

    Definition at line 221 of file rdp_plugin.h.

    +

    Definition at line 222 of file rdp_plugin.h.

    @@ -265,7 +267,7 @@ Data Fields
    -

    Definition at line 222 of file rdp_plugin.h.

    +

    Definition at line 223 of file rdp_plugin.h.

    @@ -281,7 +283,7 @@ Data Fields
    -

    Definition at line 223 of file rdp_plugin.h.

    +

    Definition at line 224 of file rdp_plugin.h.

    @@ -299,6 +301,22 @@ Data Fields

    Definition at line 195 of file rdp_plugin.h.

    + + + +

    ◆ extended1

    + +
    +
    + + + + +
    BOOL remmina_plugin_rdp_event::extended1
    +
    + +

    Definition at line 198 of file rdp_plugin.h.

    +
    @@ -313,7 +331,7 @@ Data Fields
    -

    Definition at line 200 of file rdp_plugin.h.

    +

    Definition at line 201 of file rdp_plugin.h.

    @@ -329,7 +347,7 @@ Data Fields
    -

    Definition at line 216 of file rdp_plugin.h.

    +

    Definition at line 217 of file rdp_plugin.h.

    @@ -345,7 +363,7 @@ Data Fields
    -

    Definition at line 220 of file rdp_plugin.h.

    +

    Definition at line 221 of file rdp_plugin.h.

    @@ -391,7 +409,7 @@ Data Fields
    -

    Definition at line 217 of file rdp_plugin.h.

    +

    Definition at line 218 of file rdp_plugin.h.

    @@ -435,7 +453,7 @@ Data Fields
    -

    Definition at line 213 of file rdp_plugin.h.

    +

    Definition at line 214 of file rdp_plugin.h.

    @@ -451,7 +469,7 @@ Data Fields
    -

    Definition at line 206 of file rdp_plugin.h.

    +

    Definition at line 207 of file rdp_plugin.h.

    @@ -467,7 +485,7 @@ Data Fields
    -

    Definition at line 225 of file rdp_plugin.h.

    +

    Definition at line 226 of file rdp_plugin.h.

    @@ -483,7 +501,7 @@ Data Fields
    -

    Definition at line 224 of file rdp_plugin.h.

    +

    Definition at line 225 of file rdp_plugin.h.

    @@ -499,7 +517,7 @@ Data Fields
    -

    Definition at line 210 of file rdp_plugin.h.

    +

    Definition at line 211 of file rdp_plugin.h.

    @@ -515,7 +533,7 @@ Data Fields
    -

    Definition at line 218 of file rdp_plugin.h.

    +

    Definition at line 219 of file rdp_plugin.h.

    @@ -579,7 +597,7 @@ Data Fields
    -

    Definition at line 219 of file rdp_plugin.h.

    +

    Definition at line 220 of file rdp_plugin.h.

    @@ -595,7 +613,7 @@ Data Fields
    -

    Definition at line 201 of file rdp_plugin.h.

    +

    Definition at line 202 of file rdp_plugin.h.

    @@ -611,7 +629,7 @@ Data Fields
    -

    Definition at line 202 of file rdp_plugin.h.

    +

    Definition at line 203 of file rdp_plugin.h.

    diff --git a/public/structremmina__plugin__rdp__event.js b/public/structremmina__plugin__rdp__event.js index 0f4629afc..a208f199e 100644 --- a/public/structremmina__plugin__rdp__event.js +++ b/public/structremmina__plugin__rdp__event.js @@ -8,6 +8,7 @@ var structremmina__plugin__rdp__event = [ "desktopScaleFactor", "structremmina__plugin__rdp__event.html#ad8c508c65e9f84c92f2f817eb7be2985", null ], [ "deviceScaleFactor", "structremmina__plugin__rdp__event.html#a30115ccc01062368d9b1189a0f378f57", null ], [ "extended", "structremmina__plugin__rdp__event.html#ae1093ce4f4e4e4b632ca4704ecfa698e", null ], + [ "extended1", "structremmina__plugin__rdp__event.html#ac8c805908d492afeaeb6ef6ce6fad218", null ], [ "flags", "structremmina__plugin__rdp__event.html#a7cee906e36975da3aadf6874da5da49c", null ], [ "Flags", "structremmina__plugin__rdp__event.html#ab1ee38a965bda260c81a55eedbd97114", null ], [ "height", "structremmina__plugin__rdp__event.html#a0ff77bb8ed355ac55a7dc4ab28a02649", null ], diff --git a/public/structremmina__plugin__rdp__keymap__entry.html b/public/structremmina__plugin__rdp__keymap__entry.html index 61841890c..e678c3a27 100644 --- a/public/structremmina__plugin__rdp__keymap__entry.html +++ b/public/structremmina__plugin__rdp__keymap__entry.html @@ -100,7 +100,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 314 of file rdp_plugin.h.

    +

    Definition at line 315 of file rdp_plugin.h.

    Field Documentation

    ◆ orig_keycode

    @@ -114,7 +114,7 @@ Data Fields
    -

    Definition at line 315 of file rdp_plugin.h.

    +

    Definition at line 316 of file rdp_plugin.h.

    @@ -130,7 +130,7 @@ Data Fields
    -

    Definition at line 316 of file rdp_plugin.h.

    +

    Definition at line 317 of file rdp_plugin.h.

    diff --git a/public/structremmina__plugin__rdp__ui__object.html b/public/structremmina__plugin__rdp__ui__object.html index f5a102aae..0a5feda51 100644 --- a/public/structremmina__plugin__rdp__ui__object.html +++ b/public/structremmina__plugin__rdp__ui__object.html @@ -176,7 +176,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 265 of file rdp_plugin.h.

    +

    Definition at line 266 of file rdp_plugin.h.

    Field Documentation

    ◆ @51

    @@ -204,7 +204,7 @@ Data Fields
    -

    Definition at line 291 of file rdp_plugin.h.

    +

    Definition at line 292 of file rdp_plugin.h.

    @@ -220,7 +220,7 @@ Data Fields
    -

    Definition at line 297 of file rdp_plugin.h.

    +

    Definition at line 298 of file rdp_plugin.h.

    @@ -250,7 +250,7 @@ Data Fields
    -

    Definition at line 268 of file rdp_plugin.h.

    +

    Definition at line 269 of file rdp_plugin.h.

    @@ -266,7 +266,7 @@ Data Fields
    -

    Definition at line 277 of file rdp_plugin.h.

    +

    Definition at line 278 of file rdp_plugin.h.

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

    Definition at line 298 of file rdp_plugin.h.

    +

    Definition at line 299 of file rdp_plugin.h.

    @@ -326,7 +326,7 @@ Data Fields
    -

    Definition at line 296 of file rdp_plugin.h.

    +

    Definition at line 297 of file rdp_plugin.h.

    @@ -342,7 +342,7 @@ Data Fields
    -

    Definition at line 290 of file rdp_plugin.h.

    +

    Definition at line 291 of file rdp_plugin.h.

    @@ -358,7 +358,7 @@ Data Fields
    -

    Definition at line 282 of file rdp_plugin.h.

    +

    Definition at line 283 of file rdp_plugin.h.

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

    Definition at line 284 of file rdp_plugin.h.

    +

    Definition at line 285 of file rdp_plugin.h.

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

    Definition at line 274 of file rdp_plugin.h.

    +

    Definition at line 275 of file rdp_plugin.h.

    @@ -420,7 +420,7 @@ Data Fields
    -

    Definition at line 278 of file rdp_plugin.h.

    +

    Definition at line 279 of file rdp_plugin.h.

    @@ -464,7 +464,7 @@ Data Fields
    -

    Definition at line 311 of file rdp_plugin.h.

    +

    Definition at line 312 of file rdp_plugin.h.

    @@ -480,7 +480,7 @@ Data Fields
    -

    Definition at line 309 of file rdp_plugin.h.

    +

    Definition at line 310 of file rdp_plugin.h.

    @@ -510,7 +510,7 @@ Data Fields
    -

    Definition at line 267 of file rdp_plugin.h.

    +

    Definition at line 268 of file rdp_plugin.h.

    @@ -526,7 +526,7 @@ Data Fields
    -

    Definition at line 270 of file rdp_plugin.h.

    +

    Definition at line 271 of file rdp_plugin.h.

    @@ -542,7 +542,7 @@ Data Fields
    -

    Definition at line 269 of file rdp_plugin.h.

    +

    Definition at line 270 of file rdp_plugin.h.

    @@ -558,7 +558,7 @@ Data Fields
    -

    Definition at line 295 of file rdp_plugin.h.

    +

    Definition at line 296 of file rdp_plugin.h.

    @@ -574,7 +574,7 @@ Data Fields
    -

    Definition at line 283 of file rdp_plugin.h.

    +

    Definition at line 284 of file rdp_plugin.h.

    @@ -590,7 +590,7 @@ Data Fields
    -

    Definition at line 266 of file rdp_plugin.h.

    +

    Definition at line 267 of file rdp_plugin.h.

    @@ -606,7 +606,7 @@ Data Fields
    -

    Definition at line 279 of file rdp_plugin.h.

    +

    Definition at line 280 of file rdp_plugin.h.

    @@ -622,7 +622,7 @@ Data Fields
    -

    Definition at line 294 of file rdp_plugin.h.

    +

    Definition at line 295 of file rdp_plugin.h.

    @@ -638,7 +638,7 @@ Data Fields
    -

    Definition at line 301 of file rdp_plugin.h.

    +

    Definition at line 302 of file rdp_plugin.h.

    @@ -654,7 +654,7 @@ Data Fields
    -

    Definition at line 273 of file rdp_plugin.h.

    +

    Definition at line 274 of file rdp_plugin.h.

    @@ -670,7 +670,7 @@ Data Fields
    -

    Definition at line 289 of file rdp_plugin.h.

    +

    Definition at line 290 of file rdp_plugin.h.

    @@ -686,7 +686,7 @@ Data Fields
    -

    Definition at line 304 of file rdp_plugin.h.

    +

    Definition at line 305 of file rdp_plugin.h.

    @@ -702,7 +702,7 @@ Data Fields
    -

    Definition at line 305 of file rdp_plugin.h.

    +

    Definition at line 306 of file rdp_plugin.h.

    diff --git a/public/structrf__context.html b/public/structrf__context.html index 921ff5677..2139db82f 100644 --- a/public/structrf__context.html +++ b/public/structrf__context.html @@ -213,7 +213,7 @@ Data Fields

    Detailed Description

    -

    Definition at line 319 of file rdp_plugin.h.

    +

    Definition at line 320 of file rdp_plugin.h.

    Member Enumeration Documentation

    ◆ anonymous enum

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

    Definition at line 392 of file rdp_plugin.h.

    +

    Definition at line 393 of file rdp_plugin.h.

    @@ -267,7 +267,7 @@ Data Fields
    -

    Definition at line 390 of file rdp_plugin.h.

    +

    Definition at line 391 of file rdp_plugin.h.

    @@ -283,7 +283,7 @@ Data Fields
    -

    Definition at line 368 of file rdp_plugin.h.

    +

    Definition at line 369 of file rdp_plugin.h.

    @@ -299,7 +299,7 @@ Data Fields
    -

    Definition at line 367 of file rdp_plugin.h.

    +

    Definition at line 368 of file rdp_plugin.h.

    @@ -315,7 +315,7 @@ Data Fields
    -

    Definition at line 386 of file rdp_plugin.h.

    +

    Definition at line 387 of file rdp_plugin.h.

    @@ -331,7 +331,7 @@ Data Fields
    -

    Definition at line 334 of file rdp_plugin.h.

    +

    Definition at line 335 of file rdp_plugin.h.

    @@ -347,7 +347,7 @@ Data Fields
    -

    Definition at line 370 of file rdp_plugin.h.

    +

    Definition at line 371 of file rdp_plugin.h.

    @@ -363,7 +363,7 @@ Data Fields
    -

    Definition at line 343 of file rdp_plugin.h.

    +

    Definition at line 344 of file rdp_plugin.h.

    @@ -379,7 +379,7 @@ Data Fields
    -

    Definition at line 320 of file rdp_plugin.h.

    +

    Definition at line 321 of file rdp_plugin.h.

    @@ -395,7 +395,7 @@ Data Fields
    -

    Definition at line 360 of file rdp_plugin.h.

    +

    Definition at line 361 of file rdp_plugin.h.

    @@ -411,7 +411,7 @@ Data Fields
    -

    Definition at line 335 of file rdp_plugin.h.

    +

    Definition at line 336 of file rdp_plugin.h.

    @@ -427,7 +427,7 @@ Data Fields
    -

    Definition at line 364 of file rdp_plugin.h.

    +

    Definition at line 365 of file rdp_plugin.h.

    @@ -443,7 +443,7 @@ Data Fields
    -

    Definition at line 355 of file rdp_plugin.h.

    +

    Definition at line 356 of file rdp_plugin.h.

    @@ -459,7 +459,7 @@ Data Fields
    -

    Definition at line 338 of file rdp_plugin.h.

    +

    Definition at line 339 of file rdp_plugin.h.

    @@ -475,7 +475,7 @@ Data Fields
    -

    Definition at line 382 of file rdp_plugin.h.

    +

    Definition at line 383 of file rdp_plugin.h.

    @@ -491,7 +491,7 @@ Data Fields
    -

    Definition at line 381 of file rdp_plugin.h.

    +

    Definition at line 382 of file rdp_plugin.h.

    @@ -507,7 +507,7 @@ Data Fields
    -

    Definition at line 380 of file rdp_plugin.h.

    +

    Definition at line 381 of file rdp_plugin.h.

    @@ -523,7 +523,7 @@ Data Fields
    -

    Definition at line 327 of file rdp_plugin.h.

    +

    Definition at line 328 of file rdp_plugin.h.

    @@ -539,7 +539,7 @@ Data Fields
    -

    Definition at line 344 of file rdp_plugin.h.

    +

    Definition at line 345 of file rdp_plugin.h.

    @@ -555,7 +555,7 @@ Data Fields
    -

    Definition at line 388 of file rdp_plugin.h.

    +

    Definition at line 389 of file rdp_plugin.h.

    @@ -571,7 +571,7 @@ Data Fields
    -

    Definition at line 383 of file rdp_plugin.h.

    +

    Definition at line 384 of file rdp_plugin.h.

    @@ -587,7 +587,7 @@ Data Fields
    -

    Definition at line 384 of file rdp_plugin.h.

    +

    Definition at line 385 of file rdp_plugin.h.

    @@ -603,7 +603,7 @@ Data Fields
    -

    Definition at line 372 of file rdp_plugin.h.

    +

    Definition at line 373 of file rdp_plugin.h.

    @@ -619,7 +619,7 @@ Data Fields
    -

    Definition at line 373 of file rdp_plugin.h.

    +

    Definition at line 374 of file rdp_plugin.h.

    @@ -635,7 +635,7 @@ Data Fields
    -

    Definition at line 350 of file rdp_plugin.h.

    +

    Definition at line 351 of file rdp_plugin.h.

    @@ -665,7 +665,7 @@ Data Fields
    -

    Definition at line 379 of file rdp_plugin.h.

    +

    Definition at line 380 of file rdp_plugin.h.

    @@ -681,7 +681,7 @@ Data Fields
    -

    Definition at line 323 of file rdp_plugin.h.

    +

    Definition at line 324 of file rdp_plugin.h.

    @@ -697,7 +697,7 @@ Data Fields
    -

    Definition at line 337 of file rdp_plugin.h.

    +

    Definition at line 338 of file rdp_plugin.h.

    @@ -713,7 +713,7 @@ Data Fields
    -

    Definition at line 341 of file rdp_plugin.h.

    +

    Definition at line 342 of file rdp_plugin.h.

    @@ -729,7 +729,7 @@ Data Fields
    -

    Definition at line 339 of file rdp_plugin.h.

    +

    Definition at line 340 of file rdp_plugin.h.

    @@ -745,7 +745,7 @@ Data Fields
    -

    Definition at line 351 of file rdp_plugin.h.

    +

    Definition at line 352 of file rdp_plugin.h.

    @@ -761,7 +761,7 @@ Data Fields
    -

    Definition at line 352 of file rdp_plugin.h.

    +

    Definition at line 353 of file rdp_plugin.h.

    @@ -777,7 +777,7 @@ Data Fields
    -

    Definition at line 329 of file rdp_plugin.h.

    +

    Definition at line 330 of file rdp_plugin.h.

    @@ -793,7 +793,7 @@ Data Fields
    -

    Definition at line 330 of file rdp_plugin.h.

    +

    Definition at line 331 of file rdp_plugin.h.

    @@ -809,7 +809,7 @@ Data Fields
    -

    Definition at line 357 of file rdp_plugin.h.

    +

    Definition at line 358 of file rdp_plugin.h.

    @@ -825,7 +825,7 @@ Data Fields
    -

    Definition at line 356 of file rdp_plugin.h.

    +

    Definition at line 357 of file rdp_plugin.h.

    @@ -841,7 +841,7 @@ Data Fields
    -

    Definition at line 358 of file rdp_plugin.h.

    +

    Definition at line 359 of file rdp_plugin.h.

    @@ -857,7 +857,7 @@ Data Fields
    -

    Definition at line 359 of file rdp_plugin.h.

    +

    Definition at line 360 of file rdp_plugin.h.

    @@ -873,7 +873,7 @@ Data Fields
    -

    Definition at line 369 of file rdp_plugin.h.

    +

    Definition at line 370 of file rdp_plugin.h.

    @@ -889,7 +889,7 @@ Data Fields
    -

    Definition at line 326 of file rdp_plugin.h.

    +

    Definition at line 327 of file rdp_plugin.h.

    @@ -905,7 +905,7 @@ Data Fields
    -

    Definition at line 363 of file rdp_plugin.h.

    +

    Definition at line 364 of file rdp_plugin.h.

    @@ -921,7 +921,7 @@ Data Fields
    -

    Definition at line 345 of file rdp_plugin.h.

    +

    Definition at line 346 of file rdp_plugin.h.

    @@ -937,7 +937,7 @@ Data Fields
    -

    Definition at line 366 of file rdp_plugin.h.

    +

    Definition at line 367 of file rdp_plugin.h.

    @@ -953,7 +953,7 @@ Data Fields
    -

    Definition at line 354 of file rdp_plugin.h.

    +

    Definition at line 355 of file rdp_plugin.h.

    @@ -969,7 +969,7 @@ Data Fields
    -

    Definition at line 332 of file rdp_plugin.h.

    +

    Definition at line 333 of file rdp_plugin.h.

    @@ -985,7 +985,7 @@ Data Fields
    -

    Definition at line 377 of file rdp_plugin.h.

    +

    Definition at line 378 of file rdp_plugin.h.

    @@ -1001,7 +1001,7 @@ Data Fields
    -

    Definition at line 375 of file rdp_plugin.h.

    +

    Definition at line 376 of file rdp_plugin.h.

    @@ -1017,7 +1017,7 @@ Data Fields
    -

    Definition at line 376 of file rdp_plugin.h.

    +

    Definition at line 377 of file rdp_plugin.h.

    @@ -1033,7 +1033,7 @@ Data Fields
    -

    Definition at line 361 of file rdp_plugin.h.

    +

    Definition at line 362 of file rdp_plugin.h.

    @@ -1049,7 +1049,7 @@ Data Fields
    -

    Definition at line 331 of file rdp_plugin.h.

    +

    Definition at line 332 of file rdp_plugin.h.

    @@ -1065,7 +1065,7 @@ Data Fields
    -

    Definition at line 365 of file rdp_plugin.h.

    +

    Definition at line 366 of file rdp_plugin.h.

    -- cgit v1.2.3