[gtk/gtk-3-24: 4/5] menu: Adapt scroll offset if arrow is shown



commit c35878ecf1e9ee960b72b213b73c15f92b64afe5
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Jan 17 19:27:51 2019 +0100

    menu: Adapt scroll offset if arrow is shown
    
    When a popup is placed using move_to_rect(), it'll get feedback about
    the position and size it got assigned. We use this feedback to update
    the scroll offset, but while doing so, if the visibility of the arrow
    changed, we didn't adapt the offset accordingly.
    
    Fix this by offsetting the provided offset by the height of the arrow,
    if it was made visible as a side effect of the scroll offset change
    triggered by the feedback.
    
    Related: mutter#105
    Closes: #1463

 gtk/gtkmenu.c | 74 +++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 52 insertions(+), 22 deletions(-)
---
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 5b84eab3fa..f079f06e91 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -213,6 +213,12 @@ enum {
   CHILD_PROP_BOTTOM_ATTACH
 };
 
+typedef enum _GtkMenuScrollFlag
+{
+  GTK_MENU_SCROLL_FLAG_NONE = 0,
+  GTK_MENU_SCROLL_FLAG_ADAPT = 1 << 0,
+} GtkMenuScrollFlag;
+
 static void     gtk_menu_set_property      (GObject          *object,
                                             guint             prop_id,
                                             const GValue     *value,
@@ -255,7 +261,8 @@ static gboolean gtk_menu_enter_notify      (GtkWidget        *widget,
 static gboolean gtk_menu_leave_notify      (GtkWidget        *widget,
                                             GdkEventCrossing *event);
 static void     gtk_menu_scroll_to         (GtkMenu          *menu,
-                                            gint              offset);
+                                            gint              offset,
+                                            GtkMenuScrollFlag flags);
 static void     gtk_menu_grab_notify       (GtkWidget        *widget,
                                             gboolean          was_grabbed);
 static gboolean gtk_menu_captured_event    (GtkWidget        *widget,
@@ -1977,7 +1984,7 @@ gtk_menu_popup_internal (GtkMenu             *menu,
 
   associate_menu_grab_transfer_window (menu);
 
-  gtk_menu_scroll_to (menu, priv->scroll_offset);
+  gtk_menu_scroll_to (menu, priv->scroll_offset, GTK_MENU_SCROLL_FLAG_NONE);
 
   /* if no item is selected, select the first one */
   if (!menu_shell->priv->active_menu_item &&
@@ -2479,7 +2486,8 @@ gtk_menu_update_scroll_offset (GtkMenu            *menu,
 
   get_arrows_border (menu, &arrows_border);
   menu->priv->scroll_offset = arrows_border.top + (final_rect->y - flipped_rect->y);
-  gtk_menu_scroll_to (menu, menu->priv->scroll_offset);
+  gtk_menu_scroll_to (menu, menu->priv->scroll_offset,
+                      GTK_MENU_SCROLL_FLAG_ADAPT);
 }
 
 /**
@@ -2552,7 +2560,8 @@ gtk_menu_popdown (GtkMenu *menu)
        * non-tearoff menu was popped down.
        */
       if (!priv->tearoff_active)
-        gtk_menu_scroll_to (menu, priv->saved_scroll_offset);
+        gtk_menu_scroll_to (menu, priv->saved_scroll_offset,
+                            GTK_MENU_SCROLL_FLAG_NONE);
       priv->tearoff_active = TRUE;
     }
   else
@@ -2843,7 +2852,7 @@ gtk_menu_scrollbar_changed (GtkAdjustment *adjustment,
 
   value = gtk_adjustment_get_value (adjustment);
   if (menu->priv->scroll_offset != value)
-    gtk_menu_scroll_to (menu, value);
+    gtk_menu_scroll_to (menu, value, GTK_MENU_SCROLL_FLAG_NONE);
 }
 
 static void
@@ -3036,7 +3045,7 @@ gtk_menu_set_tearoff_state (GtkMenu  *menu,
           gtk_widget_show (GTK_WIDGET (menu));
           gtk_widget_show (priv->tearoff_window);
 
-          gtk_menu_scroll_to (menu, 0);
+          gtk_menu_scroll_to (menu, 0, GTK_MENU_SCROLL_FLAG_NONE);
 
         }
       else
@@ -3482,7 +3491,7 @@ gtk_menu_size_allocate (GtkWidget     *widget,
   height = allocation->height - (2 * border_width) - padding.top - padding.bottom;
 
   if (menu_shell->priv->active)
-    gtk_menu_scroll_to (menu, priv->scroll_offset);
+    gtk_menu_scroll_to (menu, priv->scroll_offset, GTK_MENU_SCROLL_FLAG_NONE);
 
   get_arrows_border (menu, &arrow_border);
 
@@ -3590,7 +3599,7 @@ gtk_menu_size_allocate (GtkWidget     *widget,
                   gtk_widget_hide (priv->tearoff_scrollbar);
                   gtk_menu_set_tearoff_hints (menu, allocation->width);
 
-                  gtk_menu_scroll_to (menu, 0);
+                  gtk_menu_scroll_to (menu, 0, GTK_MENU_SCROLL_FLAG_NONE);
                 }
             }
           else
@@ -4168,7 +4177,7 @@ gtk_menu_scroll_by (GtkMenu *menu,
     offset = priv->requested_height - view_height;
 
   if (offset != priv->scroll_offset)
-    gtk_menu_scroll_to (menu, offset);
+    gtk_menu_scroll_to (menu, offset, GTK_MENU_SCROLL_FLAG_NONE);
 }
 
 static gboolean
@@ -4678,7 +4687,7 @@ gtk_menu_captured_event (GtkWidget *widget,
                               MIN (priv->scroll_offset, 0),
                               MAX (priv->scroll_offset, priv->requested_height - view_height));
 
-              gtk_menu_scroll_to (menu, offset);
+              gtk_menu_scroll_to (menu, offset, GTK_MENU_SCROLL_FLAG_NONE);
 
               retval = TRUE;
             }
@@ -5323,11 +5332,26 @@ gtk_menu_stop_scrolling (GtkMenu *menu)
 }
 
 static void
-gtk_menu_scroll_to (GtkMenu *menu,
-                    gint    offset)
+sync_arrows_state (GtkMenu *menu)
 {
   GtkMenuPrivate *priv = menu->priv;
   GtkCssNode *top_arrow_node, *bottom_arrow_node;
+
+  top_arrow_node = gtk_css_gadget_get_node (priv->top_arrow_gadget);
+  gtk_css_node_set_visible (top_arrow_node, priv->upper_arrow_visible);
+  gtk_css_node_set_state (top_arrow_node, priv->upper_arrow_state);
+
+  bottom_arrow_node = gtk_css_gadget_get_node (priv->bottom_arrow_gadget);
+  gtk_css_node_set_visible (bottom_arrow_node, priv->lower_arrow_visible);
+  gtk_css_node_set_state (bottom_arrow_node, priv->lower_arrow_state);
+}
+
+static void
+gtk_menu_scroll_to (GtkMenu           *menu,
+                    gint               offset,
+                    GtkMenuScrollFlag  flags)
+{
+  GtkMenuPrivate *priv = menu->priv;
   GtkBorder arrow_border, padding;
   GtkWidget *widget;
   gint x, y;
@@ -5363,13 +5387,25 @@ gtk_menu_scroll_to (GtkMenu *menu,
         {
           GtkStateFlags upper_arrow_previous_state = priv->upper_arrow_state;
           GtkStateFlags lower_arrow_previous_state = priv->lower_arrow_state;
+          gboolean should_offset_by_arrow;
 
           if (!priv->upper_arrow_visible || !priv->lower_arrow_visible)
             gtk_widget_queue_draw (GTK_WIDGET (menu));
 
+          if (!priv->upper_arrow_visible &
+              flags & GTK_MENU_SCROLL_FLAG_ADAPT)
+            should_offset_by_arrow = TRUE;
+          else
+            should_offset_by_arrow = FALSE;
+
           priv->upper_arrow_visible = priv->lower_arrow_visible = TRUE;
 
+          if (flags & GTK_MENU_SCROLL_FLAG_ADAPT)
+            sync_arrows_state (menu);
+
           get_arrows_border (menu, &arrow_border);
+          if (should_offset_by_arrow)
+            offset += arrow_border.top;
           y += arrow_border.top;
           view_height -= arrow_border.top;
           view_height -= arrow_border.bottom;
@@ -5436,13 +5472,7 @@ gtk_menu_scroll_to (GtkMenu *menu,
         }
     }
 
-  top_arrow_node = gtk_css_gadget_get_node (priv->top_arrow_gadget);
-  gtk_css_node_set_visible (top_arrow_node, priv->upper_arrow_visible);
-  gtk_css_node_set_state (top_arrow_node, priv->upper_arrow_state);
-
-  bottom_arrow_node = gtk_css_gadget_get_node (priv->bottom_arrow_gadget);
-  gtk_css_node_set_visible (bottom_arrow_node, priv->lower_arrow_visible);
-  gtk_css_node_set_state (bottom_arrow_node, priv->lower_arrow_state);
+  sync_arrows_state (menu);
 
   /* Scroll the menu: */
   if (gtk_widget_get_realized (widget))
@@ -5528,7 +5558,7 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
            * is on the menu
            */
           menu_shell->priv->ignore_enter = TRUE;
-          gtk_menu_scroll_to (menu, child_offset);
+          gtk_menu_scroll_to (menu, child_offset, GTK_MENU_SCROLL_FLAG_NONE);
         }
       else
         {
@@ -5549,7 +5579,7 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
                * is on the menu
                */
               menu_shell->priv->ignore_enter = TRUE;
-              gtk_menu_scroll_to (menu, y);
+              gtk_menu_scroll_to (menu, y, GTK_MENU_SCROLL_FLAG_NONE);
             }
         }
     }
@@ -6033,7 +6063,7 @@ gtk_menu_real_move_scroll (GtkMenu       *menu,
         new_offset = priv->scroll_offset + step;
         new_offset = CLAMP (new_offset, 0, end_position - page_size);
 
-        gtk_menu_scroll_to (menu, new_offset);
+        gtk_menu_scroll_to (menu, new_offset, GTK_MENU_SCROLL_FLAG_NONE);
 
         if (menu_shell->priv->active_menu_item)
           {


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