From c58d9446f40b36136f25baf66dfb6116fb16888c Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 21 May 2020 18:05:43 -0400 Subject: [PATCH 1/6] Differentiate keypad keysyms in accelerators When displaying accelerators, differentiate keypad symbols with a 'KP' prefix. Fixing a 17 year old bug. Update expected output in accelerator tests. Fixes: #227 --- gtk/gtkaccelgroup.c | 85 +++++++++++++++++++++++-------------------- testsuite/gtk/accel.c | 4 +- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c index b749581629..cb7b2660b7 100644 --- a/gtk/gtkaccelgroup.c +++ b/gtk/gtkaccelgroup.c @@ -220,14 +220,14 @@ static inline gboolean is_primary (const gchar *string) { return ((string[0] == '<') && - (string[1] == 'p' || string[1] == 'P') && - (string[2] == 'r' || string[2] == 'R') && - (string[3] == 'i' || string[3] == 'I') && - (string[4] == 'm' || string[4] == 'M') && - (string[5] == 'a' || string[5] == 'A') && - (string[6] == 'r' || string[6] == 'R') && - (string[7] == 'y' || string[7] == 'Y') && - (string[8] == '>')); + (string[1] == 'p' || string[1] == 'P') && + (string[2] == 'r' || string[2] == 'R') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'm' || string[4] == 'M') && + (string[5] == 'a' || string[5] == 'A') && + (string[6] == 'r' || string[6] == 'R') && + (string[7] == 'y' || string[7] == 'Y') && + (string[8] == '>')); } static inline gboolean @@ -411,15 +411,15 @@ gtk_accelerator_parse_with_keycode (const gchar *accelerator, goto out; } } - else - { - keyval = gdk_keyval_from_name (accelerator); - if (keyval == GDK_KEY_VoidSymbol) - { - error = TRUE; - goto out; - } - } + else + { + keyval = gdk_keyval_from_name (accelerator); + if (keyval == GDK_KEY_VoidSymbol) + { + error = TRUE; + goto out; + } + } if (keyval && accelerator_codes != NULL) { @@ -937,18 +937,25 @@ gtk_accelerator_print_label (GString *gstring, if (seen_mod) append_separator (gstring); + if (accelerator_key >= GDK_KEY_KP_Space && + accelerator_key <= GDK_KEY_KP_Equal) + { + g_string_append (gstring, C_("keyboard label", "KP")); + g_string_append (gstring, " "); + } + switch (ch) - { - case ' ': - g_string_append (gstring, C_("keyboard label", "Space")); - break; - case '\\': - g_string_append (gstring, C_("keyboard label", "Backslash")); - break; - default: - g_string_append_unichar (gstring, g_unichar_toupper (ch)); - break; - } + { + case ' ': + g_string_append (gstring, C_("keyboard label", "Space")); + break; + case '\\': + g_string_append (gstring, C_("keyboard label", "Backslash")); + break; + default: + g_string_append_unichar (gstring, g_unichar_toupper (ch)); + break; + } } else if (!append_keyval_symbol (accelerator_key, gstring)) { @@ -956,22 +963,22 @@ gtk_accelerator_print_label (GString *gstring, tmp = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key)); if (tmp != NULL) - { + { if (seen_mod) append_separator (gstring); - if (tmp[0] != 0 && tmp[1] == 0) - g_string_append_c (gstring, g_ascii_toupper (tmp[0])); - else - { - const char *str; + if (tmp[0] != 0 && tmp[1] == 0) + g_string_append_c (gstring, g_ascii_toupper (tmp[0])); + else + { + const char *str; str = g_dpgettext2 (GETTEXT_PACKAGE, "keyboard label", tmp); - if (str == tmp) + if (str == tmp) append_without_underscores (gstring, tmp); - else - g_string_append (gstring, str); - } - } + else + g_string_append (gstring, str); + } + } } } diff --git a/testsuite/gtk/accel.c b/testsuite/gtk/accel.c index 4c06b28ca0..559635160e 100644 --- a/testsuite/gtk/accel.c +++ b/testsuite/gtk/accel.c @@ -87,13 +87,13 @@ accel2 (void) static void accel3 (void) { - test_one_accel ("KP_7", 0, GDK_KEY_KP_7, "7", TRUE); + test_one_accel ("KP_7", 0, GDK_KEY_KP_7, "KP 7", TRUE); } static void accel4 (void) { - test_one_accel ("KP_7", GDK_CONTROL_MASK, GDK_KEY_KP_7, "Ctrl+7", TRUE); + test_one_accel ("KP_7", GDK_CONTROL_MASK, GDK_KEY_KP_7, "Ctrl+KP 7", TRUE); } static void From 061f257e839aace0dd70164cf03efa21eea48cc1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 21 May 2020 18:15:14 -0400 Subject: [PATCH 2/6] accelgroup: Use Unicode in string literals Its 2020, non-ASCII characters are not taboo anymore. --- gtk/gtkaccelgroup.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c index cb7b2660b7..77e9bf963e 100644 --- a/gtk/gtkaccelgroup.c +++ b/gtk/gtkaccelgroup.c @@ -841,7 +841,7 @@ gtk_accelerator_print_label (GString *gstring, g_string_append (gstring, C_("keyboard label", "Shift")); #else /* U+21E7 UPWARDS WHITE ARROW */ - g_string_append (gstring, "\xe2\x87\xa7"); + g_string_append (gstring, "⇧"); #endif seen_mod = TRUE; } @@ -860,7 +860,7 @@ gtk_accelerator_print_label (GString *gstring, g_string_append (gstring, C_("keyboard label", "Ctrl")); #else /* U+2303 UP ARROWHEAD */ - g_string_append (gstring, "\xe2\x8c\x83"); + g_string_append (gstring, "⌃"); #endif seen_mod = TRUE; } @@ -879,7 +879,7 @@ gtk_accelerator_print_label (GString *gstring, g_string_append (gstring, C_("keyboard label", "Alt")); #else /* U+2325 OPTION KEY */ - g_string_append (gstring, "\xe2\x8c\xa5"); + g_string_append (gstring, "⌥"); #endif seen_mod = TRUE; } @@ -925,8 +925,7 @@ gtk_accelerator_print_label (GString *gstring, */ g_string_append (gstring, C_("keyboard label", "Meta")); #else - /* Command key symbol U+2318 PLACE OF INTEREST SIGN */ - g_string_append (gstring, "\xe2\x8c\x98"); + g_string_append (gstring, "⌘"); #endif seen_mod = TRUE; } From af162b70c5a2dee25ae437c907d57746a7a6eb36 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 21 May 2020 18:59:58 -0400 Subject: [PATCH 3/6] tooltip: Avoid criticals It is possible that the target widget is already unparented at the time that we call the tooltips handle_event function. Quietly return in that case, no need to emit a critical. --- gtk/gtktooltip.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 36b162885b..4d10edf3e1 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -919,18 +919,21 @@ _gtk_tooltip_handle_event (GtkWidget *target, GdkSurface *surface; double x, y; double nx, ny; - GtkWidget *native; + GtkNative *native; if (!tooltips_enabled (event)) return; + native = gtk_widget_get_native (target); + if (!native) + return; + event_type = gdk_event_get_event_type (event); surface = gdk_event_get_surface (event); gdk_event_get_position (event, &x, &y); - native = GTK_WIDGET (gtk_widget_get_native (target)); - gtk_native_get_surface_transform (GTK_NATIVE (native), &nx, &ny); - gtk_widget_translate_coordinates (native, target, x - nx, y - ny, &x, &y); + gtk_native_get_surface_transform (native, &nx, &ny); + gtk_widget_translate_coordinates (GTK_WIDGET (native), target, x - nx, y - ny, &x, &y); gtk_tooltip_handle_event_internal (event_type, surface, target, x, y); } From 3b8bd265a3a65141a78f0120bd81708ed0c1300f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 21 May 2020 19:04:27 -0400 Subject: [PATCH 4/6] windowhandle: Drop Move and Resize from the fallback menu The expected behavior is that we trigger a keyboard-driven interactive move or resize operation. But that doesn't work with common compositors like mutter or weston, so lets not expose non-working menuitems. --- gtk/gtkwindowhandle.c | 45 ------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/gtk/gtkwindowhandle.c b/gtk/gtkwindowhandle.c index efe26714d6..0a21694e73 100644 --- a/gtk/gtkwindowhandle.c +++ b/gtk/gtkwindowhandle.c @@ -106,37 +106,6 @@ restore_window_clicked (GtkModelButton *button, gtk_window_unmaximize (window); } -static void -move_window_clicked (GtkModelButton *button, - GtkWindowHandle *self) -{ - GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self)); - GdkSurface *surface = gtk_native_get_surface (native); - - if (GDK_IS_TOPLEVEL (surface)) - gdk_toplevel_begin_move (GDK_TOPLEVEL (surface), - NULL, - 0, /* 0 means "use keyboard" */ - 0, 0, - GDK_CURRENT_TIME); -} - -static void -resize_window_clicked (GtkModelButton *button, - GtkWindowHandle *self) -{ - GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self)); - GdkSurface *surface = gtk_native_get_surface (native); - - if (GDK_IS_TOPLEVEL (surface)) - gdk_toplevel_begin_resize (GDK_TOPLEVEL (surface), - 0, - NULL, - 0, /* 0 means "use keyboard" */ - 0, 0, - GDK_CURRENT_TIME); -} - static void minimize_window_clicked (GtkModelButton *button, GtkWindowHandle *self) @@ -251,20 +220,6 @@ do_popup_fallback (GtkWindowHandle *self, G_CALLBACK (restore_window_clicked), self); gtk_box_append (GTK_BOX (box), menuitem); - menuitem = gtk_model_button_new (); - g_object_set (menuitem, "text", _("Move"), NULL); - gtk_widget_set_sensitive (menuitem, !maximized); - g_signal_connect (G_OBJECT (menuitem), "clicked", - G_CALLBACK (move_window_clicked), self); - gtk_box_append (GTK_BOX (box), menuitem); - - menuitem = gtk_model_button_new (); - g_object_set (menuitem, "text", _("Resize"), NULL); - gtk_widget_set_sensitive (menuitem, resizable && !maximized); - g_signal_connect (G_OBJECT (menuitem), "clicked", - G_CALLBACK (resize_window_clicked), self); - gtk_box_append (GTK_BOX (box), menuitem); - menuitem = gtk_model_button_new (); g_object_set (menuitem, "text", _("Minimize"), NULL); g_signal_connect (G_OBJECT (menuitem), "clicked", From e9872d52d8bbaa074e89e0b8795452fe7a843b3f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 21 May 2020 20:37:54 -0400 Subject: [PATCH 5/6] range: Treat lower and upper limit the same When clamping values to be within the range of the adjustment, treat the lower and upper limit the same. Fixes: #328 --- gtk/gtkrange.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index 6e96362914..bc765d1f67 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -1746,9 +1746,9 @@ coord_to_value (GtkRange *range, else { if (priv->slider_size_fixed) - frac = MAX (0, coord) / (double) (trough_length); + frac = CLAMP (coord / (double) trough_length, 0, 1); else - frac = MAX (0, coord) / (double) (trough_length - slider_length); + frac = CLAMP (coord / (double) (trough_length - slider_length), 0, 1); } if (should_invert (range)) From e8a120e5afd4542584ecbbe23f76300d2c858d9e Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Thu, 21 May 2020 21:14:47 -0400 Subject: [PATCH 6/6] trash-monitor: Rate limit updates Trash monitor queries info from gvfsd-trash after each file monitor change which can be problematic when too many changes happen in a short time. Let's rate limit the number of queries... Fixes: #1010 --- gtk/gtktrashmonitor.c | 69 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/gtk/gtktrashmonitor.c b/gtk/gtktrashmonitor.c index d52006432e..fe9d3fcb98 100644 --- a/gtk/gtktrashmonitor.c +++ b/gtk/gtktrashmonitor.c @@ -24,13 +24,18 @@ #include "gtkmarshalers.h" #include "gtktrashmonitor.h" +#define UPDATE_RATE_SECONDS 1 + struct _GtkTrashMonitor { GObject parent; GFileMonitor *file_monitor; gulong file_monitor_changed_id; - + + gboolean pending; + gint timeout_id; + guint has_trash : 1; }; @@ -70,6 +75,10 @@ gtk_trash_monitor_dispose (GObject *object) g_clear_object (&monitor->file_monitor); } + if (monitor->timeout_id > 0) + g_source_remove (monitor->timeout_id); + monitor->timeout_id = 0; + G_OBJECT_CLASS (_gtk_trash_monitor_parent_class)->dispose (object); } @@ -84,18 +93,18 @@ _gtk_trash_monitor_class_init (GtkTrashMonitorClass *class) signals[TRASH_STATE_CHANGED] = g_signal_new (I_("trash-state-changed"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkTrashMonitorClass, trash_state_changed), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkTrashMonitorClass, trash_state_changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); } /* Updates the internal has_trash flag and emits the "trash-state-changed" signal */ static void update_has_trash_and_notify (GtkTrashMonitor *monitor, - gboolean has_trash) + gboolean has_trash) { if (monitor->has_trash == !!has_trash) return; @@ -136,12 +145,38 @@ trash_query_info_cb (GObject *source, g_object_unref (monitor); /* was reffed in recompute_trash_state() */ } +static void recompute_trash_state (GtkTrashMonitor *monitor); + +static gboolean +recompute_trash_state_cb (gpointer data) +{ + GtkTrashMonitor *monitor = data; + + monitor->timeout_id = 0; + if (monitor->pending) + { + monitor->pending = FALSE; + recompute_trash_state (monitor); + } + + return G_SOURCE_REMOVE; +} + /* Asynchronously recomputes whether there is trash or not */ static void recompute_trash_state (GtkTrashMonitor *monitor) { GFile *file; + /* Rate limit the updates to not flood the gvfsd-trash when too many changes + * happended in a short time. + */ + if (monitor->timeout_id > 0) + { + monitor->pending = TRUE; + return; + } + file = g_file_new_for_uri ("trash:///"); g_file_query_info_async (file, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT, @@ -149,6 +184,10 @@ recompute_trash_state (GtkTrashMonitor *monitor) G_PRIORITY_DEFAULT, NULL, trash_query_info_cb, g_object_ref (monitor)); + monitor->timeout_id = g_timeout_add_seconds (UPDATE_RATE_SECONDS, + recompute_trash_state_cb, + monitor); + g_object_unref (file); } @@ -156,11 +195,11 @@ recompute_trash_state (GtkTrashMonitor *monitor) * whenever something happens. */ static void -file_monitor_changed_cb (GFileMonitor *file_monitor, - GFile *child, - GFile *other_file, - GFileMonitorEvent event_type, - GtkTrashMonitor *monitor) +file_monitor_changed_cb (GFileMonitor *file_monitor, + GFile *child, + GFile *other_file, + GFileMonitorEvent event_type, + GtkTrashMonitor *monitor) { recompute_trash_state (monitor); } @@ -173,12 +212,14 @@ _gtk_trash_monitor_init (GtkTrashMonitor *monitor) file = g_file_new_for_uri ("trash:///"); monitor->file_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + monitor->pending = FALSE; + monitor->timeout_id = 0; g_object_unref (file); if (monitor->file_monitor) monitor->file_monitor_changed_id = g_signal_connect (monitor->file_monitor, "changed", - G_CALLBACK (file_monitor_changed_cb), monitor); + G_CALLBACK (file_monitor_changed_cb), monitor); recompute_trash_state (monitor); }