[gtk+] Allow windows to be dragged by clicking on empty areas



commit 7491e9e97aa6b0f9950897c4f1282b470c79d451
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jul 16 01:15:47 2010 -0400

    Allow windows to be dragged by clicking on empty areas
    
    Allow windows to be dragged by clicking on empty areas in menubars
    and toolbars. This is under theme control, via the GtkWidget::window-dragging
    style property. The idea is that it makes sense to turn this on if a
    theme makes the window frame and the menubar/toolbar appear visually
    contiguous.
    
    The main patch was written by Cody Russell, with a contribution by
    Ayan George. See bug 611313.

 gtk/gtkmenushell.c         |   41 ++++++++--
 gtk/gtkseparatortoolitem.c |  197 ++++++++++++++++++++++++++++++++++++--------
 gtk/gtktoolbar.c           |   30 ++++++-
 gtk/gtkwidget.c            |    7 ++
 4 files changed, 231 insertions(+), 44 deletions(-)
---
diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c
index 1a8b80d..3fb8ee6 100644
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@ -596,18 +596,45 @@ gtk_menu_shell_button_press (GtkWidget      *widget,
 
   if (!menu_shell->active || !menu_shell->button)
     {
-      _gtk_menu_shell_activate (menu_shell);
+      gboolean initially_active = menu_shell->active;
 
       menu_shell->button = event->button;
 
-      if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
-	  menu_item->parent == widget &&
-          menu_item != menu_shell->active_menu_item)
+      if (menu_item)
         {
-          if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
+          if (_gtk_menu_item_is_selectable (menu_item) &&
+              menu_item->parent == widget &&
+              menu_item != menu_shell->active_menu_item)
             {
-              menu_shell->activate_time = event->time;
-              gtk_menu_shell_select_item (menu_shell, menu_item);
+              _gtk_menu_shell_activate (menu_shell);
+              menu_shell->button = event->button;
+
+              if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
+                {
+                  menu_shell->activate_time = event->time;
+                  gtk_menu_shell_select_item (menu_shell, menu_item);
+                }
+            }
+        }
+      else
+        {
+          if (!initially_active)
+            {
+              gboolean window_drag = FALSE;
+
+              gtk_widget_style_get (widget,
+                                    "window-dragging", &window_drag,
+                                    NULL);
+
+              if (window_drag)
+                {
+                  gtk_menu_shell_deactivate (menu_shell);
+                  gtk_window_begin_move_drag (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+                                              event->button,
+                                              event->x_root,
+                                              event->y_root,
+                                              event->time);
+                }
             }
         }
     }
diff --git a/gtk/gtkseparatortoolitem.c b/gtk/gtkseparatortoolitem.c
index 54f72df..3b02eb2 100644
--- a/gtk/gtkseparatortoolitem.c
+++ b/gtk/gtkseparatortoolitem.c
@@ -44,11 +44,11 @@
  * Use gtk_separator_tool_item_new() to create a new #GtkSeparatorToolItem.
  */
 
-
 #define MENU_ID "gtk-separator-tool-item-menu-id"
 
 struct _GtkSeparatorToolItemPrivate
 {
+  GdkWindow *event_window;
   guint draw : 1;
 };
 
@@ -59,20 +59,28 @@ enum {
 
 static gboolean gtk_separator_tool_item_create_menu_proxy (GtkToolItem               *item);
 static void     gtk_separator_tool_item_set_property      (GObject                   *object,
-							   guint                      prop_id,
-							   const GValue              *value,
-							   GParamSpec                *pspec);
-static void     gtk_separator_tool_item_get_property       (GObject                   *object,
-							   guint                      prop_id,
-							   GValue                    *value,
-							   GParamSpec                *pspec);
+                                                           guint                      prop_id,
+                                                           const GValue              *value,
+                                                           GParamSpec                *pspec);
+static void     gtk_separator_tool_item_get_property      (GObject                   *object,
+                                                           guint                      prop_id,
+                                                           GValue                    *value,
+                                                           GParamSpec                *pspec);
 static void     gtk_separator_tool_item_size_request      (GtkWidget                 *widget,
-							   GtkRequisition            *requisition);
+                                                           GtkRequisition            *requisition);
+static void     gtk_separator_tool_item_size_allocate     (GtkWidget                 *widget,
+                                                           GtkAllocation             *allocation);
 static gboolean gtk_separator_tool_item_expose            (GtkWidget                 *widget,
-							   GdkEventExpose            *event);
+                                                           GdkEventExpose            *event);
 static void     gtk_separator_tool_item_add               (GtkContainer              *container,
-							   GtkWidget                 *child);
+                                                           GtkWidget                 *child);
 static gint     get_space_size                            (GtkToolItem               *tool_item);
+static void     gtk_separator_tool_item_realize           (GtkWidget                 *widget);
+static void     gtk_separator_tool_item_unrealize         (GtkWidget                 *widget);
+static void     gtk_separator_tool_item_map               (GtkWidget                 *widget);
+static void     gtk_separator_tool_item_unmap             (GtkWidget                 *widget);
+static gboolean gtk_separator_tool_item_button_event      (GtkWidget                 *widget,
+                                                           GdkEventButton            *event);
 
 
 G_DEFINE_TYPE (GtkSeparatorToolItem, gtk_separator_tool_item, GTK_TYPE_TOOL_ITEM)
@@ -86,8 +94,8 @@ get_space_size (GtkToolItem *tool_item)
   if (GTK_IS_TOOLBAR (parent))
     {
       gtk_widget_style_get (parent,
-			    "space-size", &space_size,
-			    NULL);
+                            "space-size", &space_size,
+                            NULL);
     }
   
   return space_size;
@@ -109,34 +117,45 @@ gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class)
   object_class->set_property = gtk_separator_tool_item_set_property;
   object_class->get_property = gtk_separator_tool_item_get_property;
   widget_class->size_request = gtk_separator_tool_item_size_request;
+  widget_class->size_allocate = gtk_separator_tool_item_size_allocate;
   widget_class->expose_event = gtk_separator_tool_item_expose;
+  widget_class->realize = gtk_separator_tool_item_realize;
+  widget_class->unrealize = gtk_separator_tool_item_unrealize;
+  widget_class->map = gtk_separator_tool_item_map;
+  widget_class->unmap = gtk_separator_tool_item_unmap;
+  widget_class->button_press_event = gtk_separator_tool_item_button_event;
+  widget_class->button_release_event = gtk_separator_tool_item_button_event;
+
   toolitem_class->create_menu_proxy = gtk_separator_tool_item_create_menu_proxy;
   
   container_class->add = gtk_separator_tool_item_add;
   
   g_object_class_install_property (object_class,
-				   PROP_DRAW,
-				   g_param_spec_boolean ("draw",
-							 P_("Draw"),
-							 P_("Whether the separator is drawn, or just blank"),
-							 TRUE,
-							 GTK_PARAM_READWRITE));
+                                   PROP_DRAW,
+                                   g_param_spec_boolean ("draw",
+                                                         P_("Draw"),
+                                                         P_("Whether the separator is drawn, or just blank"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
   
+
   g_type_class_add_private (object_class, sizeof (GtkSeparatorToolItemPrivate));
 }
 
 static void
-gtk_separator_tool_item_init (GtkSeparatorToolItem      *separator_item)
+gtk_separator_tool_item_init (GtkSeparatorToolItem *separator_item)
 {
   separator_item->priv = G_TYPE_INSTANCE_GET_PRIVATE (separator_item,
                                                       GTK_TYPE_SEPARATOR_TOOL_ITEM,
                                                       GtkSeparatorToolItemPrivate);
   separator_item->priv->draw = TRUE;
+
+  gtk_widget_set_has_window (GTK_WIDGET (separator_item), FALSE);
 }
 
 static void
 gtk_separator_tool_item_add (GtkContainer *container,
-			     GtkWidget    *child)
+                             GtkWidget    *child)
 {
   g_warning ("attempt to add a child to an GtkSeparatorToolItem");
 }
@@ -155,9 +174,9 @@ gtk_separator_tool_item_create_menu_proxy (GtkToolItem *item)
 
 static void
 gtk_separator_tool_item_set_property (GObject      *object,
-				      guint         prop_id,
-				      const GValue *value,
-				      GParamSpec   *pspec)
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
 {
   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
   
@@ -174,9 +193,9 @@ gtk_separator_tool_item_set_property (GObject      *object,
 
 static void
 gtk_separator_tool_item_get_property (GObject      *object,
-				      guint         prop_id,
-				      GValue       *value,
-				      GParamSpec   *pspec)
+                                      guint         prop_id,
+                                      GValue       *value,
+                                      GParamSpec   *pspec)
 {
   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
   
@@ -193,7 +212,7 @@ gtk_separator_tool_item_get_property (GObject      *object,
 
 static void
 gtk_separator_tool_item_size_request (GtkWidget      *widget,
-				      GtkRequisition *requisition)
+                                      GtkRequisition *requisition)
 {
   GtkToolItem *item = GTK_TOOL_ITEM (widget);
   GtkOrientation orientation = gtk_tool_item_get_orientation (item);
@@ -210,9 +229,119 @@ gtk_separator_tool_item_size_request (GtkWidget      *widget,
     }
 }
 
+static void
+gtk_separator_tool_item_size_allocate (GtkWidget     *widget,
+                                       GtkAllocation *allocation)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+
+  widget->allocation = *allocation;
+
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (priv->event_window,
+                            widget->allocation.x,
+                            widget->allocation.y,
+                            widget->allocation.width,
+                            widget->allocation.height);
+
+}
+
+static void
+gtk_separator_tool_item_realize (GtkWidget *widget)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  gtk_widget_set_realized (widget, TRUE);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_ONLY;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget) |
+                          GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK;
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  widget->window = gtk_widget_get_parent_window (widget);
+  g_object_ref (widget->window);
+
+  priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                                       &attributes, attributes_mask);
+  gdk_window_set_user_data (priv->event_window, widget);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+}
+
+static void
+gtk_separator_tool_item_unrealize (GtkWidget *widget)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+
+  if (priv->event_window)
+    {
+      gdk_window_set_user_data (priv->event_window, NULL);
+      gdk_window_destroy (priv->event_window);
+      priv->event_window = NULL;
+    }
+
+  GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unrealize (widget);
+}
+
+static void
+gtk_separator_tool_item_map (GtkWidget *widget)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+
+  GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->map (widget);
+
+  if (priv->event_window)
+    gdk_window_show (priv->event_window);
+}
+
+static void
+gtk_separator_tool_item_unmap (GtkWidget *widget)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+
+  if (priv->event_window)
+    gdk_window_hide (priv->event_window);
+
+  GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unmap (widget);
+}
+
+static gboolean
+gtk_separator_tool_item_button_event (GtkWidget      *widget,
+                                      GdkEventButton *event)
+{
+  GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
+  GtkSeparatorToolItemPrivate *priv = separator->priv;
+
+  /* We want window dragging to work on empty toolbar areas,
+   * so we only eat button events on visible separators
+   */
+  return priv->draw;
+}
+
+#define DEFAULT_SPACE_SIZE  12
+#define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
+#define SPACE_LINE_DIVISION 10.0
+#define SPACE_LINE_START    2.0
+#define SPACE_LINE_END      8.0
+
 static gboolean
 gtk_separator_tool_item_expose (GtkWidget      *widget,
-				GdkEventExpose *event)
+                                GdkEventExpose *event)
 {
   GtkToolbar *toolbar = NULL;
   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
@@ -221,12 +350,12 @@ gtk_separator_tool_item_expose (GtkWidget      *widget,
   if (priv->draw)
     {
       if (GTK_IS_TOOLBAR (widget->parent))
-	toolbar = GTK_TOOLBAR (widget->parent);
+        toolbar = GTK_TOOLBAR (widget->parent);
 
       _gtk_toolbar_paint_space_line (widget, toolbar,
-				     &(event->area), &widget->allocation);
+                                     &(event->area), &widget->allocation);
     }
-  
+
   return FALSE;
 }
 
@@ -245,7 +374,7 @@ gtk_separator_tool_item_new (void)
   GtkToolItem *self;
   
   self = g_object_new (GTK_TYPE_SEPARATOR_TOOL_ITEM,
-		       NULL);
+                       NULL);
   
   return self;
 }
@@ -282,7 +411,7 @@ gtk_separator_tool_item_get_draw (GtkSeparatorToolItem *item)
  */
 void
 gtk_separator_tool_item_set_draw (GtkSeparatorToolItem *item,
-				  gboolean              draw)
+                                  gboolean              draw)
 {
   g_return_if_fail (GTK_IS_SEPARATOR_TOOL_ITEM (item));
 
diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c
index a010ef9..d5a5afc 100644
--- a/gtk/gtktoolbar.c
+++ b/gtk/gtktoolbar.c
@@ -2630,17 +2630,41 @@ static gboolean
 gtk_toolbar_button_press (GtkWidget      *toolbar,
     			  GdkEventButton *event)
 {
+  GtkWidget *window;
+
   if (event->button == 3)
     {
       gboolean return_value;
-      
+
       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
 		     (int)event->x_root, (int)event->y_root, event->button,
 		     &return_value);
-      
+
       return return_value;
     }
-  
+
+  window = gtk_widget_get_toplevel (toolbar);
+
+  if (window)
+    {
+      gboolean window_drag = FALSE;
+
+      gtk_widget_style_get (toolbar,
+                            "window-dragging", &window_drag,
+                            NULL);
+
+      if (window_drag)
+        {
+          gtk_window_begin_move_drag (GTK_WINDOW (window),
+                                      event->button,
+                                      event->x_root,
+                                      event->y_root,
+                                      event->time);
+
+          return TRUE;
+        }
+    }
+
   return FALSE;
 }
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index b092857..f65b7ae 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -2491,6 +2491,13 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 							       0.0, 1.0, 0.04,
 							       GTK_PARAM_READABLE));
 
+  gtk_widget_class_install_style_property (klass,
+                                           g_param_spec_boolean ("window-dragging",
+                                                                 P_("Window dragging"),
+                                                                 P_("Whether windows can be dragged by clicking on empty areas"),
+                                                                 FALSE,
+                                                                 GTK_PARAM_READWRITE));
+
   /**
    * GtkWidget:draw-border:
    *



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