[gnome-builder/wip/gtk4-port: 814/1774] libide/sourceview: take over context menu control for text view




commit c51ba048b378f8aadedadd9e0f78e9d04fae5e06
Author: Christian Hergert <chergert redhat com>
Date:   Fri Apr 29 14:15:33 2022 -0700

    libide/sourceview: take over context menu control for text view
    
    Rather than rely on GtkTextView to display menu items we can't control
    positioning of, just take over control of the menu display and placement
    with all of the items merge-able by plugins.
    
    We still need some work to update actions but that can happen in followup
    commits. We also need to add soem missing items like emoji. It may also
    make sense to add some "junction" widgets for copy/paste/etc as those take
    a lot of vertical space with very rare usage.

 src/libide/sourceview/{archive => gtk}/menus.ui    |  2 -
 src/libide/sourceview/ide-source-view-private.h    |  1 +
 src/libide/sourceview/ide-source-view.c            | 82 +++++++++++++++++++++-
 .../sourceview/libide-sourceview.gresource.xml     |  1 +
 4 files changed, 83 insertions(+), 3 deletions(-)
---
diff --git a/src/libide/sourceview/archive/menus.ui b/src/libide/sourceview/gtk/menus.ui
similarity index 98%
rename from src/libide/sourceview/archive/menus.ui
rename to src/libide/sourceview/gtk/menus.ui
index cccd3fc68..ace729427 100644
--- a/src/libide/sourceview/archive/menus.ui
+++ b/src/libide/sourceview/gtk/menus.ui
@@ -51,8 +51,6 @@
         <attribute name="accel">Delete</attribute>
       </item>
     </section>
-    <section id="ide-source-view-popup-menu-spellcheck-section">
-    </section>
     <section id="ide-source-view-popup-menu-highlighting-section">
       <submenu id="ide-source-view-popup-menu-highlighting-submenu">
         <attribute name="label" translatable="yes">_Highlighting</attribute>
diff --git a/src/libide/sourceview/ide-source-view-private.h b/src/libide/sourceview/ide-source-view-private.h
index 19c847351..f88ea6974 100644
--- a/src/libide/sourceview/ide-source-view-private.h
+++ b/src/libide/sourceview/ide-source-view-private.h
@@ -53,6 +53,7 @@ struct _IdeSourceView
    * addins to extend it.
    */
   IdeJoinedMenu *joined_menu;
+  GtkPopover *popup_menu;
 
   /* Various addins for different ways of extending the
    * GtkSourceView. These are managed in ide-source-view-addins.c
diff --git a/src/libide/sourceview/ide-source-view.c b/src/libide/sourceview/ide-source-view.c
index 1a31a5357..4b4c06851 100644
--- a/src/libide/sourceview/ide-source-view.c
+++ b/src/libide/sourceview/ide-source-view.c
@@ -374,6 +374,82 @@ ide_source_view_root (GtkWidget *widget)
   IDE_EXIT;
 }
 
+static void
+ide_source_view_menu_popup_action (GtkWidget  *widget,
+                                   const char *action_name,
+                                   GVariant   *param)
+{
+  IdeSourceView *self = (IdeSourceView *)widget;
+  GtkTextView *text_view = (GtkTextView *)widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter iter;
+  GdkRectangle iter_location;
+  GdkRectangle visible_rect;
+  gboolean is_visible;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (ide_str_equal0 (action_name, "menu.popup"));
+  g_assert (param == NULL);
+
+  if (self->popup_menu == NULL)
+    {
+      GMenuModel *model;
+
+      model = G_MENU_MODEL (self->joined_menu);
+      self->popup_menu = GTK_POPOVER (gtk_popover_menu_new_from_model (model));
+      gtk_widget_set_parent (GTK_WIDGET (self->popup_menu), widget);
+      gtk_popover_set_position (self->popup_menu, GTK_POS_BOTTOM);
+      gtk_popover_set_has_arrow (self->popup_menu, FALSE);
+      gtk_widget_set_halign (GTK_WIDGET (self->popup_menu), GTK_ALIGN_START);
+    }
+
+  buffer = gtk_text_view_get_buffer (text_view);
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter,
+                                    gtk_text_buffer_get_insert (buffer));
+  gtk_text_view_get_iter_location (text_view, &iter, &iter_location);
+  gtk_text_view_get_visible_rect (text_view, &visible_rect);
+
+  is_visible = (iter_location.x + iter_location.width > visible_rect.x &&
+                iter_location.x < visible_rect.x + visible_rect.width &&
+                iter_location.y + iter_location.height > visible_rect.y &&
+                iter_location.y < visible_rect.y + visible_rect.height);
+
+  if (is_visible)
+    {
+      gtk_text_view_buffer_to_window_coords (text_view,
+                                             GTK_TEXT_WINDOW_WIDGET,
+                                             iter_location.x,
+                                             iter_location.y,
+                                             &iter_location.x,
+                                             &iter_location.y);
+
+      gtk_popover_set_pointing_to (self->popup_menu, &iter_location);
+    }
+
+  gtk_popover_popup (self->popup_menu);
+
+  IDE_EXIT;
+}
+
+static void
+ide_source_view_size_allocate (GtkWidget *widget,
+                               int        width,
+                               int        height,
+                               int        baseline)
+{
+  IdeSourceView *self = (IdeSourceView *)widget;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (GTK_IS_WIDGET (widget));
+
+  GTK_WIDGET_CLASS (ide_source_view_parent_class)->size_allocate (widget, width, height, baseline);
+
+  if (self->popup_menu != NULL)
+    gtk_popover_present (self->popup_menu);
+}
+
 static void
 ide_source_view_dispose (GObject *object)
 {
@@ -386,6 +462,7 @@ ide_source_view_dispose (GObject *object)
   g_clear_object (&self->joined_menu);
   g_clear_object (&self->css_provider);
   g_clear_pointer (&self->font_desc, pango_font_description_free);
+  g_clear_pointer ((GtkWidget **)&self->popup_menu, gtk_widget_unparent);
 
   g_assert (self->completion_providers == NULL);
 
@@ -476,6 +553,7 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   object_class->set_property = ide_source_view_set_property;
 
   widget_class->root = ide_source_view_root;
+  widget_class->size_allocate = ide_source_view_size_allocate;
 
   properties [PROP_LINE_HEIGHT] =
     g_param_spec_double ("line-height",
@@ -507,6 +585,8 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
+  gtk_widget_class_install_action (widget_class, "menu.popup", NULL, ide_source_view_menu_popup_action);
+
   /**
    * IdeSourceView::populate-menu:
    * @self: an #IdeSourceView
@@ -539,7 +619,7 @@ ide_source_view_init (IdeSourceView *self)
                     NULL);
 
   /* Setup our extra menu so that consumers can use
-   * ide_source_view_append_men() or similar to update menus.
+   * ide_source_view_append_menu() or similar to update menus.
    */
   self->joined_menu = ide_joined_menu_new ();
   gtk_text_view_set_extra_menu (GTK_TEXT_VIEW (self),
diff --git a/src/libide/sourceview/libide-sourceview.gresource.xml 
b/src/libide/sourceview/libide-sourceview.gresource.xml
index 203de6496..33fffdf8b 100644
--- a/src/libide/sourceview/libide-sourceview.gresource.xml
+++ b/src/libide/sourceview/libide-sourceview.gresource.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/libide-sourceview">
+    <file preprocess="xml-stripblanks">gtk/menus.ui</file>
   </gresource>
 </gresources>


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