[gtk+/resizegrips] Get scrollbars out of the way of the window's resize grip.



commit a303eec75f24aa404c051c999fa8d4e555cfe9a7
Author: Cody Russell <bratsche gnome org>
Date:   Thu Sep 30 14:11:09 2010 -0500

    Get scrollbars out of the way of the window's resize grip.

 gtk/gtkrange.c  |  112 ++++++++++++++++++++++++++++++
 gtk/gtkwindow.c |  207 +++++++++++++++++++++++++++++++++++++-----------------
 gtk/gtkwindow.h |   10 +++
 3 files changed, 264 insertions(+), 65 deletions(-)
---
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index 07d89e1..0da7247 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -37,6 +37,7 @@
 #include "gtkrange.h"
 #include "gtkscale.h"
 #include "gtkscrollbar.h"
+#include "gtkwindow.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 
@@ -1569,12 +1570,123 @@ gtk_range_size_request (GtkWidget      *widget,
   requisition->height = range_rect.height + border.top + border.bottom;
 }
 
+static GtkWidget *
+find_toplevel_window (GtkWidget *widget)
+{
+  if (GTK_IS_WINDOW (widget))
+    {
+      return widget;
+    }
+  else if (gtk_widget_get_parent (widget))
+    {
+      return find_toplevel_window (gtk_widget_get_parent (widget));
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+static gint
+get_fixup_for_window_grip (GtkWidget *widget)
+{
+  GtkWidget *window;
+  GtkRange *range = GTK_RANGE (widget);
+
+  window = find_toplevel_window (widget);
+  if (window == NULL)
+    {
+      return 0;
+    }
+
+  if (!gtk_window_resize_grip_is_visible (GTK_WINDOW (window)))
+    {
+      return 0;
+    }
+
+  if (gtk_window_get_has_resize_grip (GTK_WINDOW (window)))
+    {
+      GtkRangePrivate *priv;
+      GdkRectangle grip_rect;
+      GdkRectangle orig_rect;
+      GdkRectangle translated_rect;
+      gint x = 0;
+      gint y = 0;
+
+      priv = range->priv;
+
+      gtk_range_calc_layout (range, priv->adjustment->value);
+
+      /* Get the area of the window's corner grip */
+      gtk_window_get_resize_grip_area (GTK_WINDOW (window),
+                                       &grip_rect);
+
+      /* Get the area of the stepper that might be blocked by the grip */
+      if (gtk_widget_get_direction (window) == GTK_TEXT_DIR_LTR)
+        {
+          orig_rect = priv->stepper_d;
+        }
+      else
+        {
+          orig_rect = priv->stepper_a;
+        }
+
+      /* Translate the stepper's area into window coords */
+      if (gtk_widget_translate_coordinates (widget,
+                                            window,
+                                            orig_rect.x,
+                                            orig_rect.y,
+                                            &x,
+                                            &y))
+        {
+          translated_rect.x = x;
+          translated_rect.y = y;
+          translated_rect.width = orig_rect.width;
+          translated_rect.height = orig_rect.height;
+
+          /* If the stepper button intersects the window resize grip.. */
+          if (gdk_rectangle_intersect (&grip_rect, &translated_rect, NULL))
+            {
+              gint grip_height;
+              gint grip_width;
+
+              /* Return the height of the grip */
+              gtk_widget_style_get (window,
+                                    "resize-grip-height", &grip_height,
+                                    "resize-grip-width",  &grip_width,
+                                    NULL);
+
+              if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
+                return grip_width;
+              else
+                return grip_height;
+            }
+        }
+    }
+
+  return 0;
+}
+
 static void
 gtk_range_size_allocate (GtkWidget     *widget,
                          GtkAllocation *allocation)
 {
   GtkRange *range = GTK_RANGE (widget);
   GtkRangePrivate *priv = range->priv;
+  gint fixup;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  fixup = get_fixup_for_window_grip (widget);
+
+  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_VERTICAL)
+    {
+      allocation->height -= fixup;
+    }
+  else
+    {
+      allocation->width -= fixup;
+    }
 
   gtk_widget_set_allocation (widget, allocation);
 
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 83b0fde..5867753 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -391,12 +391,9 @@ static GList   *icon_list_from_theme                  (GtkWidget    *widget,
 						       const gchar  *name);
 static void     gtk_window_realize_icon               (GtkWindow    *window);
 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
-static void     get_grip_rect                         (GtkWindow    *window,
-                                                       GdkRectangle *rect);
-static void     gtk_window_set_has_resize_grip        (GtkWindow    *window,
-                                                       gboolean      value);
 static void     resize_grip_create_window             (GtkWindow    *window);
 static void     resize_grip_destroy_window            (GtkWindow    *window);
+static void     update_grip_visibility                (GtkWindow    *window);
 
 static void        gtk_window_notify_keys_changed (GtkWindow   *window);
 static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
@@ -846,7 +843,7 @@ gtk_window_class_init (GtkWindowClass *klass)
    *
    * Whether the window should have a corner resize grip.
    *
-   * Since: 2.20
+   * Since: 3.0
    */
   g_object_class_install_property (gobject_class,
                                    PROP_HAS_RESIZE_GRIP,
@@ -909,6 +906,24 @@ gtk_window_class_init (GtkWindowClass *klass)
 							1.0,
 							GTK_PARAM_READWRITE));
 
+
+  /* Style properties.
+   */
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("resize-grip-width",
+                                                             P_("Width of resize grip"),
+                                                             P_("Width of resize grip"),
+                                                             0, G_MAXINT, 16, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("resize-grip-height",
+                                                             P_("Height of resize grip"),
+                                                             P_("Height of resize grip"),
+                                                             0, G_MAXINT, 16, GTK_PARAM_READWRITE));
+
+
+  /* Signals
+   */
   window_signals[SET_FOCUS] =
     g_signal_new (I_("set-focus"),
                   G_TYPE_FROM_CLASS (gobject_class),
@@ -4993,7 +5008,7 @@ set_grip_position (GtkWindow *window)
   if (priv->grip_window == NULL)
     return;
 
-  get_grip_rect (window, &rect);
+  gtk_window_get_resize_grip_area (window, &rect);
   gdk_window_raise (priv->grip_window);
   gdk_window_move_resize (priv->grip_window,
                           rect.x, rect.y,
@@ -5166,63 +5181,11 @@ gtk_window_configure_event (GtkWidget         *widget,
   return TRUE;
 }
 
-static void
-get_grip_rect (GtkWindow    *window,
-               GdkRectangle *rect)
-{
-  GtkWidget *widget;
-  GtkAllocation allocation;
-  GtkStyle *style;
-  gint w, h;
-
-  widget = GTK_WIDGET (window);
-  gtk_widget_get_allocation (widget, &allocation);
-  style = gtk_widget_get_style (widget);
-
-  /* These are in effect the max/default size of the grip. */
-  /* FIXME: need to take from style */
-  w = 18;
-  h = 18;
-
-  if (w > allocation.width)
-    w = allocation.width;
-
-  if (h > allocation.height - style->ythickness)
-    h = allocation.height - style->ythickness;
-
-  rect->width = w;
-  rect->height = h;
-  rect->y = allocation.y + allocation.height - h;
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
-    rect->x = allocation.x + allocation.width - w;
-  else
-    rect->x = allocation.x + style->xthickness;
-}
-
-static void
-set_grip_visibility (GtkWindow *window)
-{
-  GtkWindowPrivate *priv = window->priv;
-  GdkWindowState state;
-
-  if (priv->grip_window == NULL)
-    return;
-
-  state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
-
-  if (priv->has_resize_grip && priv->resizable &&
-      (state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) == 0)
-    gdk_window_show (priv->grip_window);
-  else
-    gdk_window_hide (priv->grip_window);
-}
-
 static gboolean
 gtk_window_state_event (GtkWidget           *widget,
                         GdkEventWindowState *event)
 {
-  set_grip_visibility (GTK_WINDOW (widget));
+  update_grip_visibility (GTK_WINDOW (widget));
 
   return FALSE;
 }
@@ -5245,7 +5208,7 @@ gtk_window_state_changed (GtkWidget    *widget,
   GtkWindow *window = GTK_WINDOW (widget);
 
   set_grip_cursor (window);
-  set_grip_visibility (window);
+  update_grip_visibility (window);
 }
 
 static void
@@ -5263,7 +5226,7 @@ resize_grip_create_window (GtkWindow *window)
   g_return_if_fail (gtk_widget_get_realized (widget));
   g_return_if_fail (priv->grip_window == NULL);
 
-  get_grip_rect (window, &rect);
+  gtk_window_get_resize_grip_area (window, &rect);
 
   attributes.x = rect.x;
   attributes.y = rect.y;
@@ -5287,7 +5250,7 @@ resize_grip_create_window (GtkWindow *window)
 
   set_grip_cursor (window);
   set_grip_shape (window);
-  set_grip_visibility (window);
+  update_grip_visibility (window);
 }
 
 static void
@@ -5300,7 +5263,7 @@ resize_grip_destroy_window (GtkWindow *window)
   priv->grip_window = NULL;
 }
 
-static void
+void
 gtk_window_set_has_resize_grip (GtkWindow *window,
                                 gboolean   value)
 {
@@ -5326,6 +5289,120 @@ gtk_window_set_has_resize_grip (GtkWindow *window,
     }
 }
 
+static void
+update_grip_visibility (GtkWindow *window)
+{
+  if (gtk_window_resize_grip_is_visible (window))
+    {
+      gdk_window_show (window->priv->grip_window);
+    }
+  else
+    {
+      gdk_window_hide (window->priv->grip_window);
+    }
+}
+
+/**
+ * gtk_window_resize_grip_is_visible:
+ * @window: a #GtkWindow
+ *
+ * Determines whether a resize grip is visible for the specified window.
+ *
+ * Returns %TRUE if a resize grip exists and is visible.
+ *
+ * Since: 3.0
+ */
+gboolean
+gtk_window_resize_grip_is_visible (GtkWindow *window)
+{
+  GdkWindowState state;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  if (!gtk_widget_get_realized (GTK_WIDGET (window)))
+    return FALSE;
+
+  state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+
+  if (state & GDK_WINDOW_STATE_MAXIMIZED || state & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+      return FALSE;
+    }
+
+  return window->priv->has_resize_grip;
+}
+
+/**
+ * gtk_window_get_has_resize_grip:
+ * @window: a #GtkWindow
+ *
+ * Determines whether the window has a resize grip.
+ *
+ * Returns: %TRUE if the window has a resize grip.
+ *
+ * Since: 3.0
+ */
+gboolean
+gtk_window_get_has_resize_grip (GtkWindow *window)
+{
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  return window->priv->has_resize_grip;
+}
+
+/**
+ * gtk_window_get_resize_grip_area:
+ * @window: a #GtkWindow
+ * @rect: a pointer to a #GdkRectangle which we should store the resize grip area.
+ *
+ * If a window has a resize grip, this will retrieve the grip position, width
+ * and height into the specified #GdkRectangle.
+ *
+ * Returns: %TRUE if the resize grip's area was retrieved.
+ *
+ * Since: 3.0
+ */
+gboolean
+gtk_window_get_resize_grip_area (GtkWindow *window,
+                                 GdkRectangle *rect)
+{
+  GtkWidget *widget = GTK_WIDGET (window);
+  GtkAllocation allocation;
+  GtkStyle *style;
+  gint grip_width;
+  gint grip_height;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  if (!window->priv->has_resize_grip)
+    return FALSE;
+
+  gtk_widget_get_allocation (widget, &allocation);
+  style = gtk_widget_get_style (widget);
+
+  gtk_widget_style_get (widget,
+                        "resize-grip-width", &grip_width,
+                        "resize-grip-height", &grip_height,
+                        NULL);
+
+  if (grip_width > allocation.width)
+    grip_width = allocation.width;
+
+  if (grip_height > allocation.height)
+    grip_height = allocation.height;
+
+  rect->width = grip_width;
+  rect->height = grip_height;
+  rect->y = allocation.y + allocation.height - grip_height;
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+    rect->x = allocation.x + allocation.width - grip_width;
+  else
+    rect->x = allocation.x + style->xthickness;
+
+  return TRUE;
+}
+
 /* the accel_key and accel_mods fields of the key have to be setup
  * upon calling this function. it'll then return whether that key
  * is at all used as accelerator, and if so will OR in the
@@ -7004,7 +7081,7 @@ gtk_window_draw (GtkWidget *widget,
 
       cairo_save (cr);
       gtk_cairo_transform_to_window (cr, widget, priv->grip_window);
-      get_grip_rect (GTK_WINDOW (widget), &rect);
+      gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect);
       gtk_paint_resize_grip (gtk_widget_get_style (widget),
                              cr,
                              gtk_widget_get_state (widget),
@@ -7658,7 +7735,7 @@ gtk_window_set_resizable (GtkWindow *window,
   g_object_notify (G_OBJECT (window), "resizable");
 
   if (priv->grip_window != NULL)
-    set_grip_visibility (window);
+    update_grip_visibility (window);
 
   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
 }
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 792eeea..eb7d4d9 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -340,6 +340,16 @@ GtkWidget *      gtk_window_group_get_current_device_grab (GtkWindowGroup *windo
                                                            GdkDevice      *device);
 
 
+/* Window grips
+ */
+void     gtk_window_set_has_resize_grip    (GtkWindow    *window,
+                                            gboolean      value);
+gboolean gtk_window_get_has_resize_grip    (GtkWindow    *window);
+gboolean gtk_window_resize_grip_is_visible (GtkWindow    *window);
+gboolean gtk_window_get_resize_grip_area   (GtkWindow    *window,
+                                            GdkRectangle *rect);
+
+
 /* --- internal functions --- */
 void            _gtk_window_internal_set_focus (GtkWindow *window,
 						GtkWidget *focus);



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