[gtk+/resizegrips] Initial attempt at generic resize grips



commit 9e9e76862b9880e5aed8b31eeaae13a5766e4055
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Sep 27 22:41:24 2010 -0400

    Initial attempt at generic resize grips

 gtk/gtkwindow.c |  267 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 259 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index b663636..6f97950 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -104,6 +104,9 @@ struct _GtkWindowPrivate
 
   gdouble  opacity;
 
+  gboolean   has_resize_grip;
+  GdkWindow *grip_window;
+
   gchar   *startup_id;
   gchar   *title;
   gchar   *wmclass_class;
@@ -201,7 +204,8 @@ enum {
   PROP_GRAVITY,
   PROP_TRANSIENT_FOR,
   PROP_OPACITY,
-  
+  PROP_HAS_RESIZE_GRIP,
+
   /* Readonly properties */
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
@@ -307,6 +311,8 @@ static gint gtk_window_key_press_event    (GtkWidget         *widget,
 					   GdkEventKey       *event);
 static gint gtk_window_key_release_event  (GtkWidget         *widget,
 					   GdkEventKey       *event);
+static gint gtk_window_button_press_event (GtkWidget         *widget,
+                                           GdkEventButton    *event);
 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
 					   GdkEventCrossing  *event);
 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
@@ -379,6 +385,11 @@ 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        gtk_window_notify_keys_changed (GtkWindow   *window);
 static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
@@ -542,6 +553,7 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->enter_notify_event = gtk_window_enter_notify_event;
   widget_class->leave_notify_event = gtk_window_leave_notify_event;
   widget_class->focus_in_event = gtk_window_focus_in_event;
+  widget_class->button_press_event = gtk_window_button_press_event;
   widget_class->focus_out_event = gtk_window_focus_out_event;
   widget_class->client_event = gtk_window_client_event;
   widget_class->focus = gtk_window_focus;
@@ -819,6 +831,21 @@ gtk_window_class_init (GtkWindowClass *klass)
 							 TRUE,
 							 GTK_PARAM_READWRITE));
 
+  /**
+   * GtkWindow:has-resize-grip
+   *
+   * Whether the window should have a corner resize grip.
+   *
+   * Since: 2.20
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_HAS_RESIZE_GRIP,
+                                   g_param_spec_boolean ("has-resize-grip",
+                                                         P_("Resize grip"),
+                                                         P_("Specifies whether the window should have a resize grip"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
+
 
   /**
    * GtkWindow:gravity:
@@ -1026,6 +1053,7 @@ gtk_window_init (GtkWindow *window)
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   priv->opacity = 1.0;
   priv->startup_id = NULL;
+  priv->has_resize_grip = TRUE;
   priv->mnemonics_visible = TRUE;
 
   g_object_ref_sink (window);
@@ -1046,7 +1074,7 @@ gtk_window_set_property (GObject      *object,
 {
   GtkWindow  *window = GTK_WINDOW (object);
   GtkWindowPrivate *priv = window->priv;
-  
+
   switch (prop_id)
     {
     case PROP_TYPE:
@@ -1060,7 +1088,7 @@ gtk_window_set_property (GObject      *object,
       break;
     case PROP_STARTUP_ID:
       gtk_window_set_startup_id (window, g_value_get_string (value));
-      break; 
+      break;
     case PROP_RESIZABLE:
       priv->resizable = g_value_get_boolean (value);
       gtk_widget_queue_resize (GTK_WIDGET (window));
@@ -1136,6 +1164,8 @@ gtk_window_set_property (GObject      *object,
     case PROP_OPACITY:
       gtk_window_set_opacity (window, g_value_get_double (value));
       break;
+    case PROP_HAS_RESIZE_GRIP:
+      gtk_window_set_has_resize_grip (window, g_value_get_boolean (value));
     case PROP_MNEMONICS_VISIBLE:
       gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
       break;
@@ -1248,6 +1278,8 @@ gtk_window_get_property (GObject      *object,
     case PROP_OPACITY:
       g_value_set_double (value, gtk_window_get_opacity (window));
       break;
+    case PROP_HAS_RESIZE_GRIP:
+      g_value_set_boolean (value, priv->has_resize_grip);
     case PROP_MNEMONICS_VISIBLE:
       g_value_set_boolean (value, priv->mnemonics_visible);
       break;
@@ -4540,6 +4572,9 @@ gtk_window_map (GtkWidget *widget)
   if (priv->frame)
     gdk_window_show (priv->frame);
 
+  if (priv->grip_window)
+    gdk_window_show (priv->grip_window);
+
   if (!disable_startup_notification)
     {
       /* Do we have a custom startup-notification id? */
@@ -4591,7 +4626,7 @@ gtk_window_unmap (GtkWidget *widget)
 {
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = window->priv;
-  GtkWindowGeometryInfo *info;    
+  GtkWindowGeometryInfo *info;
   GdkWindow *gdk_window;
   GdkWindowState state;
 
@@ -4603,6 +4638,9 @@ gtk_window_unmap (GtkWidget *widget)
   else
     gdk_window_withdraw (gdk_window);
 
+  if (priv->grip_window)
+    gdk_window_hide (priv->grip_window);
+
   priv->configure_request_count = 0;
   priv->configure_notify_received = FALSE;
 
@@ -4814,6 +4852,9 @@ gtk_window_realize (GtkWidget *widget)
 
   /* Icons */
   gtk_window_realize_icon (window);
+
+  if (priv->has_resize_grip)
+    resize_grip_create_window (window);
 }
 
 static void
@@ -4856,6 +4897,44 @@ gtk_window_unrealize (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
 }
 
+static GdkWindowEdge
+get_grip_edge (GtkWidget *widget)
+{
+  return gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_SOUTH_EAST : GDK_WINDOW_EDGE_SOUTH_WEST;
+}
+
+static void
+set_grip_cursor (GtkWindow *window)
+{
+  GtkWindowPrivate *priv = window->priv;
+
+  if (priv->has_resize_grip && priv->grip_window != NULL)
+    {
+      GtkWidget *widget = GTK_WIDGET (window);
+      GdkDisplay *display;
+      GdkWindowEdge edge;
+      GdkCursorType cursor_type;
+      GdkCursor *cursor;
+
+      if (gtk_widget_is_sensitive (widget))
+        {
+          display = gtk_widget_get_display (widget);
+          edge = get_grip_edge (widget);
+
+          if (edge == GDK_WINDOW_EDGE_SOUTH_EAST)
+            cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+          else
+            cursor_type = GDK_BOTTOM_LEFT_CORNER;
+
+          cursor = gdk_cursor_new_for_display (display, cursor_type);
+          gdk_window_set_cursor (priv->grip_window, cursor);
+          gdk_cursor_unref (cursor);
+        }
+      else
+        gdk_window_set_cursor (priv->grip_window, NULL);
+    }
+}
+
 static void
 gtk_window_size_allocate (GtkWidget     *widget,
 			  GtkAllocation *allocation)
@@ -4888,6 +4967,19 @@ gtk_window_size_allocate (GtkWidget     *widget,
 			 allocation->width + priv->frame_left + priv->frame_right,
 			 allocation->height + priv->frame_top + priv->frame_bottom);
     }
+
+  if (priv->grip_window != NULL)
+    {
+      GdkRectangle rect;
+
+      get_grip_rect (window, &rect);
+
+      gdk_window_move_resize (priv->grip_window,
+                              rect.x, rect.y,
+                              rect.width, rect.height);
+
+      set_grip_cursor (window);
+    }
 }
 
 static gint
@@ -5008,11 +5100,130 @@ gtk_window_configure_event (GtkWidget         *widget,
   allocation.height = event->height;
   gtk_widget_set_allocation (widget, &allocation);
 
+  gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); // XXX - What was this for again?
+
   _gtk_container_queue_resize (GTK_CONTAINER (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. */
+  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
+resize_grip_create_window (GtkWindow *window)
+{
+  GtkWidget *widget;
+  GtkWindowPrivate *priv;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GdkRectangle rect;
+
+  priv = window->priv;
+  widget = GTK_WIDGET (window);
+
+  g_return_if_fail (gtk_widget_get_realized (widget));
+  g_return_if_fail (priv->grip_window == NULL);
+
+  get_grip_rect (window, &rect);
+
+  attributes.x = rect.x;
+  attributes.y = rect.y;
+  attributes.width = rect.width;
+  attributes.height = rect.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_ONLY;
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_BUTTON_PRESS_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  priv->grip_window = gdk_window_new (gtk_widget_get_window (widget),
+                                      &attributes,
+                                      attributes_mask);
+
+  gdk_window_set_user_data (priv->grip_window, widget);
+
+  gdk_window_raise (priv->grip_window);
+
+  set_grip_cursor (window);
+}
+
+static void
+resize_grip_destroy_window (GtkWindow *window)
+{
+  GtkWindowPrivate *priv = window->priv;
+
+  gdk_window_set_user_data (priv->grip_window, NULL);
+  gdk_window_destroy (priv->grip_window);
+  priv->grip_window = NULL;
+}
+
+static void
+gtk_window_set_has_resize_grip (GtkWindow *window,
+                                gboolean   value)
+{
+  GtkWidget *widget = GTK_WIDGET (window);
+  GtkWindowPrivate *priv = window->priv;
+
+  value = value != FALSE;
+
+  if (value != priv->has_resize_grip)
+    {
+      priv->has_resize_grip = value;
+      //gtk_widget_queue_resize (statusbar->label);  // XXX
+      gtk_widget_queue_draw (widget);
+
+      if (gtk_widget_get_realized (widget))
+        {
+          if (priv->has_resize_grip && priv->grip_window == NULL)
+            {
+              resize_grip_create_window (window);
+
+              if (gtk_widget_get_mapped (widget))
+                {
+                  gdk_window_show (priv->grip_window);
+                }
+            }
+          else if (!priv->has_resize_grip && priv->grip_window != NULL)
+            {
+              resize_grip_destroy_window (window);
+            }
+        }
+
+      g_object_notify (G_OBJECT (priv), "has-resize-grip");
+    }
+}
+
 /* 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
@@ -5151,6 +5362,25 @@ gtk_window_key_release_event (GtkWidget   *widget,
   return handled;
 }
 
+static gint
+gtk_window_button_press_event (GtkWidget *widget,
+                               GdkEventButton *event)
+{
+  GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+
+  if (event->window == priv->grip_window)
+    {
+      gtk_window_begin_resize_drag (GTK_WINDOW (widget),
+                                    get_grip_edge (widget),
+                                    event->button,
+                                    event->x_root,
+                                    event->y_root,
+                                    event->time);
+    }
+
+  return FALSE;
+}
+
 static void
 gtk_window_real_activate_default (GtkWindow *window)
 {
@@ -6652,7 +6882,10 @@ static gboolean
 gtk_window_draw (GtkWidget *widget,
 		 cairo_t   *cr)
 {
-  if (!gtk_widget_get_app_paintable (widget))
+  GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+  gboolean ret = FALSE;
+
+ if (!gtk_widget_get_app_paintable (widget))
     gtk_paint_flat_box (gtk_widget_get_style (widget),
                         cr,
                         GTK_STATE_NORMAL,
@@ -6660,11 +6893,29 @@ gtk_window_draw (GtkWidget *widget,
                         0, 0,
                         gtk_widget_get_allocated_width (widget),
                         gtk_widget_get_allocated_height (widget));
-  
+
   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
-    return GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
+    ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
 
-  return FALSE;
+  if (priv->has_resize_grip)
+    {
+      GdkRectangle rect;
+      GtkAllocation allocation;
+
+      gtk_widget_get_allocation (widget, &allocation);
+      get_grip_rect (GTK_WINDOW (widget), &rect);
+
+      gtk_paint_resize_grip (gtk_widget_get_style (widget),
+                             cr,
+                             gtk_widget_get_state (widget),
+                             widget,
+                             "statusbar",
+                             get_grip_edge (widget),
+                             rect.x, rect.y,
+                             rect.width, rect.height);
+    }
+
+  return ret;
 }
 
 /**



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