[gnome-software: 44/110] Rework event handling




commit cbbb83ec76e04d7a75aa2b6913855f0b1134b0a8
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Aug 24 09:21:24 2021 -0300

    Rework event handling
    
    On GTK4, GtkWidget doesn't have the *-event signals anymore. Events must
    be routed through controllers and gestures (e.g. GtkEventController and
    GtkGestureClick).
    
    This commit does that.
    
    GsShell needs 2 separate key controllers, one during the capture phase
    and the other during bubble, so that it can mimic its current behavior.
    It would be ideal to switch to actions later, but for now let's be as
    un-disruptive as possible.
    
    Since GtkGestureClick supports setting a button, the 'if (button != 8)'
    check can be dropped. To stop event propagation of click gestures, claim
    the gesture state.

 src/gs-common.c             |  7 ++--
 src/gs-details-page.c       | 14 ++++---
 src/gs-details-page.ui      | 15 +++----
 src/gs-featured-carousel.c  | 20 +++++-----
 src/gs-featured-carousel.ui |  5 +++
 src/gs-shell.c              | 95 ++++++++++++++++++++++-----------------------
 src/gs-shell.ui             | 21 ++++++++--
 src/gs-update-dialog.c      | 47 +++++++++-------------
 src/gs-update-dialog.ui     | 13 +++++++
 9 files changed, 130 insertions(+), 107 deletions(-)
---
diff --git a/src/gs-common.c b/src/gs-common.c
index 4161a05b5..6a0328d2f 100644
--- a/src/gs-common.c
+++ b/src/gs-common.c
@@ -453,12 +453,11 @@ gs_utils_widget_set_css (GtkWidget *widget, GtkCssProvider **provider, const gch
                                        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 }
 
-static gboolean
-unset_focus (GtkWidget *widget, GdkEvent *event, gpointer data)
+static void
+unset_focus (GtkWidget *widget, gpointer data)
 {
        if (GTK_IS_WINDOW (widget))
                gtk_window_set_focus (GTK_WINDOW (widget), NULL);
-       return FALSE;
 }
 
 /**
@@ -527,7 +526,7 @@ insert_details_widget (GtkMessageDialog *dialog, const gchar *details)
        gtk_widget_set_vexpand (sw, TRUE);
        gtk_box_append (GTK_BOX (message_area), sw);
 
-       g_signal_connect (dialog, "map-event", G_CALLBACK (unset_focus), NULL);
+       g_signal_connect (dialog, "map", G_CALLBACK (unset_focus), NULL);
 }
 
 /**
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index 6faa5ac06..513f47086 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -135,7 +135,6 @@ struct _GsDetailsPage
        GtkWidget               *scrolledwindow_details;
        GtkWidget               *spinner_details;
        GtkWidget               *stack_details;
-       GtkWidget               *star_eventbox;
        GtkWidget               *origin_popover;
        GtkWidget               *origin_popover_list_box;
        GtkWidget               *origin_box;
@@ -1392,14 +1391,14 @@ gs_details_page_refresh_reviews (GsDetailsPage *self)
        if (gs_app_get_state (self->app) != GS_APP_STATE_INSTALLED) {
                gtk_widget_set_visible (self->button_review, FALSE);
                gtk_widget_set_sensitive (self->button_review, FALSE);
-               gtk_widget_set_sensitive (self->star_eventbox, FALSE);
+               gtk_widget_set_sensitive (self->star, FALSE);
        } else if (gs_plugin_loader_get_network_available (self->plugin_loader)) {
                gtk_widget_set_sensitive (self->button_review, TRUE);
-               gtk_widget_set_sensitive (self->star_eventbox, TRUE);
+               gtk_widget_set_sensitive (self->star, TRUE);
                gtk_widget_set_tooltip_text (self->button_review, NULL);
        } else {
                gtk_widget_set_sensitive (self->button_review, FALSE);
-               gtk_widget_set_sensitive (self->star_eventbox, FALSE);
+               gtk_widget_set_sensitive (self->star, FALSE);
                gtk_widget_set_tooltip_text (self->button_review,
                                             /* TRANSLATORS: we need a remote server to process */
                                             _("You need internet access to write a review"));
@@ -2049,7 +2048,11 @@ gs_details_page_network_available_notify_cb (GsPluginLoader *plugin_loader,
 }
 
 static void
-gs_details_page_star_pressed_cb(GtkWidget *widget, GdkEventButton *event, GsDetailsPage *self)
+gs_details_page_star_pressed_cb (GtkGestureClick *click,
+                                 gint             n_press,
+                                 gdouble          x,
+                                 gdouble          y,
+                                 GsDetailsPage   *self)
 {
        gs_details_page_write_review_cb(GTK_BUTTON (self->button_review), self);
 }
@@ -2296,7 +2299,6 @@ gs_details_page_class_init (GsDetailsPageClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, scrolledwindow_details);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, spinner_details);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, stack_details);
-       gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, star_eventbox);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, origin_popover);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, origin_popover_list_box);
        gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, origin_box);
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index 1d1814bd5..9840f1f27 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -197,15 +197,16 @@
                                             <property name="visible">True</property>
                                             <property name="valign">start</property>
                                             <child>
-                                              <object class="GtkEventBox" id="star_eventbox">
+                                              <object class="GsStarWidget" id="star">
                                                 <property name="visible">True</property>
-                                                <signal name="button-press-event" 
handler="gs_details_page_star_pressed_cb"/>
+                                                <property name="halign">start</property>
+                                                <property name="valign">center</property>
+                                                <property name="icon-size">16</property>
                                                 <child>
-                                                  <object class="GsStarWidget" id="star">
-                                                    <property name="visible">True</property>
-                                                    <property name="halign">start</property>
-                                                    <property name="valign">center</property>
-                                                    <property name="icon-size">16</property>
+                                                  <object class="GtkGestureClick">
+                                                    <!-- GDK_BUTTON_PRIMARY -->
+                                                    <property name="button">1</property>
+                                                    <signal name="pressed" 
handler="gs_details_page_star_pressed_cb" object="GsDetailsPage" swapped="no" />
                                                   </object>
                                                 </child>
                                               </object>
diff --git a/src/gs-featured-carousel.c b/src/gs-featured-carousel.c
index f51abed0f..55700d232 100644
--- a/src/gs-featured-carousel.c
+++ b/src/gs-featured-carousel.c
@@ -255,23 +255,24 @@ gs_featured_carousel_dispose (GObject *object)
 }
 
 static gboolean
-gs_featured_carousel_key_press_event (GtkWidget   *widget,
-                                      GdkEventKey *event)
+key_pressed_cb (GtkEventControllerKey *controller,
+                guint                  keyval,
+                guint                  keycode,
+                GdkModifierType        state,
+                GsFeaturedCarousel    *self)
 {
-       GsFeaturedCarousel *self = GS_FEATURED_CAROUSEL (widget);
-
        if (gtk_widget_is_visible (GTK_WIDGET (self->previous_button)) &&
            gtk_widget_is_sensitive (GTK_WIDGET (self->previous_button)) &&
-           ((gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_LTR && 
event->keyval == GDK_KEY_Left) ||
-            (gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_RTL && 
event->keyval == GDK_KEY_Right))) {
+           ((gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_LTR && keyval == 
GDK_KEY_Left) ||
+            (gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_RTL && keyval == 
GDK_KEY_Right))) {
                gtk_widget_activate (GTK_WIDGET (self->previous_button));
                return GDK_EVENT_STOP;
        }
 
        if (gtk_widget_is_visible (GTK_WIDGET (self->next_button)) &&
            gtk_widget_is_sensitive (GTK_WIDGET (self->next_button)) &&
-           ((gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_LTR && event->keyval 
== GDK_KEY_Right) ||
-            (gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_RTL && event->keyval 
== GDK_KEY_Left))) {
+           ((gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_LTR && keyval == 
GDK_KEY_Right) ||
+            (gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_RTL && keyval == 
GDK_KEY_Left))) {
                gtk_widget_activate (GTK_WIDGET (self->next_button));
                return GDK_EVENT_STOP;
        }
@@ -309,8 +310,6 @@ gs_featured_carousel_class_init (GsFeaturedCarouselClass *klass)
        object_class->set_property = gs_featured_carousel_set_property;
        object_class->dispose = gs_featured_carousel_dispose;
 
-       widget_class->key_press_event = gs_featured_carousel_key_press_event;
-
        /**
         * GsFeaturedCarousel:apps: (nullable)
         *
@@ -375,6 +374,7 @@ gs_featured_carousel_class_init (GsFeaturedCarouselClass *klass)
        gtk_widget_class_bind_template_callback (widget_class, previous_button_clicked_cb);
        gtk_widget_class_bind_template_callback (widget_class, previous_button_direction_changed_cb);
        gtk_widget_class_bind_template_callback (widget_class, carousel_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, key_pressed_cb);
 }
 
 /**
diff --git a/src/gs-featured-carousel.ui b/src/gs-featured-carousel.ui
index eea2ee94e..8441991f1 100644
--- a/src/gs-featured-carousel.ui
+++ b/src/gs-featured-carousel.ui
@@ -8,6 +8,11 @@
     <property name="spacing">12</property>
     <property name="visible">True</property>
     <property name="can-focus">True</property>
+    <child>
+      <object class="GtkEventControllerKey">
+        <signal name="key-pressed" handler="key_pressed_cb"/>
+      </object>
+    </child>
     <signal name="clicked" handler="carousel_clicked_cb"/>
     <style>
       <class name="featured-carousel"/>
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 6036c2263..077760b7f 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -905,37 +905,37 @@ initial_refresh_done (GsLoadingPage *loading_page, gpointer data)
 }
 
 static gboolean
-window_keypress_handler (GtkWidget *window, GdkEvent *event, GsShell *shell)
+window_keypress_handler (GtkEventControllerKey *key_controller,
+                         guint                  keyval,
+                         guint                  keycode,
+                         GdkModifierType        state,
+                         GsShell               *shell)
 {
        /* handle ctrl+f shortcut */
-       if (event->type == GDK_KEY_PRESS) {
-               GdkEventKey *e = (GdkEventKey *) event;
-               if ((e->state & GDK_CONTROL_MASK) > 0 &&
-                   e->keyval == GDK_KEY_f) {
-                       if (!adw_search_bar_get_search_mode (ADW_SEARCH_BAR (shell->search_bar))) {
-                               GsShellMode mode = gs_shell_get_mode (shell);
-
-                               adw_search_bar_set_search_mode (ADW_SEARCH_BAR (shell->search_bar), TRUE);
-                               gtk_widget_grab_focus (shell->entry_search);
-
-                               /* If the mode doesn't have a search button,
-                                * switch to the search page right away,
-                                * otherwise we would show the search bar
-                                * without a button to toggle it. */
-                               switch (mode) {
-                               case GS_SHELL_MODE_OVERVIEW:
-                               case GS_SHELL_MODE_INSTALLED:
-                               case GS_SHELL_MODE_SEARCH:
-                                       break;
-                               default:
-                                       gs_shell_show_search (shell, "");
-                                       break;
-                               }
-                       } else {
-                               adw_search_bar_set_search_mode (ADW_SEARCH_BAR (shell->search_bar), FALSE);
+       if ((state & GDK_CONTROL_MASK) > 0 && keyval == GDK_KEY_f) {
+               if (!adw_search_bar_get_search_mode (ADW_SEARCH_BAR (shell->search_bar))) {
+                       GsShellMode mode = gs_shell_get_mode (shell);
+
+                       adw_search_bar_set_search_mode (ADW_SEARCH_BAR (shell->search_bar), TRUE);
+                       gtk_widget_grab_focus (shell->entry_search);
+
+                       /* If the mode doesn't have a search button,
+                        * switch to the search page right away,
+                        * otherwise we would show the search bar
+                        * without a button to toggle it. */
+                       switch (mode) {
+                       case GS_SHELL_MODE_OVERVIEW:
+                       case GS_SHELL_MODE_INSTALLED:
+                       case GS_SHELL_MODE_SEARCH:
+                               break;
+                       default:
+                               gs_shell_show_search (shell, "");
+                               break;
                        }
-                       return GDK_EVENT_STOP;
+               } else {
+                       adw_search_bar_set_search_mode (ADW_SEARCH_BAR (shell->search_bar), FALSE);
                }
+               return GDK_EVENT_STOP;
        }
 
        /* pass to search bar */
@@ -971,21 +971,17 @@ search_button_clicked_cb (GtkToggleButton *toggle_button, GsShell *shell)
 }
 
 static gboolean
-window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell)
+window_key_pressed_cb (GtkEventControllerKey *key_controller,
+                       guint                  keyval,
+                       guint                  keycode,
+                       GdkModifierType        state,
+                       GsShell               *shell)
 {
-       GdkKeymap *keymap;
-       GdkModifierType state;
-       gboolean is_rtl;
-
-       state = event->state;
-       keymap = gdk_keymap_get_for_display (gtk_widget_get_display (win));
-       gdk_keymap_add_virtual_modifiers (keymap, &state);
-       state = state & gtk_accelerator_get_default_mod_mask ();
-       is_rtl = gtk_widget_get_direction (shell->button_back) == GTK_TEXT_DIR_RTL;
+       gboolean is_rtl = gtk_widget_get_direction (shell->button_back) == GTK_TEXT_DIR_RTL;
 
-       if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) ||
-           (is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) ||
-           event->keyval == GDK_KEY_Back) {
+       if ((!is_rtl && state == GDK_MOD1_MASK && keyval == GDK_KEY_Left) ||
+           (is_rtl && state == GDK_MOD1_MASK && keyval == GDK_KEY_Right) ||
+           keyval == GDK_KEY_Back) {
                /* GTK will only actually activate the one which is visible */
                gtk_widget_activate (shell->button_back);
                gtk_widget_activate (shell->button_back2);
@@ -995,17 +991,18 @@ window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell)
        return GDK_EVENT_PROPAGATE;
 }
 
-static gboolean
-window_button_press_event (GtkWidget *win, GdkEventButton *event, GsShell *shell)
+static void
+window_button_pressed_cb (GtkGestureClick *click_gesture,
+                          gint             n_press,
+                          gdouble          x,
+                          gdouble          y,
+                          GsShell         *shell)
 {
-       /* Mouse hardware back button is 8 */
-       if (event->button != 8)
-               return GDK_EVENT_PROPAGATE;
-
        /* GTK will only actually activate the one which is visible */
        gtk_widget_activate (shell->button_back);
        gtk_widget_activate (shell->button_back2);
-       return GDK_EVENT_STOP;
+
+       gtk_gesture_set_state (GTK_GESTURE (click_gesture), GTK_EVENT_SEQUENCE_CLAIMED);
 }
 
 static gboolean
@@ -2598,9 +2595,9 @@ gs_shell_class_init (GsShellClass *klass)
        gtk_widget_class_bind_template_callback (widget_class, gs_shell_main_window_mapped_cb);
        gtk_widget_class_bind_template_callback (widget_class, gs_shell_main_window_realized_cb);
        gtk_widget_class_bind_template_callback (widget_class, main_window_closed_cb);
-       gtk_widget_class_bind_template_callback (widget_class, window_key_press_event);
+       gtk_widget_class_bind_template_callback (widget_class, window_key_pressed_cb);
        gtk_widget_class_bind_template_callback (widget_class, window_keypress_handler);
-       gtk_widget_class_bind_template_callback (widget_class, window_button_press_event);
+       gtk_widget_class_bind_template_callback (widget_class, window_button_pressed_cb);
        gtk_widget_class_bind_template_callback (widget_class, gs_shell_details_back_button_cb);
        gtk_widget_class_bind_template_callback (widget_class, gs_shell_back_button_cb);
        gtk_widget_class_bind_template_callback (widget_class, gs_overview_page_button_cb);
diff --git a/src/gs-shell.ui b/src/gs-shell.ui
index 7fc0cd34c..bcf9f191f 100644
--- a/src/gs-shell.ui
+++ b/src/gs-shell.ui
@@ -23,9 +23,24 @@
     <signal name="map" handler="gs_shell_main_window_mapped_cb"/>
     <signal name="realize" handler="gs_shell_main_window_realized_cb"/>
     <signal name="delete-event" handler="main_window_closed_cb"/>
-    <signal name="key-press-event" handler="window_key_press_event" after="yes"/>
-    <signal name="key-press-event" handler="window_keypress_handler"/>
-    <signal name="button-press-event" handler="window_button_press_event" after="yes"/>
+    <child>
+      <object class="GtkEventControllerKey">
+        <property name="propagation-phase">capture</property>
+        <signal name="key-pressed" handler="window_keypress_handler"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkEventControllerKey">
+        <signal name="key-pressed" handler="window_key_pressed_cb"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkGestureClick">
+        <!-- Mouse hardware back button -->
+        <property name="button">8</property>
+        <signal name="pressed" handler="window_button_pressed_cb"/>
+      </object>
+    </child>
     <child>
       <object class="GtkStack" id="stack_loading">
         <property name="visible">True</property>
diff --git a/src/gs-update-dialog.c b/src/gs-update-dialog.c
index 45a2ed3b1..b458e78ff 100644
--- a/src/gs-update-dialog.c
+++ b/src/gs-update-dialog.c
@@ -211,22 +211,17 @@ gs_update_dialog_show_update_details (GsUpdateDialog *dialog, GsApp *app)
 }
 
 static gboolean
-key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+key_pressed_cb (GtkEventControllerKey *key_controller,
+                guint                  keyval,
+                guint                  keycode,
+                GdkModifierType        state,
+                GsUpdateDialog        *dialog)
 {
-       GsUpdateDialog *dialog = (GsUpdateDialog *) widget;
-       GdkKeymap *keymap;
-       GdkModifierType state;
-       gboolean is_rtl;
-
-       state = event->state;
-       keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
-       gdk_keymap_add_virtual_modifiers (keymap, &state);
-       state = state & gtk_accelerator_get_default_mod_mask ();
-       is_rtl = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_RTL;
-
-       if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) ||
-           (is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) ||
-           event->keyval == GDK_KEY_Back) {
+       gboolean is_rtl = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_RTL;
+
+       if ((!is_rtl && state == GDK_MOD1_MASK && keyval == GDK_KEY_Left) ||
+           (is_rtl && state == GDK_MOD1_MASK && keyval == GDK_KEY_Right) ||
+           keyval == GDK_KEY_Back) {
                adw_deck_navigate (ADW_DECK (dialog->deck), ADW_NAVIGATION_DIRECTION_BACK);
                return GDK_EVENT_STOP;
        }
@@ -234,15 +229,15 @@ key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
        return GDK_EVENT_PROPAGATE;
 }
 
-static gboolean
-button_press_event (GsUpdateDialog *dialog, GdkEventButton *event)
+static void
+button_pressed_cb (GtkGestureClick *click_gesture,
+                   gint             n_press,
+                   gdouble          x,
+                   gdouble          y,
+                   GsUpdateDialog  *dialog)
 {
-       /* Mouse hardware back button is 8 */
-       if (event->button != 8)
-               return GDK_EVENT_PROPAGATE;
-
        adw_deck_navigate (ADW_DECK (dialog->deck), ADW_NAVIGATION_DIRECTION_BACK);
-       return GDK_EVENT_STOP;
+       gtk_gesture_set_state (GTK_GESTURE (click_gesture), GTK_EVENT_SEQUENCE_CLAIMED);
 }
 
 static void
@@ -338,12 +333,6 @@ gs_update_dialog_init (GsUpdateDialog *dialog)
                          G_CALLBACK (installed_updates_row_activated_cb), dialog);
 
        g_signal_connect_after (dialog, "show", G_CALLBACK (unset_focus), NULL);
-
-       /* global keynav and mouse back button */
-       g_signal_connect (dialog, "key-press-event",
-                         G_CALLBACK (key_press_event), NULL);
-       g_signal_connect (dialog, "button-press-event",
-                         G_CALLBACK (button_press_event), NULL);
 }
 
 static void
@@ -391,7 +380,9 @@ gs_update_dialog_class_init (GsUpdateDialogClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, list_box_installed_updates);
        gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, spinner);
        gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, stack);
+       gtk_widget_class_bind_template_callback (widget_class, button_pressed_cb);
        gtk_widget_class_bind_template_callback (widget_class, deck_child_transition_cb);
+       gtk_widget_class_bind_template_callback (widget_class, key_pressed_cb);
 
        gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
 }
diff --git a/src/gs-update-dialog.ui b/src/gs-update-dialog.ui
index a5ad8badf..ed85f4f12 100644
--- a/src/gs-update-dialog.ui
+++ b/src/gs-update-dialog.ui
@@ -12,6 +12,19 @@
     <property name="default-width">640</property>
     <property name="default-height">576</property>
 
+    <child>
+      <object class="GtkEventControllerKey">
+        <signal name="key-pressed" handler="key_pressed_cb"/>
+      </object>
+    </child>
+    <child>
+      <object class="GtkGestureClick">
+        <!-- Mouse hardware back button -->
+        <property name="button">8</property>
+        <signal name="pressed" handler="button_pressed_cb"/>
+      </object>
+    </child>
+
     <child>
       <object class="AdwDeck" id="deck">
         <property name="visible">True</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]