diff options
-rw-r--r-- | plugins/rdp/rdp_event.c | 3 | ||||
-rw-r--r-- | plugins/rdp/rdp_plugin.c | 18 | ||||
-rw-r--r-- | src/include/remmina/types.h | 7 | ||||
-rw-r--r-- | src/remmina_connection_window.c | 66 | ||||
-rw-r--r-- | src/remmina_file_editor.c | 79 | ||||
-rw-r--r-- | src/remmina_protocol_widget.c | 53 | ||||
-rw-r--r-- | src/remmina_protocol_widget.h | 4 |
7 files changed, 178 insertions, 52 deletions
diff --git a/plugins/rdp/rdp_event.c b/plugins/rdp/rdp_event.c index b6c643a10..23cb50bd3 100644 --- a/plugins/rdp/rdp_event.c +++ b/plugins/rdp/rdp_event.c @@ -314,9 +314,6 @@ static gboolean remmina_rdp_event_on_draw(GtkWidget* widget, cairo_t* context, R if (!rfi->surface) return FALSE; - GtkAllocation a; - gtk_widget_get_allocation(GTK_WIDGET(gp), &a); - if (rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) cairo_scale(context, rfi->scale_x, rfi->scale_y); diff --git a/plugins/rdp/rdp_plugin.c b/plugins/rdp/rdp_plugin.c index 293370a44..6c25d9460 100644 --- a/plugins/rdp/rdp_plugin.c +++ b/plugins/rdp/rdp_plugin.c @@ -1424,17 +1424,25 @@ static void remmina_rdp_call_feature(RemminaProtocolWidget* gp, const RemminaPro break; case REMMINA_RDP_FEATURE_SCALE: - rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp); - remmina_rdp_event_update_scale(gp); + 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: rfi is null in %s REMMINA_RDP_FEATURE_SCALE\n", __func__); + } break; case REMMINA_RDP_FEATURE_DYNRESUPDATE: break; case REMMINA_RDP_FEATURE_TOOL_REFRESH: - 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)); + 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: rfi is null in %s REMMINA_RDP_FEATURE_TOOL_REFRESH\n", __func__); + } break; case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL: diff --git a/src/include/remmina/types.h b/src/include/remmina/types.h index 46cb93afe..5178e151d 100644 --- a/src/include/remmina/types.h +++ b/src/include/remmina/types.h @@ -121,6 +121,13 @@ typedef enum { REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES = 2 } RemminaScaleMode; +typedef enum { + RES_INVALID = -1, + RES_USE_CUSTOM = 0, + RES_USE_CLIENT = 1, + RES_USE_INITIAL_WINDOW_SIZE = 2 +} RemminaProtocolWidgetResolutionMode; + G_END_DECLS diff --git a/src/remmina_connection_window.c b/src/remmina_connection_window.c index ab91f3f12..0ab9e2575 100644 --- a/src/remmina_connection_window.c +++ b/src/remmina_connection_window.c @@ -158,6 +158,9 @@ typedef struct _RemminaConnectionObject { gboolean connected; gboolean dynres_unlocked; + + gulong deferred_open_size_allocate_handler; + } RemminaConnectionObject; struct _RemminaConnectionHolder { @@ -3900,6 +3903,38 @@ gboolean remmina_connection_window_open_from_filename(const gchar* filename) } } +static gboolean open_connection_last_stage(gpointer user_data) +{ + RemminaProtocolWidget *gp = (RemminaProtocolWidget *)user_data; + + /* Now we have an allocated size for our RemminaProtocolWidget. We can proceed with the connection */ + remmina_protocol_widget_update_remote_resolution(gp); + remmina_protocol_widget_open_connection(gp); + + return FALSE; +} + +static void rpw_size_allocated_on_connection(GtkWidget *w, GdkRectangle *allocation, gpointer user_data) +{ + RemminaProtocolWidget *gp = (RemminaProtocolWidget *)w; + + /* Disconnect signal handler to avoid to be called again after a normal resize */ + g_signal_handler_disconnect(w, gp->cnnobj->deferred_open_size_allocate_handler); + + /* Schedule a connection ASAP */ + if (remmina_file_get_int(gp->cnnobj->remmina_file, "resolution_mode", RES_INVALID) == RES_USE_INITIAL_WINDOW_SIZE) { + /* Allow the WM to decide the real size of our windows before reading current window + * size and connecting: some WM, i.e. GnomeShell/mutter with edge-tiling, + * will resize our window after creating it, so we must wait to be in a stable state + * before reading the window internal widgets allocated size for RES_USE_INTERNAL_WINDOW_SIZE */ + g_timeout_add(200, open_connection_last_stage, gp); + } + else + g_idle_add(open_connection_last_stage, gp); + + return; +} + void remmina_connection_window_open_from_file(RemminaFile* remminafile) { TRACE_CALL(__func__); @@ -3916,6 +3951,7 @@ GtkWidget* remmina_connection_window_open_from_file_full(RemminaFile* remminafil RemminaConnectionWindow* cnnwin; GtkWidget* tab; gint i; + gboolean defer_connection_after_size_allocation; /* Create the RemminaConnectionObject */ cnnobj = g_new0(RemminaConnectionObject, 1); @@ -3934,14 +3970,6 @@ GtkWidget* remmina_connection_window_open_from_file_full(RemminaFile* remminafil g_object_set_data(G_OBJECT(cnnobj->proto), "user-data", data); } - - /* Set default remote desktop size in the profile, so the plugins can query - * protocolwidget and know WxH that the user put on the profile settings */ - remmina_protocol_widget_update_remote_resolution((RemminaProtocolWidget*)cnnobj->proto, - remmina_file_get_int(remminafile, "resolution_width", -1), - remmina_file_get_int(remminafile, "resolution_height", -1) - ); - /* Create the viewport to make the RemminaProtocolWidget scrollable */ cnnobj->viewport = gtk_viewport_new(NULL, NULL); gtk_widget_set_name(cnnobj->viewport, "remmina-cw-viewport"); @@ -4038,7 +4066,27 @@ GtkWidget* remmina_connection_window_open_from_file_full(RemminaFile* remminafil return cnnobj->proto; } - remmina_protocol_widget_open_connection(REMMINA_PROTOCOL_WIDGET((RemminaProtocolWidget*)cnnobj->proto), remminafile); + + /* GTK window setup is done here, and we are almost ready to call remmina_protocol_widget_open_connection(). + * But size has not yet been allocated by GTK + * to the widgets. If we are in RES_USE_INITIAL_WINDOW_SIZE resolution mode, + * we should wait for a size allocation from GTK for cnnobj->proto + * before connecting */ + + defer_connection_after_size_allocation = FALSE; + if (remmina_file_get_int(remminafile, "resolution_mode", RES_INVALID) == RES_USE_INITIAL_WINDOW_SIZE) { + GtkAllocation al; + gtk_widget_get_allocation(cnnobj->proto, &al); + if (al.width < 10 || al.height < 10) { + defer_connection_after_size_allocation = TRUE; + } + } + + if (defer_connection_after_size_allocation) { + cnnobj->deferred_open_size_allocate_handler = g_signal_connect(G_OBJECT(cnnobj->proto), "size-allocate", G_CALLBACK(rpw_size_allocated_on_connection), NULL); + } else { + g_idle_add(open_connection_last_stage, cnnobj->proto); + } return cnnobj->proto; diff --git a/src/remmina_file_editor.c b/src/remmina_file_editor.c index 0597ad35d..1848a4d00 100644 --- a/src/remmina_file_editor.c +++ b/src/remmina_file_editor.c @@ -119,6 +119,7 @@ struct _RemminaFileEditorPriv { GtkWidget* config_container; GtkWidget* server_combo; + GtkWidget* resolution_iws_radio; GtkWidget* resolution_auto_radio; GtkWidget* resolution_custom_radio; GtkWidget* resolution_custom_combo; @@ -498,8 +499,26 @@ static void remmina_file_editor_create_resolution(RemminaFileEditor* gfe, const TRACE_CALL(__func__); GtkWidget* widget; GtkWidget* hbox; - const gchar *resolution_w, *resolution_h; + int resolution_w, resolution_h; gchar *res_str; + RemminaProtocolWidgetResolutionMode res_mode; + + res_mode = remmina_file_get_int(gfe->priv->remmina_file, "resolution_mode", RES_INVALID); + resolution_w = remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", -1); + resolution_h = remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", -1); + + /* If resolution_mode is non-existent (-1), then we try to calculate it + * as we did before having resolution_mode */ + if (res_mode == RES_INVALID) { + if (resolution_w <= 0 || resolution_h <= 0) + res_mode = RES_USE_INITIAL_WINDOW_SIZE; + else + res_mode = RES_USE_CUSTOM; + } + if (res_mode == RES_USE_CUSTOM) + res_str = g_strdup_printf("%dx%d", resolution_w, resolution_h); + else + res_str = NULL; widget = gtk_label_new(_("Resolution")); gtk_widget_show(widget); @@ -507,27 +526,27 @@ static void remmina_file_editor_create_resolution(RemminaFileEditor* gfe, const gtk_widget_set_halign(widget, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1); - widget = gtk_radio_button_new_with_label(NULL, setting->opt1 ? _("Use window size") : _("Use client resolution")); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + widget = gtk_radio_button_new_with_label(NULL, _("Use initial window size")); gtk_widget_show(widget); - gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gfe->priv->resolution_iws_radio = widget; + widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Use client resolution")); + gtk_widget_show(widget); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); gfe->priv->resolution_auto_radio = widget; + gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1); + gtk_widget_show(hbox); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show(hbox); gtk_grid_attach(GTK_GRID(grid), hbox, 1, row + 1, 1, 1); - widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_auto_radio), _("Custom")); + widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Custom")); gtk_widget_show(widget); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0); gfe->priv->resolution_custom_radio = widget; - resolution_w = remmina_file_get_string(gfe->priv->remmina_file, "resolution_width"); - resolution_h = remmina_file_get_string(gfe->priv->remmina_file, "resolution_height"); - - if (resolution_w && resolution_h && resolution_w[0] != 0 && resolution_h[0] != 0) - res_str = g_strdup_printf("%sx%s", resolution_w, resolution_h); - else - res_str = NULL; widget = remmina_public_create_combo_text_d(remmina_pref.resolutions, res_str, NULL); gtk_widget_show(widget); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); @@ -541,13 +560,16 @@ static void remmina_file_editor_create_resolution(RemminaFileEditor* gfe, const g_signal_connect(G_OBJECT(gfe->priv->resolution_custom_radio), "toggled", G_CALLBACK(remmina_file_editor_button_on_toggled), gfe->priv->resolution_custom_combo); - if (res_str) { + if (res_mode == RES_USE_CUSTOM) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio), TRUE); - }else { + }else if (res_mode == RES_USE_CLIENT) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_auto_radio), TRUE); - gtk_widget_set_sensitive(gfe->priv->resolution_custom_combo, FALSE); + }else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_iws_radio), TRUE); } + gtk_widget_set_sensitive(gfe->priv->resolution_custom_combo, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio))); + g_free(res_str); } @@ -701,7 +723,7 @@ static void remmina_file_editor_create_settings(RemminaFileEditor* gfe, GtkWidge case REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION: remmina_file_editor_create_resolution(gfe, settings, grid, grid_row); - grid_row++; + grid_row += 1; break; case REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP: @@ -995,6 +1017,7 @@ static void remmina_file_editor_protocol_combo_on_changed(GtkComboBox* combo, Re } priv->server_combo = NULL; + priv->resolution_iws_radio = NULL; priv->resolution_auto_radio = NULL; priv->resolution_custom_radio = NULL; priv->resolution_custom_combo = NULL; @@ -1106,8 +1129,9 @@ static void remmina_file_editor_update_settings(RemminaFileEditor* gfe) static void remmina_file_editor_update(RemminaFileEditor* gfe) { TRACE_CALL(__func__); - gchar *custom_resolution, *res_w, *res_h; - int w, h; + int res_w, res_h; + gchar *custom_resolution; + RemminaProtocolWidgetResolutionMode res_mode; RemminaFileEditorPriv* priv = gfe->priv; @@ -1127,21 +1151,26 @@ static void remmina_file_editor_update(RemminaFileEditor* gfe) if (priv->resolution_auto_radio) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_auto_radio))) { - /* Resolution is set to auto */ - res_w = res_h = NULL; + /* Resolution is set to auto (which means: use client fullscreen resolution, aka use client resolution) */ + res_w = res_h = 0; + res_mode = RES_USE_CLIENT; + }else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_iws_radio))) { + /* Resolution is set to initial window size */ + res_w = res_h = 0; + res_mode = RES_USE_INITIAL_WINDOW_SIZE; }else { /* Resolution is set to a value from the list */ custom_resolution = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->resolution_custom_combo)); - if (remmina_public_split_resolution_string(custom_resolution, &w, &h)) { - res_w = g_strdup_printf("%i", w); - res_h = g_strdup_printf("%i", h); + if (remmina_public_split_resolution_string(custom_resolution, &res_w, &res_h)) { + res_mode = RES_USE_CUSTOM; }else { - res_w = res_h = NULL; + res_mode = RES_USE_INITIAL_WINDOW_SIZE; } g_free(custom_resolution); } - remmina_file_set_string_ref(priv->remmina_file, "resolution_width", res_w); - remmina_file_set_string_ref(priv->remmina_file, "resolution_height", res_h); + remmina_file_set_int(priv->remmina_file, "resolution_mode", res_mode); + remmina_file_set_int(priv->remmina_file, "resolution_width", res_w); + remmina_file_set_int(priv->remmina_file, "resolution_height", res_h); } if (priv->keymap_combo) { diff --git a/src/remmina_protocol_widget.c b/src/remmina_protocol_widget.c index 38e8cbbc4..ca6f0e33b 100644 --- a/src/remmina_protocol_widget.c +++ b/src/remmina_protocol_widget.c @@ -216,6 +216,7 @@ static void remmina_protocol_widget_init(RemminaProtocolWidget* gp) priv = g_new0(RemminaProtocolWidgetPriv, 1); gp->priv = priv; + gp->priv->closed = TRUE; g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL); g_signal_connect(G_OBJECT(gp), "connect", G_CALLBACK(remmina_protocol_widget_on_connected), NULL); @@ -232,6 +233,8 @@ void remmina_protocol_widget_open_connection_real(gpointer data) gint num_plugin; gint num_ssh; + gp->priv->closed = FALSE; + plugin = gp->priv->plugin; plugin->init(gp); @@ -282,26 +285,25 @@ static void cancel_open_connection_cb(void *cbdata, int btn) remmina_protocol_widget_close_connection(gp); } -void remmina_protocol_widget_open_connection(RemminaProtocolWidget* gp, RemminaFile* remminafile) +void remmina_protocol_widget_open_connection(RemminaProtocolWidget* gp) { TRACE_CALL(__func__); gchar *s; const gchar *name; RemminaMessagePanel *mp; - gp->priv->remmina_file = remminafile; - gp->priv->scalemode = remmina_file_get_int(remminafile, "scale", FALSE); - gp->priv->scaler_expand = remmina_file_get_int(remminafile, "scaler_expand", FALSE); + gp->priv->scalemode = remmina_file_get_int(gp->priv->remmina_file, "scale", FALSE); + gp->priv->scaler_expand = remmina_file_get_int(gp->priv->remmina_file, "scaler_expand", FALSE); /* Exec precommand before everything else */ mp = remmina_message_panel_new(); remmina_message_panel_setup_progress(mp, _("Executing external commands..."), NULL, NULL); remmina_connection_object_show_message_panel(gp->cnnobj, mp); - remmina_ext_exec_new(remminafile, "precommand"); + remmina_ext_exec_new(gp->priv->remmina_file, "precommand"); remmina_connection_object_destroy_message_panel(gp->cnnobj, mp); - name = remmina_file_get_string(remminafile, "name"); + name = remmina_file_get_string(gp->priv->remmina_file, "name"); s = g_strdup_printf(_("Connecting to '%s'..."), (name ? name : "*")); mp = remmina_message_panel_new(); @@ -1573,7 +1575,7 @@ void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *k } } -void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp, gint w, gint h) +void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp) { TRACE_CALL(__func__); GdkDisplay *display; @@ -1593,8 +1595,24 @@ void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp, #endif gint x, y; GdkRectangle rect; + gint w, h; + gint wfile, hfile; + RemminaProtocolWidgetResolutionMode res_mode; + + res_mode = remmina_file_get_int(gp->priv->remmina_file, "resolution_mode", RES_INVALID); + wfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_width", -1); + hfile = remmina_file_get_int(gp->priv->remmina_file, "resolution_height", -1); + + /* If resolution_mode is non-existent (-1), then we try to calculate it + * as we did before having resolution_mode */ + if (res_mode == RES_INVALID) { + if (wfile <= 0 || hfile <= 0) + res_mode = RES_USE_INITIAL_WINDOW_SIZE; + else + res_mode = RES_USE_CUSTOM; + } - if (w <= 0 || h <= 0) { + if (res_mode == RES_USE_CLIENT) { display = gdk_display_get_default(); /* gdk_display_get_device_manager deprecated since 3.20, Use gdk_display_get_default_seat */ #if GTK_CHECK_VERSION(3, 20, 0) @@ -1614,6 +1632,25 @@ void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp, #endif w = rect.width; h = rect.height; + } else if (res_mode == RES_USE_INITIAL_WINDOW_SIZE) { + GtkAllocation al; + gtk_widget_get_allocation(gp, &al); + w = al.width; + h = al.height; + if (w < 10) { + printf("REMMINA WARNING: %s RemminaProtocolWidget w=%d h=%d are too small, adjusting to 640x480\n", __func__, w, h); + w = 640; + h = 480; + } + /* Workaround for FreeRDP issue 5119. This will make our horizontal resolution + * an even value, but it will add a vertical black 1 pixel line on the + * right of the desktop */ + if ( w & 1 != 0) + w -= 1; + + } else { + w = wfile; + h = hfile; } gp->priv->profile_remote_width = w; gp->priv->profile_remote_height = h; diff --git a/src/remmina_protocol_widget.h b/src/remmina_protocol_widget.h index 0445d15e7..3251f41ad 100644 --- a/src/remmina_protocol_widget.h +++ b/src/remmina_protocol_widget.h @@ -93,7 +93,7 @@ void remmina_protocol_widget_set_error(RemminaProtocolWidget *gp, const gchar *f gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget *gp); RemminaFile* remmina_protocol_widget_get_file(RemminaProtocolWidget *gp); -void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp, RemminaFile *remminafile); +void remmina_protocol_widget_open_connection(RemminaProtocolWidget *gp); gboolean remmina_protocol_widget_close_connection(RemminaProtocolWidget *gp); void remmina_protocol_widget_grab_focus(RemminaProtocolWidget *gp); const RemminaProtocolFeature* remmina_protocol_widget_get_features(RemminaProtocolWidget *gp); @@ -159,7 +159,7 @@ void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget* gp, GtkMenuI /* Take screenshot of plugin */ gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget* gp, RemminaPluginScreenshotData *rpsd); -void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp, gint w, gint h); +void remmina_protocol_widget_update_remote_resolution(RemminaProtocolWidget* gp); /* Functions to support execution of GTK code on master thread */ RemminaMessagePanel* remmina_protocol_widget_mpprogress(RemminaConnectionObject* cnnobj, const gchar *msg, RemminaMessagePanelCallback response_callback, gpointer response_callback_data); |