diff options
-rw-r--r-- | data/ui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | data/ui/remmina_xinput_env_dialog.glade | 84 | ||||
-rw-r--r-- | src/rcw.c | 25 | ||||
-rw-r--r-- | src/remmina_main.c | 47 | ||||
-rw-r--r-- | src/remmina_pref.c | 6 | ||||
-rw-r--r-- | src/remmina_pref.h | 1 |
6 files changed, 148 insertions, 16 deletions
diff --git a/data/ui/CMakeLists.txt b/data/ui/CMakeLists.txt index 416bb254c..0e599d7a0 100644 --- a/data/ui/CMakeLists.txt +++ b/data/ui/CMakeLists.txt @@ -42,3 +42,4 @@ install(FILES remmina_string_list.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_mpc.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_snap_info_dialog.glade DESTINATION "${REMMINA_UIDIR}") install(FILES remmina_unlock.glade DESTINATION "${REMMINA_UIDIR}") +install(FILES remmina_xinput_env_dialog.glade DESTINATION "${REMMINA_UIDIR}") diff --git a/data/ui/remmina_xinput_env_dialog.glade b/data/ui/remmina_xinput_env_dialog.glade new file mode 100644 index 000000000..0fa74c6a1 --- /dev/null +++ b/data/ui/remmina_xinput_env_dialog.glade @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.6"/> + <object class="GtkDialog" id="xinputwarndlg"> + <property name="can_focus">False</property> + <property name="resizable">False</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="margin_left">5</property> + <property name="margin_right">5</property> + <property name="orientation">vertical</property> + <property name="spacing">15</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="button1"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">9</property> + <property name="label" translatable="yes">Remmina detected that your environment variable GDK_CORE_DEVICE_EVENTS is set. +This could make remmina freeze when grabbing the keyboard, and touch events will not work too. +Please unset GDK_CORE_DEVICE_EVENTS environment variable.</property> + <property name="wrap">True</property> + <property name="ellipsize">start</property> + <property name="max_width_chars">50</property> + <property name="lines">6</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="suppress"> + <property name="label" translatable="yes">Suppress this message for 20 days</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="1">button1</action-widget> + </action-widgets> + </object> +</interface> @@ -142,7 +142,6 @@ struct _RemminaConnectionWindowPriv { gboolean ss_maximized; gboolean kbcaptured; - gboolean dont_ungrab_on_next_focus_out_event; gboolean mouse_pointer_entered; gboolean hostkey_activated; gboolean hostkey_used; @@ -516,15 +515,16 @@ static void rcw_keyboard_grab(RemminaConnectionWindow *cnnwin) * The bugfix will be released with GTK 3.24. * Also pease note that the newer gdk_seat_grab() is still calling gdk_device_grab(). * - * dont_ungrab_on_next_focus_out_event: Xorg when grabbing keyboard - * generates an extra focus-out and focus-in event - * https://stackoverflow.com/questions/15270420/why-xgrabkey-generates-extra-focus-out-and-focus-in-events - * with mode field set to XCB_NOTIFY_MODE_GRAB - * Some windows managers can detect this evend via the mode==XCB_NOTIFY_MODE_GRAB and suppress it. - * Some WM don't. Under GTK we can't check the mode field, so we need a workaround to block - * the spurious focus-out event we receive, setting dont_ungrab_on_next_focus_out_event to true. + * Warning: gdk_seat_grab() will call XGrabKeyboard() or XIGrabDevice() + * which in turn will generate a core X input event FocusOut and FocusIn + * but not Xinput2 events. + * In some cases, GTK is unable to neutralize FocusIn and FocusOut core + * events (ie: i3wm+Plasma with GDK_CORE_DEVICE_EVENTS=1 because detail=NotifyNonlinear + * instead of detail=NotifyAncestor/detail=NotifyInferior) + * Receiving a FocusOut event for Remmina at this time will cause an infinite loop. + * Therefore is important for GTK to use Xinput2 insetead of core X events + * by unsetting GDK_CORE_DEVICE_EVENTS */ - cnnwin->priv->dont_ungrab_on_next_focus_out_event = TRUE; #if GTK_CHECK_VERSION(3, 24, 0) ggs = gdk_seat_grab(seat, gtk_widget_get_window(GTK_WIDGET(cnnwin)), GDK_SEAT_CAPABILITY_KEYBOARD, FALSE, NULL, NULL, NULL, NULL); @@ -2392,7 +2392,6 @@ static void rcw_focus_in(RemminaConnectionWindow *cnnwin) TRACE_CALL(__func__); RemminaConnectionObject *cnnobj; - cnnwin->priv->dont_ungrab_on_next_focus_out_event = FALSE; if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return; if (cnnobj && cnnobj->connected && remmina_file_get_int(cnnobj->remmina_file, "keyboard_grab", FALSE)) @@ -2404,10 +2403,8 @@ static void rcw_focus_out(RemminaConnectionWindow *cnnwin) TRACE_CALL(__func__); RemminaConnectionObject *cnnobj; - if (!cnnwin->priv->dont_ungrab_on_next_focus_out_event) - rcw_keyboard_ungrab(cnnwin); + rcw_keyboard_ungrab(cnnwin); - cnnwin->priv->dont_ungrab_on_next_focus_out_event = FALSE; cnnwin->priv->hostkey_activated = FALSE; if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return; @@ -2455,7 +2452,6 @@ static gboolean rcw_on_enter(GtkWidget *widget, GdkEventCrossing *event, gpointe return FALSE; cnnwin = (RemminaConnectionWindow *)widget; - cnnwin->priv->dont_ungrab_on_next_focus_out_event = FALSE; if (!(cnnobj = rcw_get_visible_cnnobj(cnnwin))) return FALSE; @@ -2487,7 +2483,6 @@ static gboolean rcw_on_leave(GtkWidget *widget, GdkEventCrossing *event, gpointe if (!REMMINA_IS_CONNECTION_WINDOW(widget)) return FALSE; cnnwin = (RemminaConnectionWindow *)widget; - cnnwin->priv->dont_ungrab_on_next_focus_out_event = FALSE; #if DEBUG_KB_GRABBING printf("DEBUG_KB_GRABBING: leave detail="); diff --git a/src/remmina_main.c b/src/remmina_main.c index aa43ea2a9..b3654fea3 100644 --- a/src/remmina_main.c +++ b/src/remmina_main.c @@ -244,6 +244,51 @@ static void remmina_main_clear_selection_data(void) remminamain->priv->selected_name = NULL; } +static void remmina_main_check_env() +{ + GtkBuilder *dlgbuilder = NULL; + GtkWidget *dlg; + GtkWindow *parent; + GtkWidget* dsa; + int result; + gint64 nowsec; + static gboolean shown_once = FALSE; + #define SUPPRESS_DAYS 20 + + if (shown_once) + return; + else + shown_once = TRUE; + + static char envvar[] = "GDK_CORE_DEVICE_EVENTS"; + if (g_getenv(envvar)) { + /* It seens that GTK4 no longer makes use of X core events, so all this stuff could be removed in GTK4 */ + g_print("WARNING: Remmina can freeze during keyboard grab or miss some touch events because %s environment variable is set. Please unset it.\n", envvar); + nowsec = g_get_real_time() / 1000000; + if (nowsec > remmina_pref.suppress_xinput_welcome_message_time_limit && !kioskmode) { + dlgbuilder = remmina_public_gtk_builder_new_from_file("remmina_xinput_env_dialog.glade"); + dsa = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "suppress")); + if (dlgbuilder) { + parent = remmina_main_get_window(); + dlg = GTK_WIDGET(gtk_builder_get_object(dlgbuilder, "xinputwarndlg")); + if (parent) + gtk_window_set_transient_for(GTK_WINDOW(dlg), parent); + gtk_builder_connect_signals(dlgbuilder, NULL); + result = gtk_dialog_run(GTK_DIALOG(dlg)); + if (result == 1) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dsa))) + remmina_pref.suppress_xinput_welcome_message_time_limit = (g_get_real_time() / 1000000) + SUPPRESS_DAYS * 60 * 60 * 24; + else + remmina_pref.suppress_xinput_welcome_message_time_limit = 0; + remmina_pref_save(); + } + gtk_widget_destroy(dlg); + g_object_unref(dlgbuilder); + } + } + } +} + #ifdef SNAP_BUILD static void remmina_main_show_snap_welcome() @@ -1284,7 +1329,7 @@ void remmina_main_on_show(GtkWidget *w, gpointer user_data) #ifdef SNAP_BUILD remmina_main_show_snap_welcome(); #endif - + remmina_main_check_env(); } /* RemminaMain instance */ diff --git a/src/remmina_pref.c b/src/remmina_pref.c index 5d0bea612..ff275993f 100644 --- a/src/remmina_pref.c +++ b/src/remmina_pref.c @@ -314,6 +314,11 @@ void remmina_pref_init(void) else remmina_pref.prevent_snap_welcome_message = FALSE; + if (g_key_file_has_key(gkeyfile, "remmina_pref", "suppress_xinput_welcome_message_time_limit", NULL)) + remmina_pref.suppress_xinput_welcome_message_time_limit = g_key_file_get_uint64(gkeyfile, "remmina_pref", "suppress_xinput_welcome_message_time_limit", NULL); + else + remmina_pref.suppress_xinput_welcome_message_time_limit = FALSE; + if (g_key_file_has_key(gkeyfile, "remmina_pref", "last_quickconnect_protocol", NULL)) remmina_pref.last_quickconnect_protocol = g_key_file_get_string(gkeyfile, "remmina_pref", "last_quickconnect_protocol", NULL); else @@ -739,6 +744,7 @@ gboolean remmina_pref_save(void) g_key_file_set_integer(gkeyfile, "remmina_pref", "floating_toolbar_placement", remmina_pref.floating_toolbar_placement); g_key_file_set_integer(gkeyfile, "remmina_pref", "toolbar_placement", remmina_pref.toolbar_placement); g_key_file_set_boolean(gkeyfile, "remmina_pref", "prevent_snap_welcome_message", remmina_pref.prevent_snap_welcome_message); + g_key_file_set_uint64(gkeyfile, "remmina_pref", "suppress_xinput_welcome_message_time_limit", remmina_pref.suppress_xinput_welcome_message_time_limit); g_key_file_set_string(gkeyfile, "remmina_pref", "last_quickconnect_protocol", remmina_pref.last_quickconnect_protocol); g_key_file_set_boolean(gkeyfile, "remmina_pref", "fullscreen_on_auto", remmina_pref.fullscreen_on_auto); g_key_file_set_boolean(gkeyfile, "remmina_pref", "always_show_tab", remmina_pref.always_show_tab); diff --git a/src/remmina_pref.h b/src/remmina_pref.h index 0b7c93248..4348fefca 100644 --- a/src/remmina_pref.h +++ b/src/remmina_pref.h @@ -186,6 +186,7 @@ typedef struct _RemminaPref { gint floating_toolbar_placement; gint toolbar_placement; gboolean prevent_snap_welcome_message; + guint64 suppress_xinput_welcome_message_time_limit; gchar * last_quickconnect_protocol; /* Crypto */ |