From c4dcb173e7f4df5323086c9b4f92d2f0db8c3da6 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Wed, 27 Jan 2021 15:42:41 +0100 Subject: [PATCH 1/8] Adding multi monitor support --- plugins/rdp/CMakeLists.txt | 2 + plugins/rdp/rdp_event.c | 364 +++++++++++++++++----------------- plugins/rdp/rdp_plugin.c | 162 +++++++++++---- plugins/rdp/rdp_plugin.h | 5 + src/rcw.c | 37 +++- src/remmina_protocol_widget.c | 10 + src/remmina_protocol_widget.h | 1 + 7 files changed, 357 insertions(+), 224 deletions(-) diff --git a/plugins/rdp/CMakeLists.txt b/plugins/rdp/CMakeLists.txt index e39fbfc6d7..0e28b31dd0 100644 --- a/plugins/rdp/CMakeLists.txt +++ b/plugins/rdp/CMakeLists.txt @@ -52,6 +52,8 @@ set(REMMINA_PLUGIN_RDP_SRCS rdp_graphics.h rdp_cliprdr.c rdp_cliprdr.h + rdp_monitor.c + rdp_monitor.h rdp_channels.c rdp_channels.h ) diff --git a/plugins/rdp/rdp_event.c b/plugins/rdp/rdp_event.c index 66d60534c8..fcd0225d41 100644 --- a/plugins/rdp/rdp_event.c +++ b/plugins/rdp/rdp_event.c @@ -37,14 +37,15 @@ */ #include "rdp_plugin.h" -#include "rdp_event.h" #include "rdp_cliprdr.h" +#include "rdp_event.h" +#include "rdp_monitor.h" #include "rdp_settings.h" #include <gdk/gdkkeysyms.h> #include <cairo/cairo-xlib.h> #include <freerdp/locale/keyboard.h> -static gboolean remmina_rdp_event_on_map (GtkWindow *window, GdkEvent *event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_map(GtkWindow *window, GdkEvent *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); rfContext* rfi = GET_PLUGIN_DATA(gp); @@ -61,7 +62,7 @@ static gboolean remmina_rdp_event_on_map (GtkWindow *window, GdkEvent *event, R return FALSE; } -static gboolean remmina_rdp_event_on_unmap (GtkWindow *window, GdkEvent *event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_unmap(GtkWindow *window, GdkEvent *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); rfContext* rfi = GET_PLUGIN_DATA(gp); @@ -78,11 +79,11 @@ static gboolean remmina_rdp_event_on_unmap (GtkWindow *window, GdkEvent *event, return FALSE; } -static gboolean remmina_rdp_event_on_focus_in(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); - rdpInput* input; + rfContext *rfi = GET_PLUGIN_DATA(gp); + rdpInput *input; GdkModifierType state; #if GTK_CHECK_VERSION(3, 20, 0) @@ -107,15 +108,12 @@ static gboolean remmina_rdp_event_on_focus_in(GtkWidget* widget, GdkEventKey* ev #endif gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state); - if (state & GDK_LOCK_MASK) { + if (state & GDK_LOCK_MASK) toggle_keys_state |= KBD_SYNC_CAPS_LOCK; - } - if (state & GDK_MOD2_MASK) { + if (state & GDK_MOD2_MASK) toggle_keys_state |= KBD_SYNC_NUM_LOCK; - } - if (state & GDK_MOD5_MASK) { + if (state & GDK_MOD5_MASK) toggle_keys_state |= KBD_SYNC_SCROLL_LOCK; - } input->SynchronizeEvent(input, toggle_keys_state); input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F); @@ -123,11 +121,11 @@ static gboolean remmina_rdp_event_on_focus_in(GtkWidget* widget, GdkEventKey* ev return FALSE; } -void remmina_rdp_event_event_push(RemminaProtocolWidget* gp, const RemminaPluginRdpEvent* e) +void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); - RemminaPluginRdpEvent* event; + rfContext *rfi = GET_PLUGIN_DATA(gp); + RemminaPluginRdpEvent *event; /* Called by the main GTK thread to send an event to the libfreerdp thread */ @@ -143,10 +141,10 @@ void remmina_rdp_event_event_push(RemminaProtocolWidget* gp, const RemminaPlugin } } -static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget* gp) +static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event = { 0 }; int i; @@ -164,18 +162,18 @@ static void remmina_rdp_event_release_all_keys(RemminaProtocolWidget* gp) g_array_set_size(rfi->pressed_keys, 0); } -static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, RemminaPluginRdpEvent rdp_event) +static void remmina_rdp_event_release_key(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event) { TRACE_CALL(__func__); gint i; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event_2 = { 0 }; rdp_event_2.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE || rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE_UNICODE) && - rdp_event.key_event.up ) { + rdp_event.key_event.up) { /* Unregister the keycode only */ for (i = 0; i < rfi->pressed_keys->len; i++) { rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i); @@ -193,25 +191,24 @@ static void remmina_rdp_event_release_key(RemminaProtocolWidget* gp, RemminaPlug static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (!rdp_event.key_event.key_code) return; - if (rdp_event.key_event.up) { + if (rdp_event.key_event.up) remmina_rdp_event_release_key(gp, rdp_event); - } else { + else g_array_append_val(rfi->pressed_keys, rdp_event); - } } -static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gint* y, gint* w, gint* h) +static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h) { TRACE_CALL(__func__); gint width, height; gint sx, sy, sw, sh; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface) return; @@ -234,16 +231,16 @@ static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gin /* We have to extend the scaled region one scaled pixel, to avoid gaps */ sx = MIN(MAX(0, (*x) * rfi->scale_width / width - - rfi->scale_width / width - 2), rfi->scale_width - 1); + - rfi->scale_width / width - 2), rfi->scale_width - 1); sy = MIN(MAX(0, (*y) * rfi->scale_height / height - - rfi->scale_height / height - 2), rfi->scale_height - 1); + - rfi->scale_height / height - 2), rfi->scale_height - 1); sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width - + rfi->scale_width / width + 4); + + rfi->scale_width / width + 4); sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height - + rfi->scale_height / height + 4); + + rfi->scale_height / height + 4); *x = sx; *y = sy; @@ -251,13 +248,13 @@ static void remmina_rdp_event_scale_area(RemminaProtocolWidget* gp, gint* x, gin *h = sh; } -void remmina_rdp_event_update_regions(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +void remmina_rdp_event_update_regions(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); gint x, y, w, h, i; - for(i = 0; i < ui->reg.ninvalid; i++) { + for (i = 0; i < ui->reg.ninvalid; i++) { x = ui->reg.ureg[i].x; y = ui->reg.ureg[i].y; w = ui->reg.ureg[i].w; @@ -271,10 +268,10 @@ void remmina_rdp_event_update_regions(RemminaProtocolWidget* gp, RemminaPluginRd g_free(ui->reg.ureg); } -void remmina_rdp_event_update_rect(RemminaProtocolWidget* gp, gint x, gint y, gint w, gint h) +void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) remmina_rdp_event_scale_area(gp, &x, &y, &w, &h); @@ -282,13 +279,13 @@ void remmina_rdp_event_update_rect(RemminaProtocolWidget* gp, gint x, gint y, gi gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h); } -static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget* gp) +static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); GtkAllocation a; gint rdwidth, rdheight; gint gpwidth, gpheight; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); gtk_widget_get_allocation(GTK_WIDGET(gp), &a); gpwidth = a.width; @@ -305,19 +302,18 @@ static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget* gp) rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth; rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight; } - }else { + } else { rfi->scale_width = 0; rfi->scale_height = 0; rfi->scale_x = 0; rfi->scale_y = 0; } - } -static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); guint width, height; gchar *msg; cairo_text_extents_t extents; @@ -334,7 +330,7 @@ static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, R /* Draw text */ msg = g_strdup_printf(_("Reconnection attempt %d of %d…"), - rfi->reconnect_nattempt, rfi->reconnect_maxattempts); + rfi->reconnect_nattempt, rfi->reconnect_maxattempts); cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(context, 24); @@ -343,8 +339,7 @@ static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, R cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2); cairo_show_text(context, msg); g_free(msg); - - }else { + } else { /* Standard drawing: We copy the surface from RDP */ if (!rfi->surface) @@ -362,10 +357,10 @@ static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, R return TRUE; } -static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event = { 0 }; GtkAllocation a; @@ -380,6 +375,12 @@ static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget* rfi->delayed_monitor_layout_handler = 0; gint gpwidth, gpheight, prevwidth, prevheight; + gchar *monitorids = NULL; + guint32 maxwidth = 0; + guint32 maxheight = 0; + remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight); + + REMMINA_PLUGIN_DEBUG("Sending preconfigured monitor layout"); if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) { remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor); gtk_widget_get_allocation(GTK_WIDGET(gp), &a); @@ -388,10 +389,7 @@ static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget* prevwidth = remmina_plugin_service->protocol_plugin_get_width(gp); prevheight = remmina_plugin_service->protocol_plugin_get_height(gp); - if ((gpwidth != prevwidth || gpheight != prevheight) && - gpwidth >= 200 && gpwidth < 8192 && - gpheight >= 200 && gpheight < 8192 - ) { + if ((gpwidth != prevwidth || gpheight != prevheight) && gpwidth >= 200 && gpheight >= 200) { if (rfi->rdpgfxchan) { /* Workaround for FreeRDP issue #5417 */ if (gpwidth < AVC_MIN_DESKTOP_WIDTH) @@ -400,40 +398,59 @@ static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget* gpheight = AVC_MIN_DESKTOP_HEIGHT; } rdp_event.type = REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT; - rdp_event.monitor_layout.width = gpwidth; - rdp_event.monitor_layout.height = gpheight; - rdp_event.monitor_layout.desktopOrientation = desktopOrientation; - rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor; - rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor; - remmina_rdp_event_event_push(gp, &rdp_event); + for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { + REMMINA_PLUGIN_DEBUG("Sending diplay layout n° %d", i); + rdp_event.monitor_layout.Flags = rfi->settings->MonitorDefArray[i].is_primary; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags); + rdp_event.monitor_layout.Left = rfi->settings->MonitorDefArray[i].x; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left); + rdp_event.monitor_layout.Top = rfi->settings->MonitorDefArray[i].y; + //rdp_event.monitor_layout.Top = rfi->settings->MonitorDefArray[0].y; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top); + rdp_event.monitor_layout.width = rfi->settings->MonitorDefArray[i].width; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width); + rdp_event.monitor_layout.height = rfi->settings->MonitorDefArray[i].height; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height); + rdp_event.monitor_layout.physicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth); + rdp_event.monitor_layout.physicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight); + rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation); + rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor); + rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor; + remmina_rdp_event_event_push(gp, &rdp_event); + } } } + g_free(monitorids); + return FALSE; } -void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget* gp) +void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (!rfi || !rfi->connected || rfi->is_reconnecting) return; if (rfi->delayed_monitor_layout_handler) { g_source_remove(rfi->delayed_monitor_layout_handler); rfi->delayed_monitor_layout_handler = 0; } - if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) { + if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp); - } } -static gboolean remmina_rdp_event_on_configure(GtkWidget* widget, GdkEventConfigure* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); /* Called when gp changes its size or position */ - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (!rfi || !rfi->connected || rfi->is_reconnecting) return FALSE; @@ -446,10 +463,10 @@ static gboolean remmina_rdp_event_on_configure(GtkWidget* widget, GdkEventConfig return FALSE; } -static void remmina_rdp_event_translate_pos(RemminaProtocolWidget* gp, int ix, int iy, UINT16* ox, UINT16* oy) +static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); /* * Translate a position from local window coordinates (ix,iy) to @@ -462,16 +479,16 @@ static void remmina_rdp_event_translate_pos(RemminaProtocolWidget* gp, int ix, i if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) { *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width); *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height); - }else { + } else { *ox = (UINT16)ix; *oy = (UINT16)iy; } } -static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget* gp, int ix, int iy, int* ox, int* oy) +static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); /* * Translate a position from RDP coordinates (ix,iy) to @@ -484,13 +501,13 @@ static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidge if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) { *ox = (ix * rfi->scale_width) / remmina_plugin_service->protocol_plugin_get_width(gp); *oy = (iy * rfi->scale_height) / remmina_plugin_service->protocol_plugin_get_height(gp); - }else { + } else { *ox = ix; *oy = iy; } } -static gboolean remmina_rdp_event_on_motion(GtkWidget* widget, GdkEventMotion* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); RemminaPluginRdpEvent rdp_event = { 0 }; @@ -505,7 +522,7 @@ static gboolean remmina_rdp_event_on_motion(GtkWidget* widget, GdkEventMotion* e return TRUE; } -static gboolean remmina_rdp_event_on_button(GtkWidget* widget, GdkEventButton* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); gint flag; @@ -561,7 +578,7 @@ static gboolean remmina_rdp_event_on_button(GtkWidget* widget, GdkEventButton* e return TRUE; } -static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); gint flag; @@ -574,7 +591,6 @@ static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* e /* See [MS-RDPBCGR] TS_POINTER_EVENT and WM_MOUSEWHEEL message */ switch (event->direction) { - case GDK_SCROLL_UP: flag = PTR_FLAGS_WHEEL | 0x0078; // 120 is one scroll unit defined in WM_MOUSEWHEEL break; @@ -619,7 +635,7 @@ static gboolean remmina_rdp_event_on_scroll(GtkWidget* widget, GdkEventScroll* e return TRUE; } -static void remmina_rdp_event_init_keymap(rfContext* rfi, const gchar* strmap) +static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap) { long int v1, v2; const char *s; @@ -632,7 +648,7 @@ static void remmina_rdp_event_init_keymap(rfContext* rfi, const gchar* strmap) } s = strmap; rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry)); - while(1) { + while (1) { v1 = strtol(s, &endptr, 10); if (endptr == s) break; s = endptr; @@ -651,17 +667,16 @@ static void remmina_rdp_event_init_keymap(rfContext* rfi, const gchar* strmap) g_array_unref(rfi->keymap); rfi->keymap = NULL; } - } -static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp) { TRACE_CALL(__func__); guint32 unicode_keyval; guint16 hardware_keycode; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); RemminaPluginRdpEvent rdp_event; - RemminaPluginRdpKeymapEntry* kep; + RemminaPluginRdpKeymapEntry *kep; DWORD scancode = 0; int ik; @@ -671,9 +686,9 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, #ifdef ENABLE_GTK_INSPECTOR_KEY /* GTK inspector key is propagated up. Disabled by default. * enable it by defining ENABLE_GTK_INSPECTOR_KEY */ - if ( ( event->state & GDK_CONTROL_MASK ) != 0 && ( event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D ) ) { + if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D)) return FALSE; - } + #endif rdp_event.type = REMMINA_RDP_EVENT_TYPE_SCANCODE; @@ -705,7 +720,7 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, if (!rfi->use_client_keymap) { hardware_keycode = event->hardware_keycode; if (rfi->keymap) { - for(ik = 0; ik < rfi->keymap->len; ik++) { + for (ik = 0; ik < rfi->keymap->len; ik++) { kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik); if (hardware_keycode == kep->orig_keycode) { hardware_keycode = kep->translated_keycode; @@ -731,7 +746,7 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event, * - The rest as Unicode char */ if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad… - event->hardware_keycode == 0x41 || // Spacebar + event->hardware_keycode == 0x41 || // Spacebar unicode_keyval == 0 || // Impossible to translate (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode() ) { @@ -761,7 +776,7 @@ gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *ev /* Signal handler for GTK clipboard owner-change */ TRACE_CALL(__func__); RemminaPluginRdpEvent rdp_event = { 0 }; - CLIPRDR_FORMAT_LIST* pFormatList; + CLIPRDR_FORMAT_LIST *pFormatList; /* Usually "owner-change" is fired when a user pres "COPY" on the client * OR when this plugin calls gtk_clipboard_set_with_owner() @@ -774,11 +789,11 @@ gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *ev if (rfi) remmina_rdp_clipboard_abort_transfer(rfi); - if (gtk_clipboard_get_owner(gtkClipboard) != (GObject*)gp) { + if (gtk_clipboard_get_owner(gtkClipboard) != (GObject *)gp) { /* To do: avoid this when the new owner is another remmina protocol widget of * the same remmina application */ REMMINA_PLUGIN_DEBUG(" new owner is different than me: new=%p me=%p. Sending local clipboard format list to server.", - gtk_clipboard_get_owner(gtkClipboard), (GObject*)gp); + gtk_clipboard_get_owner(gtkClipboard), (GObject *)gp); pFormatList = remmina_rdp_cliprdr_get_client_format_list(gp); rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD_SEND_CLIENT_FORMAT_LIST; @@ -790,14 +805,14 @@ gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *ev return TRUE; } -void remmina_rdp_event_init(RemminaProtocolWidget* gp) +void remmina_rdp_event_init(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - gchar* s; + gchar *s; gint flags; - rfContext* rfi = GET_PLUGIN_DATA(gp); - GtkClipboard* clipboard; - RemminaFile* remminafile; + rfContext *rfi = GET_PLUGIN_DATA(gp); + GtkClipboard *clipboard; + RemminaFile *remminafile; if (!rfi) return; remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); @@ -807,12 +822,12 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp) gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area); gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK -#if GTK_CHECK_VERSION(3,4,0) - | GDK_SMOOTH_SCROLL_MASK + | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK +#if GTK_CHECK_VERSION(3, 4, 0) + | GDK_SMOOTH_SCROLL_MASK #endif - | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK); + | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK); gtk_widget_set_can_focus(rfi->drawing_area, TRUE); remmina_plugin_service->protocol_plugin_register_hostkey(gp, rfi->drawing_area); @@ -824,32 +839,31 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp) /* Read special keymap from profile file, if exists */ remmina_rdp_event_init_keymap(rfi, remmina_plugin_service->pref_get_value("rdp_map_keycode")); - if (rfi->use_client_keymap && rfi->keymap) { + if (rfi->use_client_keymap && rfi->keymap) fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keuboard mapping' enabled\n"); - } g_signal_connect(G_OBJECT(rfi->drawing_area), "draw", - G_CALLBACK(remmina_rdp_event_on_draw), gp); + G_CALLBACK(remmina_rdp_event_on_draw), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event", - G_CALLBACK(remmina_rdp_event_on_configure), gp); + G_CALLBACK(remmina_rdp_event_on_configure), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event", - G_CALLBACK(remmina_rdp_event_on_motion), gp); + G_CALLBACK(remmina_rdp_event_on_motion), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event", - G_CALLBACK(remmina_rdp_event_on_button), gp); + G_CALLBACK(remmina_rdp_event_on_button), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event", - G_CALLBACK(remmina_rdp_event_on_button), gp); + G_CALLBACK(remmina_rdp_event_on_button), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event", - G_CALLBACK(remmina_rdp_event_on_scroll), gp); + G_CALLBACK(remmina_rdp_event_on_scroll), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event", - G_CALLBACK(remmina_rdp_event_on_key), gp); + G_CALLBACK(remmina_rdp_event_on_key), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event", - G_CALLBACK(remmina_rdp_event_on_key), gp); + G_CALLBACK(remmina_rdp_event_on_key), gp); g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event", - G_CALLBACK(remmina_rdp_event_on_focus_in), gp); + G_CALLBACK(remmina_rdp_event_on_focus_in), gp); g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "map-event", - G_CALLBACK(remmina_rdp_event_on_map), gp); + G_CALLBACK(remmina_rdp_event_on_map), gp); g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "unmap-event", - G_CALLBACK(remmina_rdp_event_on_unmap), gp); + G_CALLBACK(remmina_rdp_event_on_unmap), gp); if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) { clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD); @@ -866,13 +880,12 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp) rfi->event_pipe[0] = -1; rfi->event_pipe[1] = -1; rfi->event_handle = NULL; - }else { + } else { flags = fcntl(rfi->event_pipe[0], F_GETFL, 0); fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK); rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ); - if (!rfi->event_handle) { + if (!rfi->event_handle) g_print("CreateFileDescriptorEvent() failed\n"); - } } rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free); @@ -881,14 +894,14 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp) #if GTK_CHECK_VERSION(3, 22, 0) GdkVisual *visual = gdk_screen_get_system_visual( - gdk_display_get_default_screen(rfi->display)); - rfi->bpp = gdk_visual_get_depth (visual); + gdk_display_get_default_screen(rfi->display)); + rfi->bpp = gdk_visual_get_depth(visual); #else rfi->bpp = gdk_visual_get_best_depth(); #endif } -void remmina_rdp_event_free_event(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* obj) +void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj) { TRACE_CALL(__func__); @@ -904,11 +917,11 @@ void remmina_rdp_event_free_event(RemminaProtocolWidget* gp, RemminaPluginRdpUiO g_free(obj); } -void remmina_rdp_event_uninit(RemminaProtocolWidget* gp) +void remmina_rdp_event_uninit(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); - RemminaPluginRdpUiObject* ui; + rfContext *rfi = GET_PLUGIN_DATA(gp); + RemminaPluginRdpUiObject *ui; if (!rfi) return; @@ -925,9 +938,8 @@ void remmina_rdp_event_uninit(RemminaProtocolWidget* gp) g_source_remove(rfi->ui_handler); rfi->ui_handler = 0; } - while ((ui = (RemminaPluginRdpUiObject*)g_async_queue_try_pop(rfi->ui_queue)) != NULL) { + while ((ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue)) != NULL) remmina_rdp_event_free_event(gp, ui); - } if (rfi->surface) { cairo_surface_destroy(rfi->surface); rfi->surface = NULL; @@ -955,10 +967,10 @@ void remmina_rdp_event_uninit(RemminaProtocolWidget* gp) close(rfi->event_pipe[1]); } -static void remmina_rdp_event_create_cairo_surface(rfContext* rfi) +static void remmina_rdp_event_create_cairo_surface(rfContext *rfi) { int stride; - rdpGdi* gdi; + rdpGdi *gdi; if (!rfi) return; @@ -973,33 +985,33 @@ static void remmina_rdp_event_create_cairo_surface(rfContext* rfi) rfi->surface = NULL; } stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width); - rfi->surface = cairo_image_surface_create_for_data((unsigned char*)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride); + rfi->surface = cairo_image_surface_create_for_data((unsigned char *)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride); } -void remmina_rdp_event_update_scale(RemminaProtocolWidget* gp) +void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); gint width, height; - rdpGdi* gdi; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rdpGdi *gdi; + rfContext *rfi = GET_PLUGIN_DATA(gp); width = remmina_plugin_service->protocol_plugin_get_width(gp); height = remmina_plugin_service->protocol_plugin_get_height(gp); - gdi = ((rdpContext*)rfi)->gdi; + gdi = ((rdpContext *)rfi)->gdi; rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp); /* See if we also must rellocate rfi->surface with different width and height, * this usually happens after a DesktopResize RDP event*/ - if ( rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width || - cairo_image_surface_get_height(rfi->surface) != gdi->height) ) { + if (rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width || + cairo_image_surface_get_height(rfi->surface) != gdi->height)) { /* Destroys and recreate rfi->surface with new width and height */ cairo_surface_destroy(rfi->surface); rfi->surface = NULL; remmina_rdp_event_create_cairo_surface(rfi); - } else if ( rfi->surface == NULL ) { + } else if (rfi->surface == NULL) { remmina_rdp_event_create_cairo_surface(rfi); } @@ -1012,21 +1024,20 @@ void remmina_rdp_event_update_scale(RemminaProtocolWidget* gp) remmina_rdp_event_update_scale_factor(gp); - if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED || rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) { + if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED || rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */ - gtk_widget_set_size_request(rfi->drawing_area, -1, -1 ); - }else { + gtk_widget_set_size_request(rfi->drawing_area, -1, -1); + else /* In non scaled mode, the plugins forces dimensions of drawing area */ gtk_widget_set_size_request(rfi->drawing_area, width, height); - } remmina_plugin_service->protocol_plugin_update_align(gp); } -static void remmina_rdp_event_connected(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); - rdpGdi* gdi; + rfContext *rfi = GET_PLUGIN_DATA(gp); + rdpGdi *gdi; gdi = ((rdpContext *)rfi)->gdi; @@ -1037,27 +1048,27 @@ static void remmina_rdp_event_connected(RemminaProtocolWidget* gp, RemminaPlugin remmina_rdp_event_update_scale(gp); - remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); } -static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE); } -static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - GdkPixbuf* pixbuf; - rfContext* rfi = GET_PLUGIN_DATA(gp); - rdpPointer* pointer = (rdpPointer*)ui->cursor.pointer; - cairo_surface_t* surface; - UINT8* data = malloc(pointer->width * pointer->height * 4); + GdkPixbuf *pixbuf; + rfContext *rfi = GET_PLUGIN_DATA(gp); + rdpPointer *pointer = (rdpPointer *)ui->cursor.pointer; + cairo_surface_t *surface; + UINT8 *data = malloc(pointer->width * pointer->height * 4); if (!freerdp_image_copy_from_pointer_data( - (BYTE*)data, PIXEL_FORMAT_BGRA32, + (BYTE *)data, PIXEL_FORMAT_BGRA32, pointer->width * 4, 0, 0, pointer->width, pointer->height, pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData, pointer->lengthAndMask, @@ -1070,13 +1081,13 @@ static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget* gp, RemminaPl pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height); cairo_surface_destroy(surface); free(data); - ((rfPointer*)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos); + ((rfPointer *)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos); g_object_unref(pixbuf); return TRUE; } -static void remmina_rdp_event_free_cursor(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); g_object_unref(ui->cursor.pointer->cursor); @@ -1094,7 +1105,7 @@ static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gi GdkDeviceManager *manager; #endif GdkDevice *dev; - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (rfi == NULL) return FALSE; @@ -1120,10 +1131,10 @@ static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gi return TRUE; } -static void remmina_rdp_event_cursor(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); switch (ui->cursor.type) { case REMMINA_RDP_POINTER_NEW: @@ -1145,8 +1156,8 @@ static void remmina_rdp_event_cursor(RemminaProtocolWidget* gp, RemminaPluginRdp case REMMINA_RDP_POINTER_NULL: gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), - gdk_cursor_new_for_display(gdk_display_get_default(), - GDK_BLANK_CURSOR)); + gdk_cursor_new_for_display(gdk_display_get_default(), + GDK_BLANK_CURSOR)); ui->retval = 1; break; @@ -1157,31 +1168,31 @@ static void remmina_rdp_event_cursor(RemminaProtocolWidget* gp, RemminaPluginRdp } } -static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); remmina_rdp_event_update_scale(gp); } -void remmina_rdp_event_unfocus(RemminaProtocolWidget* gp) +void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); if (!rfi || !rfi->connected || rfi->is_reconnecting) return; remmina_rdp_event_release_all_keys(gp); } -static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); cairo_surface_destroy(rfi->surface); rfi->surface = NULL; } -static void remmina_rdp_event_process_event(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); switch (ui->event.type) { @@ -1194,7 +1205,7 @@ static void remmina_rdp_event_process_event(RemminaProtocolWidget* gp, RemminaPl } } -static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); switch (ui->type) { @@ -1227,49 +1238,46 @@ static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget* gp, Remmin } } -static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget* gp) +static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); - RemminaPluginRdpUiObject* ui; + rfContext *rfi = GET_PLUGIN_DATA(gp); + RemminaPluginRdpUiObject *ui; pthread_mutex_lock(&rfi->ui_queue_mutex); - ui = (RemminaPluginRdpUiObject*)g_async_queue_try_pop(rfi->ui_queue); + ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue); if (ui) { pthread_mutex_lock(&ui->sync_wait_mutex); - if (!rfi->thread_cancelled) { + if (!rfi->thread_cancelled) remmina_rdp_event_process_ui_event(gp, ui); - } // Should we signal the caller thread to unlock ? if (ui->sync) { ui->complete = TRUE; pthread_cond_signal(&ui->sync_wait_cond); pthread_mutex_unlock(&ui->sync_wait_mutex); - } else { remmina_rdp_event_free_event(gp, ui); } pthread_mutex_unlock(&rfi->ui_queue_mutex); return TRUE; - }else { + } else { rfi->ui_handler = 0; pthread_mutex_unlock(&rfi->ui_queue_mutex); return FALSE; } } -static void remmina_rdp_event_queue_ui(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); - rfContext* rfi = GET_PLUGIN_DATA(gp); + rfContext *rfi = GET_PLUGIN_DATA(gp); gboolean ui_sync_save; int oldcanceltype; - if (rfi->thread_cancelled) { + if (rfi->thread_cancelled) return; - } if (remmina_plugin_service->is_main_thread()) { remmina_rdp_event_process_ui_event(gp, ui); @@ -1292,17 +1300,15 @@ static void remmina_rdp_event_queue_ui(RemminaProtocolWidget* gp, RemminaPluginR g_async_queue_push(rfi->ui_queue, ui); - if (!rfi->ui_handler) { + if (!rfi->ui_handler) rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp); - } if (ui_sync_save) { /* Wait for main thread function completion before returning */ pthread_mutex_lock(&ui->sync_wait_mutex); pthread_mutex_unlock(&rfi->ui_queue_mutex); - while (!ui->complete) { + while (!ui->complete) pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex); - } pthread_cond_destroy(&ui->sync_wait_cond); pthread_mutex_destroy(&ui->sync_wait_mutex); } else { @@ -1311,13 +1317,13 @@ static void remmina_rdp_event_queue_ui(RemminaProtocolWidget* gp, RemminaPluginR pthread_setcanceltype(oldcanceltype, NULL); } -void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { ui->sync = FALSE; remmina_rdp_event_queue_ui(gp, ui); } -int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); int retval; @@ -1328,7 +1334,7 @@ int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget* gp, RemminaPlu return retval; } -void *remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget* gp, RemminaPluginRdpUiObject* ui) +void *remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui) { TRACE_CALL(__func__); void *rp; diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index ca937adfcf..507ab68e1e 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -43,6 +43,7 @@ #include "rdp_file.h" #include "rdp_settings.h" #include "rdp_cliprdr.h" +#include "rdp_monitor.h" #include "rdp_channels.h" #include <errno.h> @@ -84,7 +85,7 @@ #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5 -#define REMMINA_CONNECTION_TYPE_NONE 0 +#define REMMINA_CONNECTION_TYPE_NONE 0 /* Some string settings of FreeRDP are preallocated buffers of N bytes */ #define FREERDP_CLIENTHOSTNAME_LEN 32 @@ -241,17 +242,32 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) break; case REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT: - dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); - if (dcml) { - dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY; - dcml->Width = event->monitor_layout.width; - dcml->Height = event->monitor_layout.height; - dcml->Orientation = event->monitor_layout.desktopOrientation; - dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor; - dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor; - rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml); - g_free(dcml); + dcml = calloc(rfi->settings->MonitorCount, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:"); + if (!dcml) + break; + for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { + REMMINA_PLUGIN_DEBUG("Sending diplay layout for monitor n° %d", i); + dcml[i].Flags = (rfi->settings->MonitorDefArray[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0); + REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags); + dcml[i].Left = rfi->settings->MonitorDefArray[i].x; + REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left); + dcml[i].Top = rfi->settings->MonitorDefArray[i].y; + REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top); + dcml[i].Width = rfi->settings->MonitorDefArray[i].width; + REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width); + dcml[i].Height = rfi->settings->MonitorDefArray[i].height; + REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height); + dcml[i].PhysicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; + REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth); + dcml[i].PhysicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; + REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight); + dcml[i].Orientation = event->monitor_layout.desktopOrientation; + dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor; + dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor; } + rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, rfi->settings->MonitorCount, dcml); + g_free(dcml); break; case REMMINA_RDP_EVENT_DISCONNECT: /* Disconnect requested via GUI (i.e: tab destroy/close) */ @@ -725,20 +741,20 @@ static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char if (basecredforgw) { ret = remmina_plugin_service->protocol_plugin_init_auth(gp, - (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD) | REMMINA_MESSAGE_PANEL_FLAG_USERNAME | REMMINA_MESSAGE_PANEL_FLAG_DOMAIN, - _("Enter RDP authentication credentials"), - remmina_plugin_service->file_get_string(remminafile, "username"), - remmina_plugin_service->file_get_string(remminafile, "password"), - remmina_plugin_service->file_get_string(remminafile, "domain"), - NULL); + (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD) | REMMINA_MESSAGE_PANEL_FLAG_USERNAME | REMMINA_MESSAGE_PANEL_FLAG_DOMAIN, + _("Enter RDP authentication credentials"), + remmina_plugin_service->file_get_string(remminafile, "username"), + remmina_plugin_service->file_get_string(remminafile, "password"), + remmina_plugin_service->file_get_string(remminafile, "domain"), + NULL); } else { ret = remmina_plugin_service->protocol_plugin_init_auth(gp, - (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD) | REMMINA_MESSAGE_PANEL_FLAG_USERNAME | REMMINA_MESSAGE_PANEL_FLAG_DOMAIN, - _("Enter RDP gateway authentication credentials"), - remmina_plugin_service->file_get_string(remminafile, "gateway_username"), - remmina_plugin_service->file_get_string(remminafile, "gateway_password"), - remmina_plugin_service->file_get_string(remminafile, "gateway_domain"), - NULL); + (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD) | REMMINA_MESSAGE_PANEL_FLAG_USERNAME | REMMINA_MESSAGE_PANEL_FLAG_DOMAIN, + _("Enter RDP gateway authentication credentials"), + remmina_plugin_service->file_get_string(remminafile, "gateway_username"), + remmina_plugin_service->file_get_string(remminafile, "gateway_password"), + remmina_plugin_service->file_get_string(remminafile, "gateway_domain"), + NULL); } @@ -1167,8 +1183,9 @@ static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 t settings->SupportGraphicsPipeline = TRUE; } else if (type == REMMINA_CONNECTION_TYPE_NONE) { return FALSE; - } else + } else { return FALSE; + } return TRUE; } @@ -1326,7 +1343,7 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) rfi->settings->ProxyPort = proxy_port; } - if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)){ + if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)) { // Reset gateway credentials remmina_plugin_service->file_set_string(remminafile, "gateway_username", NULL); remmina_plugin_service->file_set_string(remminafile, "gateway_domain", NULL); @@ -1546,6 +1563,14 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) * dynamically resize remote desktop. This will automatically open * the "disp" dynamic channel, if available */ rfi->settings->SupportDisplayControl = TRUE; + if (rfi->settings->SupportDisplayControl) { + char *d[1]; + int dcount; + + dcount = 1; + d[0] = "disp"; + freerdp_client_add_dynamic_channel(rfi->settings, dcount, d); + } /* Sound settings */ @@ -1617,19 +1642,20 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_level"); - if (cs != NULL && cs[0] != '\0') { - REMMINA_PLUGIN_DEBUG ("Log level set to to %s", cs); - } else - cs = g_strdup ("INFO"); + if (cs != NULL && cs[0] != '\0') + REMMINA_PLUGIN_DEBUG("Log level set to to %s", cs); + else + cs = g_strdup("INFO"); wLog *root = WLog_GetRoot(); WLog_SetStringLogLevel(root, cs); cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_filters"); if (cs != NULL && cs[0] != '\0') { - REMMINA_PLUGIN_DEBUG ("Log filters set to to %s", cs); + REMMINA_PLUGIN_DEBUG("Log filters set to to %s", cs); WLog_AddStringLogFilters(cs); - } else + } else { WLog_AddStringLogFilters(NULL); + } cs = remmina_plugin_service->file_get_string(remminafile, "usb"); @@ -1717,6 +1743,53 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) #endif /* HAVE_CUPS */ } + if (remmina_plugin_service->file_get_int(remminafile, "span", FALSE)) { + rfi->settings->SpanMonitors = TRUE; + rfi->settings->UseMultimon = TRUE; + rfi->settings->Fullscreen = TRUE; + remmina_plugin_service->file_set_int(remminafile, "multimon", 1); + } + + if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) { + guint32 maxwidth = 0; + guint32 maxheight = 0; + rfi->settings->UseMultimon = TRUE; + /* TODO Add an option for this */ + rfi->settings->ForceMultimon = TRUE; + rfi->settings->Fullscreen = TRUE; + //if (!rfi->settings->NumMonitorIds) + //rfi->settings->NumMonitorIds = 0; + + gchar *monitorids = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids")); + /* Otherwise we get all the attached monitors */ + //if (monitorids != NULL && monitorids[0] != '\0') + //gchar *monitorids = NULL; + remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight); + if (monitorids != NULL && monitorids[0] != '\0') { + gchar **items; + guint32 i; + items = g_strsplit(monitorids, ",", -1); + rfi->settings->NumMonitorIds = g_strv_length(items); + REMMINA_PLUGIN_DEBUG("NumMonitorIds: %d", rfi->settings->NumMonitorIds); + for (i = 0; i < g_strv_length(items); i++) { + rfi->settings->MonitorIds[i] = (guint32)atoi(items[i]); + REMMINA_PLUGIN_DEBUG("Added monitor with ID %d", rfi->settings->MonitorIds[i]); + } + g_free(monitorids); + g_strfreev(items); + } + if (maxwidth && maxheight) { + REMMINA_PLUGIN_DEBUG("Setting DesktopWidth and DesktopHeight to: %dx%d", maxwidth, maxheight); + rfi->settings->DesktopWidth = maxwidth; + rfi->settings->DesktopHeight = maxheight; + REMMINA_PLUGIN_DEBUG("DesktopWidth and DesktopHeight set to: %dx%d", rfi->settings->DesktopWidth, rfi->settings->DesktopHeight); + } else { + REMMINA_PLUGIN_DEBUG("Cannot set Desktop Size, we are using the previously set values: %dx%d", rfi->settings->DesktopWidth, rfi->settings->DesktopHeight); + } + remmina_plugin_service->protocol_plugin_set_width(gp, rfi->settings->DesktopWidth); + remmina_plugin_service->protocol_plugin_set_height(gp, rfi->settings->DesktopHeight); + } + if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE)) { RDPDR_SMARTCARD *smartcard; smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD)); @@ -2399,15 +2472,18 @@ static gchar network_tooltip[] = */ static const RemminaProtocolSetting remmina_rdp_basic_settings[] = { - { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip }, - { REMMINA_PROTOCOL_SETTING_TYPE_FOLDER, "sharefolder", N_("Share folder"), FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } + { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("Monitor ID list"), FALSE, NULL, N_("Comma separated list of monitor IDs (0,1,2,4)") }, + { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip }, + { REMMINA_PROTOCOL_SETTING_TYPE_FOLDER, "sharefolder", N_("Share folder"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } }; /* Array of RemminaProtocolSetting for advanced settings. @@ -2427,7 +2503,7 @@ static const RemminaProtocolSetting remmina_rdp_advanced_settings[] = { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "freerdp_log_level", N_("FreeRDP log level"), FALSE, log_level, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "freerdp_log_filters", N_("FreeRDP log filters"), FALSE, NULL, N_("tag:level[,tag:level[,…]]") }, { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Sound"), FALSE, sound_list, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "microphone", N_("Redirect local microphone"), TRUE, NULL, microphone_tooltip }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "timeout", N_("Connection timeout in ms"), TRUE, NULL, timeout_tooltip }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL }, @@ -2437,7 +2513,7 @@ static const RemminaProtocolSetting remmina_rdp_advanced_settings[] = { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Start-up program"), FALSE, NULL, NULL }, - { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL }, { 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\"") }, { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "usb", N_("USB device redirection"), TRUE, NULL, usb_tooltip }, @@ -2469,7 +2545,7 @@ static const RemminaProtocolSetting remmina_rdp_advanced_settings[] = { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") }, - { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL }, { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL } }; diff --git a/plugins/rdp/rdp_plugin.h b/plugins/rdp/rdp_plugin.h index 9eb982a505..d736c12f0a 100644 --- a/plugins/rdp/rdp_plugin.h +++ b/plugins/rdp/rdp_plugin.h @@ -173,11 +173,16 @@ struct remmina_plugin_rdp_event { CLIPRDR_FORMAT_DATA_REQUEST *pFormatDataRequest; } clipboard_formatdatarequest; struct { + gint Flags; + gint Left; + gint Top; gint width; gint height; gint desktopOrientation; gint desktopScaleFactor; gint deviceScaleFactor; + gint physicalWidth; + gint physicalHeight; } monitor_layout; }; }; diff --git a/src/rcw.c b/src/rcw.c index 80276eb8bf..58a15105a6 100644 --- a/src/rcw.c +++ b/src/rcw.c @@ -1311,6 +1311,14 @@ static void rcw_toolbar_fullscreen(GtkToolItem *toggle, RemminaConnectionWindow if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return; + RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto); + + if (remmina_protocol_widget_get_multimon (gp) >= 1) { + REMMINA_DEBUG("Fullscreen on all monitor"); + gdk_window_set_fullscreen_mode (gtk_widget_get_window(GTK_WIDGET(toggle)), GDK_FULLSCREEN_ON_ALL_MONITORS); + } else + REMMINA_DEBUG("Fullscreen on one monitor"); + if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle))) rcw_switch_viewmode(cnnwin, cnnwin->priv->fss_view_mode); else @@ -2943,12 +2951,37 @@ static gboolean rcw_state_event(GtkWidget *widget, GdkEventWindowState *event, g static gboolean rcw_map_event_fullscreen(GtkWidget *widget, GdkEvent *event, gpointer data) { + TRACE_CALL(__func__); + RemminaConnectionObject *cnnobj; gint target_monitor; - TRACE_CALL(__func__); + REMMINA_DEBUG ("Mapping Remmina connection window"); - if (!REMMINA_IS_CONNECTION_WINDOW(widget)) + if (!REMMINA_IS_CONNECTION_WINDOW(widget)) { + REMMINA_DEBUG ("Remmina Connection Window undefined, cannot go fullscreen"); + return FALSE; + } + + //RemminaConnectionWindow *cnnwin = (RemminaConnectionWindow *)data; + cnnobj = rcw_get_visible_cnnobj((RemminaConnectionWindow*)widget); + //cnnobj = g_object_get_data(G_OBJECT(widget), "cnnobj"); + if (!cnnobj) { + REMMINA_DEBUG ("Remmina Connection Object undefined, cannot go fullscreen"); return FALSE; + } + + RemminaProtocolWidget *gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto); + if (!gp) { + REMMINA_DEBUG ("Remmina Protocol Widget undefined, cannot go fullscreen"); + } + + if (remmina_protocol_widget_get_multimon (gp) >= 1) { + REMMINA_DEBUG("Fullscreen on all monitor"); + gdk_window_set_fullscreen_mode (gtk_widget_get_window(widget), GDK_FULLSCREEN_ON_ALL_MONITORS); + gdk_window_fullscreen(gtk_widget_get_window(widget)); + return TRUE; + } else + REMMINA_DEBUG("Fullscreen on one monitor"); target_monitor = GPOINTER_TO_INT(data); diff --git a/src/remmina_protocol_widget.c b/src/remmina_protocol_widget.c index 3397a691c1..1a42da1b28 100644 --- a/src/remmina_protocol_widget.c +++ b/src/remmina_protocol_widget.c @@ -84,6 +84,7 @@ struct _RemminaProtocolWidgetPriv { gint profile_remote_width; gint profile_remote_height; + gint multimon; RemminaMessagePanel * connect_message_panel; RemminaMessagePanel * listen_message_panel; @@ -1129,6 +1130,15 @@ gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp) return gp->priv->profile_remote_width; } +gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + /* Returns ehenever multi monitor is enabled (1) */ + gp->priv->multimon = remmina_file_get_int(gp->priv->remmina_file, "multimon", -1); + REMMINA_DEBUG ("Multi monitor is set to %d", gp->priv->multimon); + return gp->priv->multimon; +} + gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp) { TRACE_CALL(__func__); diff --git a/src/remmina_protocol_widget.h b/src/remmina_protocol_widget.h index 98d71cdf1d..abb971159c 100644 --- a/src/remmina_protocol_widget.h +++ b/src/remmina_protocol_widget.h @@ -88,6 +88,7 @@ gint remmina_protocol_widget_get_height(RemminaProtocolWidget *gp); void remmina_protocol_widget_set_height(RemminaProtocolWidget *gp, gint height); gint remmina_protocol_widget_get_profile_remote_width(RemminaProtocolWidget *gp); gint remmina_protocol_widget_get_profile_remote_height(RemminaProtocolWidget *gp); +gint remmina_protocol_widget_get_multimon(RemminaProtocolWidget *gp); RemminaScaleMode remmina_protocol_widget_get_current_scale_mode(RemminaProtocolWidget *gp); void remmina_protocol_widget_set_current_scale_mode(RemminaProtocolWidget *gp, RemminaScaleMode scalemode); -- GitLab From d429c38dabcf6fb7fa5d213553229325d3704384 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Wed, 27 Jan 2021 15:46:05 +0100 Subject: [PATCH 2/8] Adding multi monitor support: monitor detection --- plugins/rdp/rdp_monitor.c | 226 ++++++++++++++++++++++++++++++++++++++ plugins/rdp/rdp_monitor.h | 45 ++++++++ 2 files changed, 271 insertions(+) create mode 100644 plugins/rdp/rdp_monitor.c create mode 100644 plugins/rdp/rdp_monitor.h diff --git a/plugins/rdp/rdp_monitor.c b/plugins/rdp/rdp_monitor.c new file mode 100644 index 0000000000..a590f791d0 --- /dev/null +++ b/plugins/rdp/rdp_monitor.c @@ -0,0 +1,226 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. * If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. * If you + * do not wish to do so, delete this exception statement from your + * version. * If you delete this exception statement from all source + * files in the program, then also delete it here. + * + */ + +#include "rdp_plugin.h" +#include "rdp_monitor.h" + +/** @ToDo Utility functions should be moved somewhere else */ +gint remmina_rdp_utils_strpos(const gchar *haystack, const gchar *needle) +{ + TRACE_CALL(__func__); + const gchar *sub; + + if (!*needle) + return -1; + + sub = strstr(haystack, needle); + if (!sub) + return -1; + + return sub - haystack; +} + +/* https://github.com/adlocode/xfwm4/blob/1d21be9ffc0fa1cea91905a07d1446c5227745f4/common/xfwm-common.c */ + + +/** + * Set the MonitorIDs, the maxwidth and maxheight + * + * - number of monitors + * - Geometry of each + * - Choosen by the user + * - Primary monitor + * - Otherwise use current monitor as the origin + * + * The origin must be 0,0 + */ +void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight) +{ + TRACE_CALL(__func__); + + GdkDisplay *display; + GdkMonitor *current_monitor, *monitor; + gboolean has_custom_monitors = FALSE; + + gboolean primary_found = FALSE; + + gint n_monitors; + gint scale; + gint index = 0; + gint count = 0; + + static gchar buffer[256]; + + GdkRectangle geometry = { 0, 0, 0, 0 }; + GdkRectangle tempgeom = { 0, 0, 0, 0 }; + GdkRectangle destgeom = { 0, 0, 0, 0 }; + rdpSettings* settings; + if (!rfi || !rfi->settings) + return; + + settings = rfi->settings; + + *maxwidth = settings->DesktopWidth; + *maxheight = settings->DesktopHeight; + + display = gdk_display_get_default (); + n_monitors = gdk_display_get_n_monitors(display); + + /* Get monitor at windows curently in use */ + //w = gtk_widget_get_window(rfi->drawing_area); + + //current_monitor = gdk_display_get_monitor_at_window (display, w); + + /* we got monitorids as options */ + if (*monitorids) + has_custom_monitors = TRUE; + + buffer[0] = '\0'; + + for (gint i = 0; i < n_monitors; ++i) { + if (has_custom_monitors) { + REMMINA_PLUGIN_DEBUG("We have custom monitors"); + gchar itoc[10]; + sprintf(itoc, "%d", i);; + if (remmina_rdp_utils_strpos(*monitorids, itoc) < 0 ) { + REMMINA_PLUGIN_DEBUG("Monitor n %d it's out of the provided list", i); + index += 1; + continue; + } + } + + monitor = gdk_display_get_monitor(display, i); + if (monitor == NULL) { + REMMINA_PLUGIN_DEBUG("Monitor n %d does not exist or is not active", i); + index +=1; + continue; + } + + monitor = gdk_display_get_monitor(display, index); + REMMINA_PLUGIN_DEBUG("Monitor n %d", index); + /* If the desktop env in use doesn't have the working area concept + * gdk_monitor_get_workarea will return the monitor geometry*/ + //gdk_monitor_get_workarea (monitor, &geometry); + gdk_monitor_get_geometry (monitor, &geometry); + settings->MonitorDefArray[index].x = geometry.x; + REMMINA_PLUGIN_DEBUG("Monitor n %d x: %d", index, geometry.x); + settings->MonitorDefArray[index].y = geometry.y; + REMMINA_PLUGIN_DEBUG("Monitor n %d y: %d", index, geometry.y); + /* geometry contain the application geometry, to obtain the real one + * we must multiply by the scale factor */ + scale = gdk_monitor_get_scale_factor (monitor); + REMMINA_PLUGIN_DEBUG("Monitor n %d scale: %d", index, scale); + geometry.width *= scale; + geometry.height *= scale; + REMMINA_PLUGIN_DEBUG("Monitor n %d width: %d", index, geometry.width); + REMMINA_PLUGIN_DEBUG("Monitor n %d height: %d", index, geometry.height); + settings->MonitorDefArray[index].width = geometry.width; + settings->MonitorDefArray[index].height = geometry.height; + settings->MonitorDefArray[index].attributes.physicalHeight = gdk_monitor_get_height_mm (monitor); + REMMINA_PLUGIN_DEBUG("Monitor n %d physical height: %d", i, settings->MonitorDefArray[index].attributes.physicalHeight); + settings->MonitorDefArray[index].attributes.physicalWidth = gdk_monitor_get_width_mm (monitor); + REMMINA_PLUGIN_DEBUG("Monitor n %d physical width: %d", i, settings->MonitorDefArray[index].attributes.physicalWidth); + settings->MonitorDefArray[index].orig_screen = index; + if (!primary_found) { + settings->MonitorLocalShiftX = settings->MonitorDefArray[index].x; + settings->MonitorLocalShiftY = settings->MonitorDefArray[index].y; + } + if (gdk_monitor_is_primary(monitor)) { + REMMINA_PLUGIN_DEBUG ("Primary monitor found with id: %d", index); + settings->MonitorDefArray[index].is_primary = TRUE; + primary_found = TRUE; + if (settings->MonitorDefArray[index].x != 0 || settings->MonitorDefArray[index].y != 0) + { + REMMINA_PLUGIN_DEBUG ("Primary monitor not at 0,0 coordinates: %d", index); + settings->MonitorLocalShiftX = settings->MonitorDefArray[index].x; + settings->MonitorLocalShiftY = settings->MonitorDefArray[index].y; + } + } else { + if (!primary_found && settings->MonitorDefArray[index].x == 0 && + settings->MonitorDefArray[index].y == 0) + { + REMMINA_PLUGIN_DEBUG ("Monitor %d has 0,0 coordiantes", index); + settings->MonitorDefArray[index].is_primary = TRUE; + settings->MonitorLocalShiftX = settings->MonitorDefArray[index].x; + settings->MonitorLocalShiftY = settings->MonitorDefArray[index].y; + primary_found = TRUE; + REMMINA_PLUGIN_DEBUG ("Primary monitor set to id: %d", index); + } + } + REMMINA_PLUGIN_DEBUG ("Local X Shift: %d", settings->MonitorLocalShiftX); + REMMINA_PLUGIN_DEBUG ("Local Y Shift: %d", settings->MonitorLocalShiftY); + //settings->MonitorDefArray[index].x = + //settings->MonitorDefArray[index].x - settings->MonitorLocalShiftX; + //REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", index, settings->MonitorDefArray[index].x); + //settings->MonitorDefArray[index].y = + //settings->MonitorDefArray[index].y - settings->MonitorLocalShiftY; + //REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", index, settings->MonitorDefArray[index].y); + + if (buffer[0] == '\0') + g_sprintf (buffer, "%d", i); + else + g_sprintf(buffer, "%s,%d", buffer, i); + REMMINA_PLUGIN_DEBUG("Monitor IDs buffer: %s", buffer); + gdk_rectangle_union(&tempgeom, &geometry, &destgeom); + memcpy(&tempgeom, &destgeom, sizeof tempgeom); + count++; + index++; + + } + settings->MonitorCount = index; + /* Subtract monitor shift from monitor variables for server-side use. + * We maintain monitor shift value as Window requires the primary monitor to have a + * coordinate of 0,0 In some X configurations, no monitor may have a coordinate of 0,0. This + * can also be happen if the user requests specific monitors from the command-line as well. + * So, we make sure to translate our primary monitor's upper-left corner to 0,0 on the + * server. + */ + for (gint i = 0; i < settings->MonitorCount; i++) + { + settings->MonitorDefArray[i].x = + settings->MonitorDefArray[i].x - settings->MonitorLocalShiftX; + REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", index, settings->MonitorDefArray[index].x); + settings->MonitorDefArray[i].y = + settings->MonitorDefArray[i].y - settings->MonitorLocalShiftY; + REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", index, settings->MonitorDefArray[index].y); + } + + REMMINA_PLUGIN_DEBUG("%d monitors on %d have been configured", rfi->settings->MonitorCount, count); + *maxwidth = destgeom.width; + *maxheight = destgeom.height; + REMMINA_PLUGIN_DEBUG("maxw and maxh: %ux%u", *maxwidth, *maxheight); + if (n_monitors > 1) + rfi->settings->SupportMonitorLayoutPdu = TRUE; + *monitorids = g_strdup(buffer); +} diff --git a/plugins/rdp/rdp_monitor.h b/plugins/rdp/rdp_monitor.h new file mode 100644 index 0000000000..1c8f08dbb7 --- /dev/null +++ b/plugins/rdp/rdp_monitor.h @@ -0,0 +1,45 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. * If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. * If you + * do not wish to do so, delete this exception statement from your + * version. * If you delete this exception statement from all source + * files in the program, then also delete it here. + * + */ + +#pragma once + + +#include <freerdp/freerdp.h> +#include "rdp_plugin.h" + +G_BEGIN_DECLS + +void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight); + +G_END_DECLS -- GitLab From 5dfc287d896ae5c5958472a3b157c6a65dc19505 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Wed, 27 Jan 2021 16:30:07 +0100 Subject: [PATCH 3/8] Sending multiple layouts only if multimon is active --- plugins/rdp/rdp_event.c | 57 ++++++++++++++++++++------------- plugins/rdp/rdp_plugin.c | 68 +++++++++++++++++++++++++--------------- 2 files changed, 78 insertions(+), 47 deletions(-) diff --git a/plugins/rdp/rdp_event.c b/plugins/rdp/rdp_event.c index fcd0225d41..d3609f9aee 100644 --- a/plugins/rdp/rdp_event.c +++ b/plugins/rdp/rdp_event.c @@ -366,9 +366,13 @@ static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget * GtkAllocation a; gint desktopOrientation, desktopScaleFactor, deviceScaleFactor; + RemminaFile *remminafile; + if (!rfi || !rfi->connected || rfi->is_reconnecting) return FALSE; + remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + if (rfi->scale != REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) return FALSE; @@ -398,28 +402,37 @@ static gboolean remmina_rdp_event_delayed_monitor_layout(RemminaProtocolWidget * gpheight = AVC_MIN_DESKTOP_HEIGHT; } rdp_event.type = REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT; - for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { - REMMINA_PLUGIN_DEBUG("Sending diplay layout n° %d", i); - rdp_event.monitor_layout.Flags = rfi->settings->MonitorDefArray[i].is_primary; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags); - rdp_event.monitor_layout.Left = rfi->settings->MonitorDefArray[i].x; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left); - rdp_event.monitor_layout.Top = rfi->settings->MonitorDefArray[i].y; - //rdp_event.monitor_layout.Top = rfi->settings->MonitorDefArray[0].y; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top); - rdp_event.monitor_layout.width = rfi->settings->MonitorDefArray[i].width; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width); - rdp_event.monitor_layout.height = rfi->settings->MonitorDefArray[i].height; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height); - rdp_event.monitor_layout.physicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth); - rdp_event.monitor_layout.physicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight); - rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation); - rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor; - REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor); - rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor; + if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) { + for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { + REMMINA_PLUGIN_DEBUG("Sending diplay layout n° %d", i); + rdp_event.monitor_layout.Flags = rfi->settings->MonitorDefArray[i].is_primary; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags); + rdp_event.monitor_layout.Left = rfi->settings->MonitorDefArray[i].x; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left); + rdp_event.monitor_layout.Top = rfi->settings->MonitorDefArray[i].y; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top); + rdp_event.monitor_layout.width = rfi->settings->MonitorDefArray[i].width; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width); + rdp_event.monitor_layout.height = rfi->settings->MonitorDefArray[i].height; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height); + rdp_event.monitor_layout.physicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth); + rdp_event.monitor_layout.physicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight); + rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation); + rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor; + REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor); + rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor; + } + remmina_rdp_event_event_push(gp, &rdp_event); + } else { + + rdp_event.monitor_layout.width = gpwidth; + rdp_event.monitor_layout.height = gpheight; + rdp_event.monitor_layout.desktopOrientation = desktopOrientation; + rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor; + rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor; remmina_rdp_event_event_push(gp, &rdp_event); } } diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index 507ab68e1e..cb114a6582 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -193,12 +193,15 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) RemminaPluginRdpEvent *event; DISPLAY_CONTROL_MONITOR_LAYOUT *dcml; CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 }; + RemminaFile *remminafile; if (rfi->event_queue == NULL) return True; input = rfi->instance->input; + remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) { switch (event->type) { case REMMINA_RDP_EVENT_TYPE_SCANCODE: @@ -242,32 +245,47 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) break; case REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT: - dcml = calloc(rfi->settings->MonitorCount, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); - REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:"); - if (!dcml) - break; - for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { - REMMINA_PLUGIN_DEBUG("Sending diplay layout for monitor n° %d", i); - dcml[i].Flags = (rfi->settings->MonitorDefArray[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0); - REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags); - dcml[i].Left = rfi->settings->MonitorDefArray[i].x; - REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left); - dcml[i].Top = rfi->settings->MonitorDefArray[i].y; - REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top); - dcml[i].Width = rfi->settings->MonitorDefArray[i].width; - REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width); - dcml[i].Height = rfi->settings->MonitorDefArray[i].height; - REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height); - dcml[i].PhysicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; - REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth); - dcml[i].PhysicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; - REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight); - dcml[i].Orientation = event->monitor_layout.desktopOrientation; - dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor; - dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor; + if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) { + /* got some crashes with g_malloc0, to be investigated */ + dcml = calloc(rfi->settings->MonitorCount, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:"); + if (!dcml) + break; + for (gint i = 0; i < rfi->settings->MonitorCount; ++i) { + REMMINA_PLUGIN_DEBUG("Sending diplay layout for monitor n° %d", i); + dcml[i].Flags = (rfi->settings->MonitorDefArray[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0); + REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags); + dcml[i].Left = rfi->settings->MonitorDefArray[i].x; + REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left); + dcml[i].Top = rfi->settings->MonitorDefArray[i].y; + REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top); + dcml[i].Width = rfi->settings->MonitorDefArray[i].width; + REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width); + dcml[i].Height = rfi->settings->MonitorDefArray[i].height; + REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height); + dcml[i].PhysicalWidth = rfi->settings->MonitorDefArray[i].attributes.physicalWidth; + REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth); + dcml[i].PhysicalHeight = rfi->settings->MonitorDefArray[i].attributes.physicalHeight; + REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight); + dcml[i].Orientation = event->monitor_layout.desktopOrientation; + dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor; + dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor; + } + rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, rfi->settings->MonitorCount, dcml); + g_free(dcml); + } else { + dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + if (dcml) { + dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY; + dcml->Width = event->monitor_layout.width; + dcml->Height = event->monitor_layout.height; + dcml->Orientation = event->monitor_layout.desktopOrientation; + dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor; + dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor; + rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml); + g_free(dcml);\ + } } - rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, rfi->settings->MonitorCount, dcml); - g_free(dcml); break; case REMMINA_RDP_EVENT_DISCONNECT: /* Disconnect requested via GUI (i.e: tab destroy/close) */ -- GitLab From 634010c7da0f445f48140dce2c18d78bb5924741 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Wed, 27 Jan 2021 15:42:41 +0100 Subject: [PATCH 4/8] Adding multi monitor support --- plugins/rdp/rdp_plugin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index cb114a6582..8c2d6a8012 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -286,6 +286,8 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) g_free(dcml);\ } } + rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, rfi->settings->MonitorCount, dcml); + g_free(dcml); break; case REMMINA_RDP_EVENT_DISCONNECT: /* Disconnect requested via GUI (i.e: tab destroy/close) */ -- GitLab From de382ef139cda19c30958e1068ed03d907a104e1 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Wed, 27 Jan 2021 16:30:07 +0100 Subject: [PATCH 5/8] Sending multiple layouts only if multimon is active --- plugins/rdp/rdp_plugin.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index 8c2d6a8012..cb114a6582 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -286,8 +286,6 @@ static BOOL rf_process_event_queue(RemminaProtocolWidget *gp) g_free(dcml);\ } } - rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, rfi->settings->MonitorCount, dcml); - g_free(dcml); break; case REMMINA_RDP_EVENT_DISCONNECT: /* Disconnect requested via GUI (i.e: tab destroy/close) */ -- GitLab From 6b95aed88b3711efd04cc23e258a88090913a175 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Fri, 29 Jan 2021 17:10:57 +0100 Subject: [PATCH 6/8] Adding multi monitor toolbar button --- data/icons/CMakeLists.txt | 1 + .../remmina-multi-monitor-symbolic.svg | 69 ++++ data/ui/remmina_main.glade | 2 +- data/ui/remmina_preferences.glade | 294 ++++++++++-------- plugins/rdp/rdp_monitor.c | 6 +- plugins/rdp/rdp_plugin.c | 36 ++- plugins/rdp/rdp_settings.c | 2 - src/include/remmina/types.h | 1 + src/rcw.c | 43 ++- src/remmina_main.c | 1 + src/remmina_pref.c | 6 + src/remmina_pref.h | 2 + src/remmina_pref_dialog.c | 29 ++ src/remmina_pref_dialog.h | 3 + 14 files changed, 344 insertions(+), 151 deletions(-) create mode 100644 data/icons/scalable/actions/remmina-multi-monitor-symbolic.svg diff --git a/data/icons/CMakeLists.txt b/data/icons/CMakeLists.txt index fd246807d4..645c09ef69 100644 --- a/data/icons/CMakeLists.txt +++ b/data/icons/CMakeLists.txt @@ -45,6 +45,7 @@ set(APPICONSCALE_ACTIONS_DATA scalable/actions/remmina-dynres-symbolic.svg scalable/actions/remmina-fit-window-symbolic.svg scalable/actions/remmina-fullscreen-symbolic.svg + scalable/actions/remmina-multi-monitor-symbolic.svg scalable/actions/remmina-go-bottom-symbolic.svg scalable/actions/remmina-keyboard-symbolic.svg scalable/actions/remmina-pan-down-symbolic.svg diff --git a/data/icons/scalable/actions/remmina-multi-monitor-symbolic.svg b/data/icons/scalable/actions/remmina-multi-monitor-symbolic.svg new file mode 100644 index 0000000000..2555478986 --- /dev/null +++ b/data/icons/scalable/actions/remmina-multi-monitor-symbolic.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="22.983299mm" + height="19.69982mm" + viewBox="0 0 22.983299 19.69982" + version="1.1" + id="svg723" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" + sodipodi:docname="remmina-multi-monitor-symbolic.svg"> + <defs + id="defs717" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:zoom="11.313708" + inkscape:cx="46.830344" + inkscape:cy="55.482858" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + inkscape:document-rotation="0" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="3840" + inkscape:window-height="2102" + inkscape:window-x="1920" + inkscape:window-y="30" + inkscape:window-maximized="1" /> + <metadata + id="metadata720"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-64.859519,-115.63819)"> + <path + d="m 66.507946,115.65733 c -1.648427,0 -1.648427,1.23946 -1.648427,1.23946 v 4.95762 h 3.296746 v -3.71817 h 4.944872 v -2.47891 z m 13.186281,0 v 2.47891 h 4.944872 v 3.71817 h 3.296443 v -4.95762 c 0,-1.23946 -1.648321,-1.23946 -1.648321,-1.23946 z m -14.834708,8.67577 v 4.95763 c 0,1.23925 1.648427,1.23925 1.648427,1.23925 h 6.593191 v -2.4787 h -4.944872 v -3.71818 z m 19.77958,0 v 3.71818 h -4.944872 v 2.4787 h 6.592994 c 0,0 1.648321,0 1.648321,-1.23925 v -4.95763 z" + id="path19-6" + inkscape:connector-curvature="0" + style="isolation:isolate;fill:#171717;stroke-width:0.230354" /> + <path + id="path1753" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#171717;fill-opacity:1;fill-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none" + d="m 76.396755,128.05397 -1.229899,5.2e-4 -0.532267,5.379 -3.91294,0.39325 -0.0021,1.51309 5.678206,-0.001 z m 0.001,7.28483 5.677689,0.001 -0.0021,-1.51309 -3.912939,-0.39325 -0.532267,-5.379 -1.2299,-5.2e-4 z" /> + </g> +</svg> diff --git a/data/ui/remmina_main.glade b/data/ui/remmina_main.glade index 53f557c965..369462dd07 100644 --- a/data/ui/remmina_main.glade +++ b/data/ui/remmina_main.glade @@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <property name="visible">True</property> <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Show the Remmina changelog.</property> - <property name="stock">gtk-info</property> + <property name="icon_name">dialog-information</property> </object> <object class="GtkImage" id="view_toggle_icon"> <property name="visible">True</property> diff --git a/data/ui/remmina_preferences.glade b/data/ui/remmina_preferences.glade index d9927dd140..401ff77afc 100644 --- a/data/ui/remmina_preferences.glade +++ b/data/ui/remmina_preferences.glade @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.36.0 +<!-- Generated with glade 3.36.0 -Remmina Preferences Dialog - -Copyright © 2014-2021 Antenore Gatta, Giovanni Panozzo +Remmina Preferences Dialog - +Copyright (C) Antenore Gatta, Giovanni Panozzo 2014-2020 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,19 +27,10 @@ Author: Antenore Gatta <!-- interface-name Remmina Preferences Dialog --> <!-- interface-copyright Antenore Gatta, Giovanni Panozzo 2014-2020 --> <!-- interface-authors Antenore Gatta --> - <object class="GtkActionGroup" id="actiongroup_preferences"> - <child> - <object class="GtkAction" id="action_preferences_close"> - <property name="label" translatable="yes">Close</property> - <property name="short_label" translatable="yes">Close</property> - <signal name="activate" handler="remmina_pref_dialog_on_close_clicked" swapped="no"/> - </object> - </child> - </object> <object class="GtkDialog" id="RemminaPrefDialog"> <property name="can_focus">False</property> <property name="title" translatable="yes">Remmina Preferences</property> - <property name="modal">True</property> + <property name="window_position">center-on-parent</property> <property name="type_hint">dialog</property> <signal name="close" handler="remmina_pref_dialog_on_close_clicked" swapped="no"/> <signal name="destroy" handler="remmina_pref_on_dialog_destroy" swapped="no"/> @@ -55,11 +46,10 @@ Author: Antenore Gatta <child> <object class="GtkButton" id="button_close"> <property name="label" translatable="yes">Close</property> - <property name="use_action_appearance">True</property> - <property name="related_action">action_preferences_close</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> + <property name="action_name">pref.close</property> <property name="use_underline">True</property> </object> <packing> @@ -80,6 +70,9 @@ Author: Antenore Gatta <object class="GtkNotebook" id="notebook_preferences"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="tab_pos">left</property> + <property name="scrollable">True</property> + <property name="enable_popup">True</property> <child> <object class="GtkGrid" id="grid_options"> <property name="visible">True</property> @@ -91,7 +84,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Double-click action</property> <property name="justify">right</property> @@ -105,7 +98,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_options_double_click"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <items> <item translatable="yes">Open connection</item> <item translatable="yes">Edit settings</item> @@ -122,7 +115,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Scaling quality</property> <property name="justify">right</property> @@ -136,7 +129,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_options_scale_quality"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <items> <item translatable="yes">Nearest</item> <item translatable="yes">Tiles</item> @@ -155,7 +148,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Step size for auto-scroll</property> <property name="justify">right</property> @@ -169,7 +162,7 @@ Author: Antenore Gatta <object class="GtkEntry" id="entry_options_scroll"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="max_length">3</property> </object> <packing> @@ -183,7 +176,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Maximal amount of recent items</property> <property name="justify">right</property> @@ -213,7 +206,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="halign">start</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_clear_recent" swapped="no"/> </object> <packing> @@ -226,7 +219,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Screen resolutions</property> <property name="justify">right</property> @@ -241,7 +234,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Keystrokes</property> <property name="justify">right</property> @@ -257,8 +250,8 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="halign">start</property> - <property name="margin_right">18</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_on_button_keystrokes_clicked" swapped="no"/> </object> <packing> @@ -272,7 +265,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Folder for screenshots</property> <property name="justify">right</property> @@ -287,7 +280,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Choose a folder to save screenshots from Remmina in.</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="action">select-folder</property> <property name="title" translatable="yes">Select a folder</property> </object> @@ -303,8 +296,8 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="halign">start</property> - <property name="margin_right">18</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_on_button_resolutions_clicked" swapped="no"/> </object> <packing> @@ -318,7 +311,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Screenshot filenames</property> <property name="justify">right</property> @@ -336,7 +329,7 @@ Author: Antenore Gatta %h Server name/IP %Y Year, %m Month, %d Day, %H Hour, %M Minute, %S Seconds (UTC time) </property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="width_chars">35</property> <property name="placeholder_text">remmina_%p_%h_%Y%m%d-%H%M%S</property> </object> @@ -352,7 +345,7 @@ Author: Antenore Gatta <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">The folder connection profiles are saved in, it defaults to the XDG_USER_DATA</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes" comments="The folder where profiles are saved">Remmina data folder</property> @@ -367,7 +360,7 @@ Author: Antenore Gatta <object class="GtkFileChooserButton" id="filechooserbutton_options_datadir_path"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="margin_top">18</property> <property name="action">select-folder</property> <property name="title" translatable="yes"/> @@ -384,7 +377,7 @@ Author: Antenore Gatta <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Remember last view for each connection</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes" comments="The star (*) is a reference to privacy consent">Remember last view mode</property> <property name="justify">right</property> @@ -398,9 +391,9 @@ Author: Antenore Gatta <object class="GtkSwitch" id="switch_options_remember_last_view_mode"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> + <property name="halign">end</property> <property name="valign">center</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> </object> <packing> <property name="left_attach">1</property> @@ -412,9 +405,9 @@ Author: Antenore Gatta <object class="GtkSwitch" id="switch_permit_send_stats"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> + <property name="halign">end</property> <property name="valign">center</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> </object> <packing> <property name="left_attach">1</property> @@ -428,7 +421,7 @@ Author: Antenore Gatta <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Set a custom filename for your Remmina connection profiles, using a formatting string.</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Template for profile filenames</property> <property name="justify">right</property> @@ -449,7 +442,7 @@ Author: Antenore Gatta </property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="width_chars">25</property> <property name="placeholder_text">%G_%P_%N_%h</property> </object> @@ -465,7 +458,7 @@ Author: Antenore Gatta <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Only save generated screenshots, don't copy them to clipboard.</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_bottom">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes">Prevent screenshots from entering clipboard</property> @@ -480,9 +473,9 @@ Author: Antenore Gatta <object class="GtkSwitch" id="switch_options_deny_screenshot_clipboard"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> + <property name="halign">end</property> <property name="valign">center</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="margin_bottom">18</property> </object> <packing> @@ -495,9 +488,9 @@ Author: Antenore Gatta <object class="GtkSwitch" id="switch_permit_news"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> + <property name="halign">end</property> <property name="valign">center</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> </object> <packing> <property name="left_attach">1</property> @@ -509,6 +502,9 @@ Author: Antenore Gatta <object class="GtkLabel" id="privacy_disclaimer_label"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="margin_start">18</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">* By enabling statistics and/or news you consent to send and fetch data to/from remmina.org</property> <property name="justify">fill</property> <property name="wrap">True</property> @@ -525,7 +521,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes" comments="The star (*) is a reference to privacy consent">Send <b><a href="https://remmina.gitlab.io/remminadoc.gitlab.io/remmina__stats_8c.html#details" title="Remmina usage statistics">anonymous</a></b> statistics. (*)</property> <property name="use_markup">True</property> @@ -540,7 +536,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">False</property> <property name="label" translatable="yes" comments="The star (*) is a reference to privacy consent">Fetch news from <a href="https://remmina.org" title="Remmina news site">remmina.org</a> (*)</property> <property name="use_markup">True</property> @@ -556,6 +552,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_options"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Options</property> </object> <packing> @@ -576,7 +574,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> </object> @@ -593,7 +591,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> </object> @@ -608,7 +606,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Default view</property> </object> <packing> @@ -620,7 +618,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_appearance_view_mode"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <items> <item translatable="yes">Automatic</item> @@ -640,7 +638,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_bottom">18</property> <property name="label" translatable="yes">Tabs</property> </object> @@ -653,7 +651,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_appearance_tab_interface"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="margin_bottom">18</property> <property name="hexpand">True</property> <items> @@ -676,7 +674,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="hexpand">True</property> <property name="active">True</property> @@ -692,7 +690,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_appearance_fullscreen_toolbar_visibility"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="active_id">0</property> <items> <item id="0" translatable="yes">Peeking</item> @@ -711,7 +709,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Fullscreen toolbar visibility</property> <property name="selectable">True</property> </object> @@ -727,7 +725,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> </object> @@ -746,6 +744,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_appearance"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Appearance</property> </object> <packing> @@ -767,7 +767,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> @@ -785,7 +785,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> </object> @@ -802,7 +802,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> <signal name="toggled" handler="remmina_pref_dialog_disable_tray_icon_on_toggled" swapped="no"/> @@ -820,7 +820,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_bottom">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> @@ -839,7 +839,7 @@ Author: Antenore Gatta <property name="receives_default">False</property> <property name="tooltip_text" translatable="yes">Improves contrast if you have a light panel.</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> </object> @@ -858,6 +858,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_applet"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Applet</property> </object> <packing> @@ -877,7 +879,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Host key</property> @@ -894,7 +896,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="margin_top">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> @@ -909,7 +911,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Show/hide fullscreen</property> </object> @@ -925,7 +927,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -939,7 +941,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Auto-fit window</property> </object> @@ -955,7 +957,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -969,7 +971,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Switch tab pages</property> </object> @@ -999,7 +1001,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1012,7 +1014,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Apply/remove scaling</property> </object> @@ -1028,7 +1030,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1042,7 +1044,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Grab keyboard</property> </object> @@ -1058,7 +1060,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1072,7 +1074,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Minimize window</property> </object> @@ -1088,8 +1090,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="valign">start</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1103,7 +1104,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Disconnect</property> </object> @@ -1119,7 +1120,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1133,7 +1134,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Show/hide toolbar</property> </object> @@ -1149,7 +1150,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1163,7 +1164,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Screenshot</property> <property name="ellipsize">start</property> @@ -1180,7 +1181,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1194,8 +1195,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> - <property name="margin_bottom">18</property> + <property name="margin_start">18</property> <property name="hexpand">True</property> <property name="label" translatable="yes">View-only mode</property> <property name="ellipsize">start</property> @@ -1212,8 +1212,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="margin_right">18</property> - <property name="margin_bottom">18</property> + <property name="margin_end">18</property> <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> </object> <packing> @@ -1222,6 +1221,39 @@ Author: Antenore Gatta <property name="width">2</property> </packing> </child> + <child> + <object class="GtkLabel" id="label_keyboard_multimon"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="margin_start">18</property> + <property name="margin_bottom">18</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">Multi monitor</property> + <property name="ellipsize">start</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">11</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_keyboard_multimon"> + <property name="label" translatable="yes">Multi monitor</property> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="margin_end">18</property> + <property name="margin_bottom">18</property> + <signal name="clicked" handler="remmina_pref_dialog_on_key_chooser" swapped="no"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">11</property> + <property name="width">2</property> + </packing> + </child> </object> <packing> <property name="position">3</property> @@ -1231,6 +1263,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_keyboard"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Keyboard</property> </object> <packing> @@ -1250,7 +1284,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Local SSH port</property> </object> <packing> @@ -1262,7 +1296,7 @@ Author: Antenore Gatta <object class="GtkEntry" id="entry_options_ssh_port"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="max_length">5</property> <property name="input_purpose">number</property> @@ -1280,7 +1314,7 @@ Author: Antenore Gatta <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_bottom">18</property> <property name="hexpand">True</property> <property name="draw_indicator">True</property> @@ -1295,7 +1329,7 @@ Author: Antenore Gatta <object class="GtkComboBoxText" id="comboboxtext_options_ssh_loglevel"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="margin_top">18</property> <property name="hexpand">True</property> <items> @@ -1317,7 +1351,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="label" translatable="yes">SSH log level</property> </object> @@ -1331,7 +1365,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label">TCP_keepidle</property> <property name="selectable">True</property> </object> @@ -1345,7 +1379,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label">TCP_keepintvl</property> <property name="selectable">True</property> </object> @@ -1359,7 +1393,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label">TCP_keepcnt</property> <property name="selectable">True</property> </object> @@ -1373,7 +1407,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label">TCP_user_timeout</property> <property name="selectable">True</property> </object> @@ -1387,7 +1421,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="tooltip_text" translatable="yes" comments="http://man7.org/linux/man-pages/man7/tcp.7.html">Seconds of connection idleness before TCP keepalive probes are sent.</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="max_length">5</property> <property name="input_purpose">number</property> @@ -1403,7 +1437,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="tooltip_text" translatable="yes" comments="http://man7.org/linux/man-pages/man7/tcp.7.html">Seconds between each keepalive probe.</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="max_length">5</property> <property name="input_purpose">number</property> @@ -1419,7 +1453,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="tooltip_text" translatable="yes" comments="http://man7.org/linux/man-pages/man7/tcp.7.html">Number of keepalive probes sent via TCP connection before it is dropped.</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="max_length">5</property> <property name="input_purpose">number</property> @@ -1435,7 +1469,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="tooltip_text" translatable="yes" comments="http://man7.org/linux/man-pages/man7/tcp.7.html">Amount of milliseconds to attempt acknowledging data before closing the corresponding TCP connection forcibly.</property> - <property name="margin_right">18</property> + <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="max_length">5</property> <property name="input_purpose">number</property> @@ -1455,6 +1489,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_ssh"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">SSH options</property> </object> <packing> @@ -1486,7 +1522,7 @@ Author: Antenore Gatta <packing> <property name="left_attach">0</property> <property name="top_attach">0</property> - <property name="width">3</property> + <property name="width">2</property> </packing> </child> <child> @@ -1503,7 +1539,6 @@ Author: Antenore Gatta <packing> <property name="left_attach">1</property> <property name="top_attach">1</property> - <property name="width">2</property> </packing> </child> <child> @@ -1512,7 +1547,6 @@ Author: Antenore Gatta <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Use secret key authentication for some widgets</property> <property name="halign">start</property> - <property name="margin_left">36</property> <property name="margin_start">36</property> <property name="margin_top">9</property> <property name="margin_bottom">9</property> @@ -1542,7 +1576,6 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">True</property> <property name="tooltip_text" translatable="yes">Master password validity in seconds</property> - <property name="halign">start</property> <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="width_chars">24</property> @@ -1552,7 +1585,6 @@ Author: Antenore Gatta <packing> <property name="left_attach">1</property> <property name="top_attach">2</property> - <property name="width">2</property> </packing> </child> <child> @@ -1571,7 +1603,7 @@ Author: Antenore Gatta <packing> <property name="left_attach">0</property> <property name="top_attach">7</property> - <property name="width">3</property> + <property name="width">2</property> </packing> </child> <child> @@ -1579,7 +1611,6 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">36</property> <property name="margin_start">36</property> <property name="label" translatable="yes">Password</property> </object> @@ -1593,7 +1624,6 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">36</property> <property name="margin_start">36</property> <property name="label" translatable="yes">Repeat the password</property> </object> @@ -1606,7 +1636,6 @@ Author: Antenore Gatta <object class="GtkEntry" id="unlock_password"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="visibility">False</property> @@ -1617,14 +1646,12 @@ Author: Antenore Gatta <packing> <property name="left_attach">1</property> <property name="top_attach">3</property> - <property name="width">2</property> </packing> </child> <child> <object class="GtkEntry" id="unlock_repassword"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="halign">start</property> <property name="margin_end">18</property> <property name="hexpand">True</property> <property name="visibility">False</property> @@ -1639,7 +1666,6 @@ Author: Antenore Gatta <packing> <property name="left_attach">1</property> <property name="top_attach">4</property> - <property name="width">2</property> </packing> </child> <child> @@ -1658,7 +1684,7 @@ Author: Antenore Gatta <packing> <property name="left_attach">0</property> <property name="top_attach">5</property> - <property name="width">3</property> + <property name="width">2</property> </packing> </child> <child> @@ -1692,7 +1718,6 @@ Author: Antenore Gatta <packing> <property name="left_attach">1</property> <property name="top_attach">6</property> - <property name="width">2</property> </packing> </child> </object> @@ -1704,6 +1729,8 @@ Author: Antenore Gatta <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Security</property> </object> <packing> @@ -1724,7 +1751,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_top">18</property> <property name="label" translatable="yes">Terminal font</property> </object> @@ -1738,7 +1765,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Scrollback lines</property> </object> <packing> @@ -1805,7 +1832,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Shortcut for copying to clipboard</property> </object> <packing> @@ -1818,7 +1845,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Shortcut for pasting from clipboard</property> </object> <packing> @@ -1831,7 +1858,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Select all shortcuts</property> </object> <packing> @@ -1898,7 +1925,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Use default system font</property> </object> <packing> @@ -1937,7 +1964,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Allow using bright colours with bold text</property> </object> <packing> @@ -1950,7 +1977,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="margin_bottom">18</property> <property name="label" translatable="yes">Colour theme</property> </object> @@ -1980,7 +2007,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Bright colours</property> </object> <packing> @@ -2187,7 +2214,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Normal colours</property> </object> <packing> @@ -2200,7 +2227,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Cursor colour</property> </object> <packing> @@ -2228,7 +2255,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Background colour</property> </object> <packing> @@ -2271,7 +2298,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Foreground colour</property> </object> <packing> @@ -2284,7 +2311,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Increase font size</property> </object> <packing> @@ -2297,7 +2324,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Decrease font size</property> </object> <packing> @@ -2346,7 +2373,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="margin_left">18</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Search text</property> </object> <packing> @@ -2376,6 +2403,7 @@ Author: Antenore Gatta <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="margin_start">18</property> <property name="label" translatable="yes">Bold colour</property> </object> <packing> @@ -2407,6 +2435,8 @@ Author: Antenore Gatta <object class="GtkLabel" id="label_tab_terminal"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="halign">end</property> + <property name="margin_end">18</property> <property name="label" translatable="yes">Terminal</property> </object> <packing> diff --git a/plugins/rdp/rdp_monitor.c b/plugins/rdp/rdp_monitor.c index a590f791d0..01c024025d 100644 --- a/plugins/rdp/rdp_monitor.c +++ b/plugins/rdp/rdp_monitor.c @@ -70,7 +70,7 @@ void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwi TRACE_CALL(__func__); GdkDisplay *display; - GdkMonitor *current_monitor, *monitor; + GdkMonitor *monitor; gboolean has_custom_monitors = FALSE; gboolean primary_found = FALSE; @@ -210,10 +210,10 @@ void remmina_rdp_monitor_get (rfContext *rfi, gchar **monitorids, guint32 *maxwi { settings->MonitorDefArray[i].x = settings->MonitorDefArray[i].x - settings->MonitorLocalShiftX; - REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", index, settings->MonitorDefArray[index].x); + REMMINA_PLUGIN_DEBUG("Monitor n %d calculated x: %d", i, settings->MonitorDefArray[i].x); settings->MonitorDefArray[i].y = settings->MonitorDefArray[i].y - settings->MonitorLocalShiftY; - REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", index, settings->MonitorDefArray[index].y); + REMMINA_PLUGIN_DEBUG("Monitor n %d calculated y: %d", i, settings->MonitorDefArray[i].y); } REMMINA_PLUGIN_DEBUG("%d monitors on %d have been configured", rfi->settings->MonitorCount, count); diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index cb114a6582..15bfcbb51b 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -84,6 +84,7 @@ #define REMMINA_RDP_FEATURE_UNFOCUS 3 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5 +#define REMMINA_RDP_FEATURE_MULTIMON 6 #define REMMINA_CONNECTION_TYPE_NONE 0 @@ -1775,13 +1776,9 @@ static gboolean remmina_rdp_main(RemminaProtocolWidget *gp) /* TODO Add an option for this */ rfi->settings->ForceMultimon = TRUE; rfi->settings->Fullscreen = TRUE; - //if (!rfi->settings->NumMonitorIds) - //rfi->settings->NumMonitorIds = 0; gchar *monitorids = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids")); /* Otherwise we get all the attached monitors */ - //if (monitorids != NULL && monitorids[0] != '\0') - //gchar *monitorids = NULL; remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight); if (monitorids != NULL && monitorids[0] != '\0') { gchar **items; @@ -2269,22 +2266,36 @@ static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaPro if (rfi) { rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp); remmina_rdp_event_update_scale(gp); - } else { - printf("Remmina RDP plugin warning: Null value for rfi in %s REMMINA_RDP_FEATURE_SCALE\n", __func__); + } else + REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_SCALE"); + break; + + case REMMINA_RDP_FEATURE_MULTIMON: + if (rfi) { + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) { + rfi->settings->UseMultimon = TRUE; + /* TODO Add an option for this */ + rfi->settings->ForceMultimon = TRUE; + rfi->settings->Fullscreen = TRUE; + remmina_rdp_event_send_delayed_monitor_layout(gp); + } + } + else + REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_MULTIMON"); break; case REMMINA_RDP_FEATURE_DYNRESUPDATE: break; case REMMINA_RDP_FEATURE_TOOL_REFRESH: - if (rfi) { + if (rfi) gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, - remmina_plugin_service->protocol_plugin_get_width(gp), - remmina_plugin_service->protocol_plugin_get_height(gp)); - } else { - printf("Remmina RDP plugin warning: Null value for rfi in %s REMMINA_RDP_FEATURE_TOOL_REFRESH\n", __func__); - } + remmina_plugin_service->protocol_plugin_get_width(gp), + remmina_plugin_service->protocol_plugin_get_height(gp)); + else + REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_TOOL_REFRESH"); break; case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL: @@ -2574,6 +2585,7 @@ static const RemminaProtocolFeature remmina_rdp_features[] = { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_RDP_FEATURE_MULTIMON, NULL, NULL, NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL }, { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL } diff --git a/plugins/rdp/rdp_settings.c b/plugins/rdp/rdp_settings.c index 9ec68ae589..fd04effdad 100644 --- a/plugins/rdp/rdp_settings.c +++ b/plugins/rdp/rdp_settings.c @@ -223,7 +223,6 @@ static void remmina_rdp_settings_grid_load_layout(RemminaPluginRdpsetGrid* grid) free(layouts); } - static void remmina_rdp_settings_grid_load_devicescalefactor_combo(RemminaPluginRdpsetGrid* grid) { TRACE_CALL(__func__); @@ -256,7 +255,6 @@ static void remmina_rdp_settings_grid_load_desktoporientation_combo(RemminaPlugi } - static void remmina_rdp_settings_grid_load_quality(RemminaPluginRdpsetGrid* grid) { TRACE_CALL(__func__); diff --git a/src/include/remmina/types.h b/src/include/remmina/types.h index 19488bf14a..b8d448e6e4 100644 --- a/src/include/remmina/types.h +++ b/src/include/remmina/types.h @@ -49,6 +49,7 @@ typedef enum { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, + REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_PROTOCOL_FEATURE_TYPE_GTKSOCKET } RemminaProtocolFeatureType; diff --git a/src/rcw.c b/src/rcw.c index 58a15105a6..2b898aee99 100644 --- a/src/rcw.c +++ b/src/rcw.c @@ -111,6 +111,7 @@ struct _RemminaConnectionWindowPriv { GtkToolItem * toolitem_dynres; GtkToolItem * toolitem_scale; GtkToolItem * toolitem_grab; + GtkToolItem * toolitem_multimon; GtkToolItem * toolitem_preferences; GtkToolItem * toolitem_tools; GtkToolItem * toolitem_duplicate; @@ -1656,6 +1657,28 @@ static void rcw_toolbar_scaled_mode(GtkToolItem *toggle, RemminaConnectionWindow rco_change_scalemode(cnnobj, bdyn, bscale); } +static void rcw_toolbar_multi_monitor_mode(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin) +{ + TRACE_CALL(__func__); + RemminaConnectionObject *cnnobj; + + if (cnnwin->priv->toolbar_is_reconfiguring) + return; + + if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return; + + if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toggle))) { + remmina_file_set_int(cnnobj->remmina_file, "multimon", 1); + remmina_protocol_widget_call_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), + REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, 0); + // Here we need a new rcw->toolbar->fullscreen_toggle. passing this toggle is a mistake + rcw_toolbar_fullscreen(cnnwin->priv->toolitem_fullscreen, cnnwin); + } else { + remmina_file_set_int(cnnobj->remmina_file, "multimon", 0); + rcw_toolbar_fullscreen(NULL, cnnwin); + } +} + static void rcw_toolbar_preferences_popdown(GtkToolItem *toggle, RemminaConnectionWindow *cnnwin) { TRACE_CALL(__func__); @@ -2139,6 +2162,12 @@ rcw_create_toolbar(RemminaConnectionWindow *cnnwin, gint mode) GtkWidget *widget; GtkWidget *arrow; + GdkDisplay *display; + gint n_monitors; + + display = gdk_display_get_default (); + n_monitors = gdk_display_get_n_monitors(display); + cnnobj = rcw_get_visible_cnnobj(cnnwin); priv->toolbar_is_reconfiguring = TRUE; @@ -2264,6 +2293,19 @@ rcw_create_toolbar(RemminaConnectionWindow *cnnwin, gint mode) g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(rcw_toolbar_scaler_option), cnnwin); priv->scaler_option_button = widget; + /* Multi monitor */ + + if (n_monitors > 1) { + toolitem = gtk_toggle_tool_button_new(); + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-multi-monitor-symbolic"); + rcw_set_tooltip(GTK_WIDGET(toolitem), _("Multi monitor"), + remmina_pref.shortcutkey_multimon, 0); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); + gtk_widget_show(GTK_WIDGET(toolitem)); + g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_multi_monitor_mode), cnnwin); + priv->toolitem_multimon = toolitem; + } + /* Grab keyboard button */ toolitem = gtk_toggle_tool_button_new(); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-keyboard-symbolic"); @@ -2381,7 +2423,6 @@ static void rco_update_toolbar(RemminaConnectionObject *cnnobj) rco_update_toolbar_autofit_button(cnnobj); - toolitem = priv->toolitem_switch_page; if (kioskmode) bval = FALSE; diff --git a/src/remmina_main.c b/src/remmina_main.c index aaec2fb5f7..1edc329fb7 100644 --- a/src/remmina_main.c +++ b/src/remmina_main.c @@ -1409,6 +1409,7 @@ GtkWidget *remmina_main_new(void) gtk_window_add_accel_group(remminamain->window, accel_group); gtk_accel_group_connect(accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0, g_cclosure_new_swap(G_CALLBACK(remmina_main_on_action_application_quit), NULL, NULL)); + // TODO: This crash remmina because the function doesn't receive the parameter we expect gtk_accel_group_connect(accel_group, GDK_KEY_P, GDK_CONTROL_MASK, 0, g_cclosure_new_swap(G_CALLBACK(remmina_main_on_accel_application_preferences), NULL, NULL)); gtk_accel_group_connect(accel_group, GDK_KEY_F, GDK_CONTROL_MASK, 0, diff --git a/src/remmina_pref.c b/src/remmina_pref.c index 4b6a9eaf62..0d46f79104 100644 --- a/src/remmina_pref.c +++ b/src/remmina_pref.c @@ -563,6 +563,11 @@ void remmina_pref_init(void) else remmina_pref.shortcutkey_viewonly = GDK_KEY_m; + if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_multimon", NULL)) + remmina_pref.shortcutkey_multimon = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_multimon", NULL); + else + remmina_pref.shortcutkey_multimon = GDK_KEY_Page_Up; + if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_grab", NULL)) remmina_pref.shortcutkey_grab = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_grab", NULL); else @@ -809,6 +814,7 @@ gboolean remmina_pref_save(void) g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_prevtab", remmina_pref.shortcutkey_prevtab); g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_scale", remmina_pref.shortcutkey_scale); g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_grab", remmina_pref.shortcutkey_grab); + g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_multimon", remmina_pref.shortcutkey_multimon); g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_viewonly", remmina_pref.shortcutkey_viewonly); g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_screenshot", remmina_pref.shortcutkey_screenshot); g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_minimize", remmina_pref.shortcutkey_minimize); diff --git a/src/remmina_pref.h b/src/remmina_pref.h index a7964a2f53..1b7b507d00 100644 --- a/src/remmina_pref.h +++ b/src/remmina_pref.h @@ -35,6 +35,7 @@ */ #pragma once +#include <gtk/gtk.h> /* * Remmina Preference Loader @@ -152,6 +153,7 @@ typedef struct _RemminaPref { guint shortcutkey_nexttab; guint shortcutkey_dynres; guint shortcutkey_scale; + guint shortcutkey_multimon; guint shortcutkey_grab; guint shortcutkey_viewonly; guint shortcutkey_screenshot; diff --git a/src/remmina_pref_dialog.c b/src/remmina_pref_dialog.c index 6f228753b6..ca1972e7f7 100644 --- a/src/remmina_pref_dialog.c +++ b/src/remmina_pref_dialog.c @@ -56,6 +56,12 @@ static RemminaPrefDialog *remmina_pref_dialog; #define GET_OBJECT(object_name) gtk_builder_get_object(remmina_pref_dialog->builder, object_name) +static GActionEntry pref_actions[] = { + { "close", remmina_pref_dialog_on_action_close, NULL, NULL, NULL }, + +}; + + /* Show a key chooser dialog */ void remmina_pref_dialog_on_key_chooser(GtkWidget *widget, gpointer user_data) { @@ -188,6 +194,11 @@ void remmina_prefdiag_unlock_repwd_on_changed(GtkEditable* editable, RemminaPref } +void remmina_pref_dialog_on_action_close(GSimpleAction *action, GVariant *param, gpointer data) +{ + TRACE_CALL(__func__); + gtk_widget_destroy(GTK_WIDGET(remmina_pref_dialog->dialog)); +} void remmina_pref_dialog_on_close_clicked(GtkWidget *widget, RemminaPrefDialog *dialog) { TRACE_CALL(__func__); @@ -296,6 +307,7 @@ void remmina_pref_on_dialog_destroy(GtkWidget *widget, gpointer user_data) remmina_pref.shortcutkey_prevtab = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_switch_tab_left)); remmina_pref.shortcutkey_nexttab = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_switch_tab_right)); remmina_pref.shortcutkey_scale = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_scaled)); + remmina_pref.shortcutkey_multimon = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_multimon)); remmina_pref.shortcutkey_grab = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_grab_keyboard)); remmina_pref.shortcutkey_screenshot = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_screenshot)); remmina_pref.shortcutkey_viewonly = remmina_key_chooser_get_keyval(gtk_button_get_label(remmina_pref_dialog->button_keyboard_viewonly)); @@ -374,6 +386,8 @@ static gboolean remmina_pref_dialog_add_pref_plugin(gchar *name, RemminaPlugin * pref_plugin = (RemminaPrefPlugin*)plugin; widget = gtk_label_new(pref_plugin->pref_label); + gtk_widget_set_halign(widget, GTK_ALIGN_END); + gtk_widget_set_margin_end(widget, 18); gtk_widget_show(widget); vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); @@ -495,6 +509,7 @@ static void remmina_pref_dialog_init(void) remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_switch_tab_left, remmina_pref.shortcutkey_prevtab); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_switch_tab_right, remmina_pref.shortcutkey_nexttab); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_scaled, remmina_pref.shortcutkey_scale); + remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_multimon, remmina_pref.shortcutkey_multimon); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_grab_keyboard, remmina_pref.shortcutkey_grab); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_screenshot, remmina_pref.shortcutkey_screenshot); remmina_pref_dialog_set_button_label(remmina_pref_dialog->button_keyboard_viewonly, remmina_pref.shortcutkey_viewonly); @@ -633,6 +648,8 @@ static void remmina_pref_dialog_init(void) GtkDialog* remmina_pref_dialog_new(gint default_tab, GtkWindow *parent) { TRACE_CALL(__func__); + GSimpleActionGroup *actions; + GtkAccelGroup *accel_group = NULL; remmina_pref_dialog = g_new0(RemminaPrefDialog, 1); remmina_pref_dialog->priv = g_new0(RemminaPrefDialogPriv, 1); @@ -692,6 +709,7 @@ GtkDialog* remmina_pref_dialog_new(gint default_tab, GtkWindow *parent) remmina_pref_dialog->button_keyboard_switch_tab_right = GTK_BUTTON(GET_OBJECT("button_keyboard_switch_tabright")); remmina_pref_dialog->button_keyboard_scaled = GTK_BUTTON(GET_OBJECT("button_keyboard_scaled")); remmina_pref_dialog->button_keyboard_grab_keyboard = GTK_BUTTON(GET_OBJECT("button_keyboard_grab_keyboard")); + remmina_pref_dialog->button_keyboard_multimon = GTK_BUTTON(GET_OBJECT("button_keyboard_multimon")); remmina_pref_dialog->button_keyboard_screenshot = GTK_BUTTON(GET_OBJECT("button_keyboard_screenshot")); remmina_pref_dialog->button_keyboard_viewonly = GTK_BUTTON(GET_OBJECT("button_keyboard_viewonly")); remmina_pref_dialog->button_keyboard_minimize = GTK_BUTTON(GET_OBJECT("button_keyboard_minimize")); @@ -752,6 +770,17 @@ GtkDialog* remmina_pref_dialog_new(gint default_tab, GtkWindow *parent) g_free(destpath); #endif #endif + /* Non widget objects */ + actions = g_simple_action_group_new(); + g_action_map_add_action_entries(G_ACTION_MAP(actions), pref_actions, G_N_ELEMENTS(pref_actions), remmina_pref_dialog->dialog); + gtk_widget_insert_action_group(GTK_WIDGET(remmina_pref_dialog->dialog), "pref", G_ACTION_GROUP(actions)); + g_action_map_add_action_entries(G_ACTION_MAP(actions), pref_actions, G_N_ELEMENTS(pref_actions), remmina_pref_dialog->dialog); + g_object_unref(actions); + /* Accelerators */ + accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(remmina_pref_dialog->dialog), accel_group); + gtk_accel_group_connect(accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0, + g_cclosure_new_swap(G_CALLBACK(remmina_pref_dialog_on_action_close), NULL, NULL)); /* Connect signals */ gtk_builder_connect_signals(remmina_pref_dialog->builder, NULL); diff --git a/src/remmina_pref_dialog.h b/src/remmina_pref_dialog.h index 18319c6296..87bb481731 100644 --- a/src/remmina_pref_dialog.h +++ b/src/remmina_pref_dialog.h @@ -34,6 +34,7 @@ */ #pragma once +#include <gtk/gtk.h> /* * Remmina Preferences Dialog @@ -95,6 +96,7 @@ typedef struct _RemminaPrefDialog { GtkButton * button_keyboard_switch_tab_left; GtkButton * button_keyboard_switch_tab_right; GtkButton * button_keyboard_scaled; + GtkButton * button_keyboard_multimon; GtkButton * button_keyboard_grab_keyboard; GtkButton * button_keyboard_screenshot; GtkButton * button_keyboard_viewonly; @@ -156,5 +158,6 @@ GtkDialog *remmina_pref_dialog_new(gint default_tab, GtkWindow *parent); /* Get the current PrefDialog or NULL if not initialized */ GtkDialog *remmina_pref_dialog_get_dialog(void); void remmina_prefdiag_unlock_repwd_on_changed(GtkEditable *editable, RemminaPrefDialog *dialog); +void remmina_pref_dialog_on_action_close(GSimpleAction *action, GVariant *param, gpointer data); G_END_DECLS -- GitLab From fbeab11e3aefbbd4931eec6ee2cc3c1bb5b5695c Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Mon, 1 Feb 2021 10:02:52 +0100 Subject: [PATCH 7/8] Setting toolbar status updates for multi monitor --- src/rcw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/rcw.c b/src/rcw.c index 2b898aee99..a57fded6b6 100644 --- a/src/rcw.c +++ b/src/rcw.c @@ -1671,8 +1671,8 @@ static void rcw_toolbar_multi_monitor_mode(GtkToolItem *toggle, RemminaConnectio remmina_file_set_int(cnnobj->remmina_file, "multimon", 1); remmina_protocol_widget_call_feature_by_type(REMMINA_PROTOCOL_WIDGET(cnnobj->proto), REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, 0); - // Here we need a new rcw->toolbar->fullscreen_toggle. passing this toggle is a mistake - rcw_toolbar_fullscreen(cnnwin->priv->toolitem_fullscreen, cnnwin); + if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_fullscreen))) + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(cnnwin->priv->toolitem_fullscreen), TRUE); } else { remmina_file_set_int(cnnobj->remmina_file, "multimon", 0); rcw_toolbar_fullscreen(NULL, cnnwin); @@ -2457,6 +2457,11 @@ static void rco_update_toolbar(RemminaConnectionObject *cnnobj) break; } + toolitem = priv->toolitem_multimon; + gtk_widget_set_sensitive(GTK_WIDGET(toolitem), cnnobj->connected); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem), + remmina_file_get_int(cnnobj->remmina_file, "multimon", FALSE)); + toolitem = priv->toolitem_grab; gtk_widget_set_sensitive(GTK_WIDGET(toolitem), cnnobj->connected); gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(toolitem), -- GitLab From bdf5f37e10c4a8d3278d9531841941b984999d14 Mon Sep 17 00:00:00 2001 From: Antenore Gatta <antenore@simbiosi.org> Date: Tue, 2 Feb 2021 11:52:40 +0100 Subject: [PATCH 8/8] Moving the multi monitor icon up close to fullscreen --- src/rcw.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/rcw.c b/src/rcw.c index a57fded6b6..9cb882adb7 100644 --- a/src/rcw.c +++ b/src/rcw.c @@ -2234,6 +2234,18 @@ rcw_create_toolbar(RemminaConnectionWindow *cnnwin, gint mode) if (mode == SCROLLED_WINDOW_MODE) gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + /* Multi monitor */ + if (n_monitors > 1) { + toolitem = gtk_toggle_tool_button_new(); + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-multi-monitor-symbolic"); + rcw_set_tooltip(GTK_WIDGET(toolitem), _("Multi monitor"), + remmina_pref.shortcutkey_multimon, 0); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); + gtk_widget_show(GTK_WIDGET(toolitem)); + g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_multi_monitor_mode), cnnwin); + priv->toolitem_multimon = toolitem; + } + /* Switch tabs */ toolitem = gtk_toggle_tool_button_new(); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-switch-page-symbolic"); @@ -2293,19 +2305,6 @@ rcw_create_toolbar(RemminaConnectionWindow *cnnwin, gint mode) g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(rcw_toolbar_scaler_option), cnnwin); priv->scaler_option_button = widget; - /* Multi monitor */ - - if (n_monitors > 1) { - toolitem = gtk_toggle_tool_button_new(); - gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-multi-monitor-symbolic"); - rcw_set_tooltip(GTK_WIDGET(toolitem), _("Multi monitor"), - remmina_pref.shortcutkey_multimon, 0); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); - gtk_widget_show(GTK_WIDGET(toolitem)); - g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK(rcw_toolbar_multi_monitor_mode), cnnwin); - priv->toolitem_multimon = toolitem; - } - /* Grab keyboard button */ toolitem = gtk_toggle_tool_button_new(); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "remmina-keyboard-symbolic"); -- GitLab