[gnome-builder/wip/gtk4-port] libide/sourceview: add populate-menu signal to view



commit 934c0c56ce9ea9d631866c45e193815287b090fe
Author: Christian Hergert <chergert redhat com>
Date:   Fri Apr 8 12:34:06 2022 -0700

    libide/sourceview: add populate-menu signal to view
    
    This allows us to not need click controllers in various page addins just
    to update menus/etc. There is still some popover issue I haven't deduced
    yet, which doesn't happen in gnome-text-editor.

 src/libide/sourceview/ide-source-view.c            |  89 +++++++++++++++++-
 .../spellcheck/gbp-spell-editor-page-addin.c       | 100 ++++++++-------------
 2 files changed, 125 insertions(+), 64 deletions(-)
---
diff --git a/src/libide/sourceview/ide-source-view.c b/src/libide/sourceview/ide-source-view.c
index 6ed34a636..6c132d3ae 100644
--- a/src/libide/sourceview/ide-source-view.c
+++ b/src/libide/sourceview/ide-source-view.c
@@ -39,6 +39,8 @@ struct _IdeSourceView
   IdeJoinedMenu *joined_menu;
 };
 
+G_DEFINE_TYPE (IdeSourceView, ide_source_view, GTK_SOURCE_TYPE_VIEW)
+
 enum {
   PROP_0,
   PROP_FONT_DESC,
@@ -48,9 +50,13 @@ enum {
   N_PROPS
 };
 
-G_DEFINE_TYPE (IdeSourceView, ide_source_view, GTK_SOURCE_TYPE_VIEW)
+enum {
+  POPULATE_MENU,
+  N_SIGNALS
+};
 
-static GParamSpec *properties [N_PROPS];
+static GParamSpec *properties[N_PROPS];
+static guint signals[N_SIGNALS];
 
 static void
 ide_source_view_update_css (IdeSourceView *self)
@@ -164,6 +170,49 @@ tweak_gutter_spacing (GtkSourceView *view)
     }
 }
 
+static void
+ide_source_view_click_pressed_cb (IdeSourceView   *self,
+                                  int              n_press,
+                                  double           x,
+                                  double           y,
+                                  GtkGestureClick *click)
+{
+  GdkEventSequence *sequence;
+  g_auto(GStrv) corrections = NULL;
+  GtkTextBuffer *buffer;
+  GdkEvent *event;
+  GtkTextIter iter;
+  int buf_x, buf_y;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (GTK_IS_GESTURE_CLICK (click));
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (click));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (click), sequence);
+
+  if (n_press != 1 || !gdk_event_triggers_context_menu (event))
+    IDE_EXIT;
+
+  /* Move the cursor position to where the click occurred so that
+   * the context menu will be useful for the click location.
+   */
+  if (!gtk_text_buffer_get_has_selection (buffer))
+    {
+      gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (self),
+                                             GTK_TEXT_WINDOW_WIDGET,
+                                             x, y, &buf_x, &buf_y);
+      gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (self), &iter, buf_x, buf_y);
+      gtk_text_buffer_select_range (buffer, &iter, &iter);
+    }
+
+  g_signal_emit (self, signals[POPULATE_MENU], 0);
+
+  IDE_EXIT;
+}
+
 static void
 ide_source_view_dispose (GObject *object)
 {
@@ -281,23 +330,59 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  /**
+   * IdeSourceView::populate-menu:
+   * @self: an #IdeSourceView
+   *
+   * The "populate-menu" signal is emitted before the context meu is shown
+   * to the user. Handlers of this signal should update any menu items they
+   * have which have been connected using ide_source_view_append_menu() or
+   * simmilar.
+   */
+  signals[POPULATE_MENU] =
+    g_signal_new_class_handler ("populate-menu",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_LAST,
+                                NULL,
+                                NULL, NULL,
+                                NULL,
+                                G_TYPE_NONE, 0);
+
 }
 
 static void
 ide_source_view_init (IdeSourceView *self)
 {
   GtkStyleContext *style_context;
+  GtkEventController *click;
 
+  /* Setup our extra menu so that consumers can use
+   * ide_source_view_append_men() or similar to update menus.
+   */
   self->joined_menu = ide_joined_menu_new ();
   gtk_text_view_set_extra_menu (GTK_TEXT_VIEW (self),
                                 G_MENU_MODEL (self->joined_menu));
 
+  /* Setup a handler to emit ::populate-menu */
+  click = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (click), 0);
+  g_signal_connect_swapped (click,
+                            "pressed",
+                            G_CALLBACK (ide_source_view_click_pressed_cb),
+                            self);
+  gtk_widget_add_controller (GTK_WIDGET (self), click);
+
+  /* This is sort of a layer vioaltion, but it's helpful for us to
+   * get the system font name and manage it invisibly.
+   */
   g_signal_connect_object (g_application_get_default (),
                            "notify::system-font-name",
                            G_CALLBACK (ide_source_view_update_css),
                            self,
                            G_CONNECT_SWAPPED);
 
+  /* Setup the CSS provider for the custom font/scale/etc. */
   self->css_provider = gtk_css_provider_new ();
   style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
   gtk_style_context_add_provider (style_context,
diff --git a/src/plugins/spellcheck/gbp-spell-editor-page-addin.c 
b/src/plugins/spellcheck/gbp-spell-editor-page-addin.c
index 7ce5c7174..94137edad 100644
--- a/src/plugins/spellcheck/gbp-spell-editor-page-addin.c
+++ b/src/plugins/spellcheck/gbp-spell-editor-page-addin.c
@@ -34,7 +34,6 @@ struct _GbpSpellEditorPageAddin
   GObject              parent_instance;
   IdeEditorPage       *page;
   GbpSpellBufferAddin *buffer_addin;
-  GtkGestureClick     *click;
   GMenuModel          *menu;
   GSimpleActionGroup  *actions;
   char                *spelling_word;
@@ -137,66 +136,45 @@ set_action_enabled (GSimpleActionGroup *group,
 }
 
 static void
-on_click_pressed_cb (GtkGestureClick         *click,
-                     int                      n_press,
-                     double                   x,
-                     double                   y,
-                     GbpSpellEditorPageAddin *self)
+gbp_spell_editor_page_addin_populate_menu_cb (GbpSpellEditorPageAddin *self,
+                                              IdeSourceView           *view)
 {
-  GdkEventSequence *sequence;
   g_auto(GStrv) corrections = NULL;
   g_autofree char *word = NULL;
-  IdeSourceView *view;
   GtkTextBuffer *buffer;
-  GdkEvent *event;
-  GtkTextIter iter, begin, end;
-  int buf_x, buf_y;
-
-  g_assert (GBP_IS_SPELL_EDITOR_PAGE_ADDIN (self));
-  g_assert (GTK_IS_GESTURE_CLICK (click));
-  g_assert (IDE_IS_EDITOR_PAGE (self->page));
+  GtkTextIter begin, end;
 
-  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (click));
-  event = gtk_gesture_get_last_event (GTK_GESTURE (click), sequence);
+  IDE_ENTRY;
 
-  if (n_press != 1 || !gdk_event_triggers_context_menu (event))
-    goto cleanup;
+  g_assert (GBP_IS_SPELL_EDITOR_PAGE_ADDIN (self));
+  g_assert (IDE_IS_SOURCE_VIEW (view));
 
-  /* Move the cursor position to where the click occurred so that
-   * the context menu will be useful for the click location.
-   */
-  view = ide_editor_page_get_view (self->page);
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-  if (gtk_text_buffer_get_selection_bounds (buffer, &begin, &end))
-    goto cleanup;
+  gtk_text_buffer_get_selection_bounds (buffer, &begin, &end);
 
-  gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
-                                         GTK_TEXT_WINDOW_WIDGET,
-                                         x, y, &buf_x, &buf_y);
-  gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, buf_x, buf_y);
-  gtk_text_buffer_select_range (buffer, &iter, &iter);
-
-  /* Get the word under the cursor */
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
-  begin = iter;
-  if (!gtk_text_iter_starts_word (&begin))
-    gtk_text_iter_backward_word_start (&begin);
-  end = begin;
-  if (!gtk_text_iter_ends_word (&end))
-    gtk_text_iter_forward_word_end (&end);
-  if (!gtk_text_iter_equal (&begin, &end) &&
-      gtk_text_iter_compare (&begin, &iter) <= 0 &&
-      gtk_text_iter_compare (&iter, &end) <= 0)
+  if (gtk_text_iter_equal (&begin, &end))
     {
-      word = gtk_text_iter_get_slice (&begin, &end);
-
-      if (!gbp_spell_buffer_addin_check_spelling (self->buffer_addin, word))
-        corrections = gbp_spell_buffer_addin_list_corrections (self->buffer_addin, word);
-      else
-        g_clear_pointer (&word, g_free);
+      GtkTextIter iter = begin;
+
+      /* Get the word under the cursor */
+      if (!gtk_text_iter_starts_word (&begin))
+        gtk_text_iter_backward_word_start (&begin);
+      end = begin;
+      if (!gtk_text_iter_ends_word (&end))
+        gtk_text_iter_forward_word_end (&end);
+      if (!gtk_text_iter_equal (&begin, &end) &&
+          gtk_text_iter_compare (&begin, &iter) <= 0 &&
+          gtk_text_iter_compare (&iter, &end) <= 0)
+        {
+          word = gtk_text_iter_get_slice (&begin, &end);
+
+          if (!gbp_spell_buffer_addin_check_spelling (self->buffer_addin, word))
+            corrections = gbp_spell_buffer_addin_list_corrections (self->buffer_addin, word);
+          else
+            g_clear_pointer (&word, g_free);
+        }
     }
 
-cleanup:
   g_free (self->spelling_word);
   self->spelling_word = g_steal_pointer (&word);
 
@@ -205,6 +183,8 @@ cleanup:
   editor_spell_menu_set_corrections (self->menu,
                                      self->spelling_word,
                                      (const char * const *)corrections);
+
+  IDE_EXIT;
 }
 
 static void
@@ -228,16 +208,6 @@ gbp_spell_editor_page_addin_load (IdeEditorPageAddin *addin,
   self->page = page;
   self->buffer_addin = GBP_SPELL_BUFFER_ADDIN (buffer_addin);
 
-  self->click = GTK_GESTURE_CLICK (gtk_gesture_click_new ());
-  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->click), 0);
-  g_signal_connect_object (self->click,
-                           "pressed",
-                           G_CALLBACK (on_click_pressed_cb),
-                           self,
-                           0);
-  gtk_widget_add_controller (GTK_WIDGET (view),
-                             GTK_EVENT_CONTROLLER (self->click));
-
   self->menu = editor_spell_menu_new ();
   ide_source_view_append_menu (view, self->menu);
 
@@ -252,6 +222,12 @@ gbp_spell_editor_page_addin_load (IdeEditorPageAddin *addin,
                                   "spelling",
                                   G_ACTION_GROUP (self->actions));
 
+  g_signal_connect_object (view,
+                           "populate-menu",
+                           G_CALLBACK (gbp_spell_editor_page_addin_populate_menu_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   IDE_EXIT;
 }
 
@@ -272,9 +248,9 @@ gbp_spell_editor_page_addin_unload (IdeEditorPageAddin *addin,
   view = ide_editor_page_get_view (page);
   ide_source_view_remove_menu (view, self->menu);
 
-  gtk_widget_remove_controller (GTK_WIDGET (view),
-                                GTK_EVENT_CONTROLLER (self->click));
-  self->click = NULL;
+  g_signal_handlers_disconnect_by_func (view,
+                                        G_CALLBACK (gbp_spell_editor_page_addin_populate_menu_cb),
+                                        self);
 
   g_clear_object (&self->menu);
   g_clear_object (&self->actions);


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