]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkhandlebox.c
Apply a cleanup patch by Kjartan Maraas (#341812)
[~andy/gtk] / gtk / gtkhandlebox.c
index ec7c22d5f7a2a2887507a7e9391406f5a0caaed8..fc1bd49c8001efeaecc1a4a994ffb8d85ad93021 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include <config.h>
 #include <stdlib.h>
 #include "gtkhandlebox.h"
+#include "gtkinvisible.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkwindow.h"
+#include "gtkprivate.h"
 #include "gtkintl.h"
+#include "gtkalias.h"
+
+typedef struct _GtkHandleBoxPrivate GtkHandleBoxPrivate;
+
+struct _GtkHandleBoxPrivate
+{
+  gint orig_x;
+  gint orig_y;
+};
 
 enum {
   PROP_0,
   PROP_SHADOW,
   PROP_SHADOW_TYPE,
   PROP_HANDLE_POSITION,
-  PROP_SNAP_EDGE
+  PROP_SNAP_EDGE,
+  PROP_SNAP_EDGE_SET
 };
 
 #define DRAG_HANDLE_SIZE 10
@@ -91,8 +104,6 @@ enum {
  *          <--------bin_window-------------------->
  */
 
-static void gtk_handle_box_class_init     (GtkHandleBoxClass *klass);
-static void gtk_handle_box_init           (GtkHandleBox      *handle_box);
 static void gtk_handle_box_set_property   (GObject      *object,
                                           guint         param_id,
                                           const GValue *value,
@@ -129,38 +140,12 @@ static gint gtk_handle_box_motion         (GtkWidget         *widget,
 static gint gtk_handle_box_delete_event   (GtkWidget         *widget,
                                           GdkEventAny       *event);
 static void gtk_handle_box_reattach       (GtkHandleBox      *hb);
+static void gtk_handle_box_end_drag       (GtkHandleBox      *hb,
+                                          guint32            time);
 
-
-static GtkBinClass *parent_class;
 static guint        handle_box_signals[SIGNAL_LAST] = { 0 };
 
-
-GType
-gtk_handle_box_get_type (void)
-{
-  static GType handle_box_type = 0;
-
-  if (!handle_box_type)
-    {
-      static const GTypeInfo handle_box_info =
-      {
-       sizeof (GtkHandleBoxClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-       (GClassInitFunc) gtk_handle_box_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       sizeof (GtkHandleBox),
-       0,              /* n_preallocs */
-       (GInstanceInitFunc) gtk_handle_box_init,
-      };
-
-      handle_box_type = g_type_register_static (GTK_TYPE_BIN, "GtkHandleBox",
-                                               &handle_box_info, 0);
-    }
-
-  return handle_box_type;
-}
+G_DEFINE_TYPE (GtkHandleBox, gtk_handle_box, GTK_TYPE_BIN)
 
 static void
 gtk_handle_box_class_init (GtkHandleBoxClass *class)
@@ -175,44 +160,50 @@ gtk_handle_box_class_init (GtkHandleBoxClass *class)
   widget_class = (GtkWidgetClass *) class;
   container_class = (GtkContainerClass *) class;
 
-  parent_class = g_type_class_peek_parent (class);
-
   gobject_class->set_property = gtk_handle_box_set_property;
   gobject_class->get_property = gtk_handle_box_get_property;
   
   g_object_class_install_property (gobject_class,
                                    PROP_SHADOW,
                                    g_param_spec_enum ("shadow", NULL,
-                                                      _("Deprecated property, use shadow_type instead"),
+                                                      P_("Deprecated property, use shadow_type instead"),
                                                      GTK_TYPE_SHADOW_TYPE,
                                                      GTK_SHADOW_ETCHED_OUT,
-                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+                                                      GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                    PROP_SHADOW_TYPE,
-                                   g_param_spec_enum ("shadow_type",
-                                                      _("Shadow type"),
-                                                      _("Appearance of the shadow that surrounds the container"),
+                                   g_param_spec_enum ("shadow-type",
+                                                      P_("Shadow type"),
+                                                      P_("Appearance of the shadow that surrounds the container"),
                                                      GTK_TYPE_SHADOW_TYPE,
                                                      GTK_SHADOW_ETCHED_OUT,
-                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+                                                      GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_HANDLE_POSITION,
-                                   g_param_spec_enum ("handle_position",
-                                                      _("Handle position"),
-                                                      _("Position of the handle relative to the child widget"),
+                                   g_param_spec_enum ("handle-position",
+                                                      P_("Handle position"),
+                                                      P_("Position of the handle relative to the child widget"),
                                                      GTK_TYPE_POSITION_TYPE,
                                                      GTK_POS_LEFT,
-                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+                                                      GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_SNAP_EDGE,
-                                   g_param_spec_enum ("snap_edge",
-                                                      _("Snap edge"),
-                                                      _("Side of the handlebox that's lined up with the docking point to dock the handlebox"),
+                                   g_param_spec_enum ("snap-edge",
+                                                      P_("Snap edge"),
+                                                      P_("Side of the handlebox that's lined up with the docking point to dock the handlebox"),
                                                      GTK_TYPE_POSITION_TYPE,
                                                      GTK_POS_TOP,
-                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
+                                                      GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SNAP_EDGE_SET,
+                                   g_param_spec_boolean ("snap-edge-set",
+                                                        P_("Snap edge set"),
+                                                        P_("Whether to use the value from the snap_edge property or a value derived from handle_position"),
+                                                        FALSE,
+                                                        GTK_PARAM_READWRITE));
 
   object_class->destroy = gtk_handle_box_destroy;
 
@@ -225,8 +216,6 @@ gtk_handle_box_class_init (GtkHandleBoxClass *class)
   widget_class->size_allocate = gtk_handle_box_size_allocate;
   widget_class->expose_event = gtk_handle_box_expose;
   widget_class->button_press_event = gtk_handle_box_button_changed;
-  widget_class->button_release_event = gtk_handle_box_button_changed;
-  widget_class->motion_notify_event = gtk_handle_box_motion;
   widget_class->delete_event = gtk_handle_box_delete_event;
 
   container_class->add = gtk_handle_box_add;
@@ -236,7 +225,7 @@ gtk_handle_box_class_init (GtkHandleBoxClass *class)
   class->child_detached = NULL;
 
   handle_box_signals[SIGNAL_CHILD_ATTACHED] =
-    g_signal_new ("child_attached",
+    g_signal_new (I_("child_attached"),
                  G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkHandleBoxClass, child_attached),
@@ -245,7 +234,7 @@ gtk_handle_box_class_init (GtkHandleBoxClass *class)
                  G_TYPE_NONE, 1,
                  GTK_TYPE_WIDGET);
   handle_box_signals[SIGNAL_CHILD_DETACHED] =
-    g_signal_new ("child_detached",
+    g_signal_new (I_("child_detached"),
                  G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkHandleBoxClass, child_detached),
@@ -253,6 +242,14 @@ gtk_handle_box_class_init (GtkHandleBoxClass *class)
                  _gtk_marshal_VOID__OBJECT,
                  G_TYPE_NONE, 1,
                  GTK_TYPE_WIDGET);
+
+  g_type_class_add_private (gobject_class, sizeof (GtkHandleBoxPrivate));    
+}
+
+static GtkHandleBoxPrivate *
+gtk_handle_box_get_private (GtkHandleBox *hb)
+{
+  return G_TYPE_INSTANCE_GET_PRIVATE (hb, GTK_TYPE_HANDLE_BOX, GtkHandleBoxPrivate);
 }
 
 static void
@@ -291,6 +288,10 @@ gtk_handle_box_set_property (GObject         *object,
     case PROP_SNAP_EDGE:
       gtk_handle_box_set_snap_edge (handle_box, g_value_get_enum (value));
       break;
+    case PROP_SNAP_EDGE_SET:
+      if (!g_value_get_boolean (value))
+       gtk_handle_box_set_snap_edge (handle_box, (GtkPositionType)-1);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -315,7 +316,12 @@ gtk_handle_box_get_property (GObject         *object,
       g_value_set_enum (value, handle_box->handle_position);
       break;
     case PROP_SNAP_EDGE:
-      g_value_set_enum (value, handle_box->snap_edge);
+      g_value_set_enum (value,
+                       (handle_box->snap_edge == -1 ?
+                        GTK_POS_TOP : handle_box->snap_edge));
+      break;
+    case PROP_SNAP_EDGE_SET:
+      g_value_set_boolean (value, handle_box->snap_edge != -1);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -332,8 +338,8 @@ gtk_handle_box_new (void)
 static void
 gtk_handle_box_destroy (GtkObject *object)
 {
-  if (GTK_OBJECT_CLASS (parent_class)->destroy)
-    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  if (GTK_OBJECT_CLASS (gtk_handle_box_parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (gtk_handle_box_parent_class)->destroy) (object);
 }
 
 static void
@@ -461,8 +467,8 @@ gtk_handle_box_unrealize (GtkWidget *widget)
   gdk_window_destroy (hb->float_window);
   hb->float_window = NULL;
 
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+  if (GTK_WIDGET_CLASS (gtk_handle_box_parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (gtk_handle_box_parent_class)->unrealize) (widget);
 }
 
 static void
@@ -534,7 +540,7 @@ gtk_handle_box_size_request (GtkWidget      *widget,
     }
 
   /* if our child is not visible, we still request its size, since we
-   * won't have any usefull hint for our size otherwise.
+   * won't have any useful hint for our size otherwise.
    */
   if (bin->child)
     gtk_widget_size_request (bin->child, &child_requisition);
@@ -616,11 +622,9 @@ gtk_handle_box_size_allocate (GtkWidget     *widget,
 
   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
     {
-      GtkWidget *child;
       GtkAllocation child_allocation;
       guint border_width;
 
-      child = bin->child;
       border_width = GTK_CONTAINER (widget)->border_width;
 
       child_allocation.x = border_width;
@@ -757,7 +761,7 @@ gtk_handle_box_set_shadow_type (GtkHandleBox  *handle_box,
   if ((GtkShadowType) handle_box->shadow_type != type)
     {
       handle_box->shadow_type = type;
-      g_object_notify (G_OBJECT (handle_box), "shadow_type");
+      g_object_notify (G_OBJECT (handle_box), "shadow-type");
       gtk_widget_queue_resize (GTK_WIDGET (handle_box));
     }
 }
@@ -788,7 +792,7 @@ gtk_handle_box_set_handle_position  (GtkHandleBox    *handle_box,
   if ((GtkPositionType) handle_box->handle_position != position)
     {
       handle_box->handle_position = position;
-      g_object_notify (G_OBJECT (handle_box), "handle_position");
+      g_object_notify (G_OBJECT (handle_box), "handle-position");
       gtk_widget_queue_resize (GTK_WIDGET (handle_box));
     }
 }
@@ -819,7 +823,11 @@ gtk_handle_box_set_snap_edge        (GtkHandleBox    *handle_box,
   if (handle_box->snap_edge != edge)
     {
       handle_box->snap_edge = edge;
-      g_object_notify (G_OBJECT (handle_box), "snap_edge");
+      
+      g_object_freeze_notify (G_OBJECT (handle_box));
+      g_object_notify (G_OBJECT (handle_box), "snap-edge");
+      g_object_notify (G_OBJECT (handle_box), "snap-edge-set");
+      g_object_thaw_notify (G_OBJECT (handle_box));
     }
 }
 
@@ -849,8 +857,7 @@ gtk_handle_box_paint (GtkWidget      *widget,
 {
   GtkBin *bin;
   GtkHandleBox *hb;
-  guint width;
-  guint height;
+  guint width, height;
   GdkRectangle rect;
   GdkRectangle dest;
   gint handle_position;
@@ -919,7 +926,7 @@ gtk_handle_box_paint (GtkWidget      *widget,
                         event ? &event->area : area);
 
   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
-    (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
+    (* GTK_WIDGET_CLASS (gtk_handle_box_parent_class)->expose_event) (widget, event);
 }
 
 static gint
@@ -944,6 +951,46 @@ gtk_handle_box_expose (GtkWidget      *widget,
   return FALSE;
 }
 
+static GtkWidget *
+gtk_handle_box_get_invisible (void)
+{
+  static GtkWidget *handle_box_invisible = NULL;
+
+  if (!handle_box_invisible)
+    {
+      handle_box_invisible = gtk_invisible_new ();
+      gtk_widget_show (handle_box_invisible);
+    }
+  
+  return handle_box_invisible;
+}
+
+static gboolean
+gtk_handle_box_grab_event (GtkWidget    *widget,
+                          GdkEvent     *event,
+                          GtkHandleBox *hb)
+{
+  switch (event->type)
+    {
+    case GDK_BUTTON_RELEASE:
+      if (hb->in_drag)         /* sanity check */
+       {
+         gtk_handle_box_end_drag (hb, event->button.time);
+         return TRUE;
+       }
+      break;
+
+    case GDK_MOTION_NOTIFY:
+      return gtk_handle_box_motion (GTK_WIDGET (hb), (GdkEventMotion *)event);
+      break;
+
+    default:
+      break;
+    }
+
+  return FALSE;
+}
+
 static gint
 gtk_handle_box_button_changed (GtkWidget      *widget,
                               GdkEventButton *event)
@@ -1000,14 +1047,19 @@ gtk_handle_box_button_changed (GtkWidget      *widget,
        {
          if (event->type == GDK_BUTTON_PRESS) /* Start a drag */
            {
+             GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
+             GtkWidget *invisible = gtk_handle_box_get_invisible ();
              gint desk_x, desk_y;
              gint root_x, root_y;
              gint width, height;
-             
+
              gdk_window_get_deskrelative_origin (hb->bin_window, &desk_x, &desk_y);
              gdk_window_get_origin (hb->bin_window, &root_x, &root_y);
              gdk_drawable_get_size (hb->bin_window, &width, &height);
-             
+                 
+             private->orig_x = event->x_root;
+             private->orig_y = event->y_root;
+                 
              hb->float_allocation.x = root_x - event->x_root;
              hb->float_allocation.y = root_y - event->y_root;
              hb->float_allocation.width = width;
@@ -1016,28 +1068,43 @@ gtk_handle_box_button_changed (GtkWidget      *widget,
              hb->deskoff_x = desk_x - root_x;
              hb->deskoff_y = desk_y - root_y;
              
-             gdk_window_get_origin (widget->window, &root_x, &root_y);
-             gdk_drawable_get_size (widget->window, &width, &height);
+             if (gdk_window_is_viewable (widget->window))
+               {
+                 gdk_window_get_origin (widget->window, &root_x, &root_y);
+                 gdk_drawable_get_size (widget->window, &width, &height);
              
-             hb->attach_allocation.x = root_x;
-             hb->attach_allocation.y = root_y;
-             hb->attach_allocation.width = width;
-             hb->attach_allocation.height = height;
-
+                 hb->attach_allocation.x = root_x;
+                 hb->attach_allocation.y = root_y;
+                 hb->attach_allocation.width = width;
+                 hb->attach_allocation.height = height;
+               }
+             else
+               {
+                 hb->attach_allocation.x = -1;
+                 hb->attach_allocation.y = -1;
+                 hb->attach_allocation.width = 0;
+                 hb->attach_allocation.height = 0;
+               }
              hb->in_drag = TRUE;
              fleur = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
                                                  GDK_FLEUR);
-             if (gdk_pointer_grab (widget->window,
+             if (gdk_pointer_grab (invisible->window,
                                    FALSE,
                                    (GDK_BUTTON1_MOTION_MASK |
                                     GDK_POINTER_MOTION_HINT_MASK |
                                     GDK_BUTTON_RELEASE_MASK),
                                    NULL,
                                    fleur,
-                                   GDK_CURRENT_TIME) != 0)
+                                   event->time) != 0)
                {
                  hb->in_drag = FALSE;
                }
+             else
+               {
+                 gtk_grab_add (invisible);
+                 g_signal_connect (invisible, "event",
+                                   G_CALLBACK (gtk_handle_box_grab_event), hb);
+               }
              
              gdk_cursor_unref (fleur);
              event_handled = TRUE;
@@ -1048,17 +1115,6 @@ gtk_handle_box_button_changed (GtkWidget      *widget,
            }
        }
     }
-  else if (event->type == GDK_BUTTON_RELEASE &&
-          hb->in_drag)
-    {
-      if (event->window != widget->window)
-       return FALSE;
-      
-      gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
-                                 GDK_CURRENT_TIME);
-      hb->in_drag = FALSE;
-      event_handled = TRUE;
-    }
   
   return event_handled;
 }
@@ -1067,19 +1123,16 @@ static gint
 gtk_handle_box_motion (GtkWidget      *widget,
                       GdkEventMotion *event)
 {
-  GtkHandleBox *hb;
+  GtkHandleBox *hb = GTK_HANDLE_BOX (widget);
   gint new_x, new_y;
   gint snap_edge;
   gboolean is_snapped = FALSE;
   gint handle_position;
+  GdkGeometry geometry;
+  GdkScreen *screen, *pointer_screen;
 
-  hb = GTK_HANDLE_BOX (widget);
   if (!hb->in_drag)
     return FALSE;
-
-  if (!hb->in_drag || (event->window != widget->window))
-    return FALSE;
-  
   handle_position = effective_handle_position (hb);
 
   /* Calculate the attachment point on the float, if the float
@@ -1087,8 +1140,18 @@ gtk_handle_box_motion (GtkWidget      *widget,
    */
   new_x = 0;
   new_y = 0;
-  gdk_window_get_pointer (gtk_widget_get_root_window (widget), 
-                         &new_x, &new_y, NULL);
+  screen = gtk_widget_get_screen (widget);
+  gdk_display_get_pointer (gdk_screen_get_display (screen),
+                          &pointer_screen, 
+                          &new_x, &new_y, NULL);
+  if (pointer_screen != screen)
+    {
+      GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
+
+      new_x = private->orig_x;
+      new_y = private->orig_y;
+    }
+  
   new_x += hb->float_allocation.x;
   new_y += hb->float_allocation.y;
 
@@ -1238,11 +1301,11 @@ gtk_handle_box_motion (GtkWidget      *widget,
          
          gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
          gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
-         gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
+         gdk_window_set_geometry_hints (hb->float_window, &geometry, GDK_HINT_POS);
          gdk_window_show (hb->float_window);
          hb->float_window_mapped = TRUE;
 #if    0
-         /* this extra move is neccessary if we use decorations, or our
+         /* this extra move is necessary if we use decorations, or our
           * window manager insists on decorations.
           */
          gdk_display_sync (gtk_widget_get_display (widget));
@@ -1267,14 +1330,14 @@ gtk_handle_box_add (GtkContainer *container,
                    GtkWidget    *widget)
 {
   gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
-  GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
+  GTK_CONTAINER_CLASS (gtk_handle_box_parent_class)->add (container, widget);
 }
 
 static void
 gtk_handle_box_remove (GtkContainer *container,
                       GtkWidget    *widget)
 {
-  GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
+  GTK_CONTAINER_CLASS (gtk_handle_box_parent_class)->remove (container, widget);
 
   gtk_handle_box_reattach (GTK_HANDLE_BOX (container));
 }
@@ -1318,11 +1381,25 @@ gtk_handle_box_reattach (GtkHandleBox *hb)
       hb->float_window_mapped = FALSE;
     }
   if (hb->in_drag)
-    {
-      gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (hb)),
-                                 GDK_CURRENT_TIME);
-      hb->in_drag = FALSE;
-    }
+    gtk_handle_box_end_drag (hb, GDK_CURRENT_TIME);
 
   gtk_widget_queue_resize (GTK_WIDGET (hb));
 }
+
+static void
+gtk_handle_box_end_drag (GtkHandleBox *hb,
+                        guint32       time)
+{
+  GtkWidget *invisible = gtk_handle_box_get_invisible ();
+               
+  hb->in_drag = FALSE;
+
+  gtk_grab_remove (invisible);
+  gdk_pointer_ungrab (time);
+  g_signal_handlers_disconnect_by_func (invisible,
+                                       G_CALLBACK (gtk_handle_box_grab_event),
+                                       hb);
+}
+
+#define __GTK_HANDLE_BOX_C__
+#include "gtkaliasdef.c"