]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkdnd.c
Use 'signed int' not 'gint' for signed bitfields. (#93020, Vitaly Tishkov)
[~andy/gtk] / gtk / gtkdnd.c
index 3e88358800ad2572bb52ef0943f95c003ceb5e47..2dc5daddff82b425bfedfdc63260a25f048ebdf7 100644 (file)
@@ -36,7 +36,6 @@
 #include "gtkstock.h"
 #include "gtkwindow.h"
 
-static GSList *drag_widgets = NULL;
 static GSList *source_widgets = NULL;
 
 typedef struct _GtkDragSourceSite GtkDragSourceSite;
@@ -95,6 +94,7 @@ struct _GtkDragSourceInfo
   gint               start_x, start_y; /* Initial position */
   gint               cur_x, cur_y;     /* Current Position */
 
+  guint32            grab_time;   /* timestamp for initial grab */
   GList             *selections;  /* selections we've claimed */
   
   GtkDragDestInfo   *proxy_dest;  /* Set if this is a proxy drag */
@@ -102,6 +102,8 @@ struct _GtkDragSourceInfo
   guint              drop_timeout;     /* Timeout for aborting drop */
   guint              destroy_icon : 1; /* If true, destroy icon_window
                                        */
+  guint              have_grab : 1;    /* Do we still have the pointer grab
+                                       */
 };
 
 struct _GtkDragDestSite 
@@ -180,8 +182,9 @@ static void          gtk_drag_get_event_actions (GdkEvent        *event,
                                                 GdkDragAction    actions,
                                                 GdkDragAction   *suggested_action,
                                                 GdkDragAction   *possible_actions);
-static GdkCursor *   gtk_drag_get_cursor         (GdkDragAction action);
-static GtkWidget    *gtk_drag_get_ipc_widget     (void);
+static GdkCursor *   gtk_drag_get_cursor         (GdkDisplay     *display,
+                                                 GdkDragAction   action);
+static GtkWidget    *gtk_drag_get_ipc_widget     (GdkScreen     *screen);
 static void          gtk_drag_release_ipc_widget (GtkWidget      *widget);
 
 static gboolean      gtk_drag_highlight_expose   (GtkWidget      *widget,
@@ -338,8 +341,8 @@ static const guchar action_none_mask_bits[] = {
 
 static struct {
   GdkDragAction action;
-  const char *bits;
-  const char *mask;
+  const guchar *bits;
+  const guchar *mask;
   GdkCursor    *cursor;
 } drag_cursors[] = {
   { GDK_ACTION_DEFAULT, 0 },
@@ -366,20 +369,25 @@ static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[
  *************************************************************/
 
 static GtkWidget *
-gtk_drag_get_ipc_widget (void)
+gtk_drag_get_ipc_widget (GdkScreen *screen)
 {
   GtkWidget *result;
+  GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), 
+                                           "gtk-dnd-ipc-widgets");
   
   if (drag_widgets)
     {
       GSList *tmp = drag_widgets;
       result = drag_widgets->data;
       drag_widgets = drag_widgets->next;
+      g_object_set_data (G_OBJECT (screen),
+                        "gtk-dnd-ipc-widgets",
+                        drag_widgets);
       g_slist_free_1 (tmp);
     }
   else
     {
-      result = gtk_invisible_new ();
+      result = gtk_invisible_new_for_screen (screen);
       gtk_widget_show (result);
     }
 
@@ -397,7 +405,13 @@ gtk_drag_get_ipc_widget (void)
 static void
 gtk_drag_release_ipc_widget (GtkWidget *widget)
 {
+  GdkScreen *screen = gtk_widget_get_screen (widget);
+  GSList *drag_widgets = g_object_get_data (G_OBJECT (screen),
+                                           "gtk-dnd-ipc-widgets");
   drag_widgets = g_slist_prepend (drag_widgets, widget);
+  g_object_set_data (G_OBJECT (screen),
+                    "gtk-dnd-ipc-widgets",
+                    drag_widgets);
 }
 
 static guint32
@@ -538,30 +552,36 @@ gtk_drag_get_event_actions (GdkEvent *event,
 }
 
 static GdkCursor *
-gtk_drag_get_cursor (GdkDragAction action)
+gtk_drag_get_cursor (GdkDisplay   *display,
+                    GdkDragAction action)
 {
   gint i;
   
   for (i = 0 ; i < n_drag_cursors - 1; i++)
     if (drag_cursors[i].action == action)
       break;
+  if (drag_cursors[i].cursor != NULL)
+    {
+      if (display != gdk_cursor_get_display (drag_cursors[i].cursor))
+       {
+         gdk_cursor_unref (drag_cursors[i].cursor);
+         drag_cursors[i].cursor = NULL;
+       }
+    }
 
   if (drag_cursors[i].cursor == NULL)
     {
-      GdkColor fg, bg;
+      GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
+      GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 };
+      GdkScreen *screen = gdk_display_get_default_screen (display);
+      GdkWindow *window = gdk_screen_get_root_window (screen);
 
       GdkPixmap *pixmap = 
-       gdk_bitmap_create_from_data (NULL, 
-                                    drag_cursors[i].bits,
-                                    CURSOR_WIDTH, CURSOR_HEIGHT);
+       gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].bits, CURSOR_WIDTH, CURSOR_HEIGHT);
+
       GdkPixmap *mask = 
-       gdk_bitmap_create_from_data (NULL, 
-                                    drag_cursors[i].mask,
-                                    CURSOR_WIDTH, CURSOR_HEIGHT);
+       gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].mask, CURSOR_WIDTH, CURSOR_HEIGHT);
 
-      gdk_color_white (gdk_colormap_get_system (), &bg);
-      gdk_color_black (gdk_colormap_get_system (), &fg);
-      
       drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
 
       gdk_pixmap_unref (pixmap);
@@ -597,7 +617,7 @@ gtk_drag_get_data (GtkWidget      *widget,
   g_return_if_fail (widget != NULL);
   g_return_if_fail (context != NULL);
 
-  selection_widget = gtk_drag_get_ipc_widget ();
+  selection_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
 
   gdk_drag_context_ref (context);
   gtk_widget_ref (widget);
@@ -684,7 +704,7 @@ gtk_drag_finish (GdkDragContext *context,
 
   if (target != GDK_NONE)
     {
-      GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
+      GtkWidget *selection_widget = gtk_drag_get_ipc_widget (gdk_drawable_get_screen (context->source_window));
 
       gdk_drag_context_ref (context);
       
@@ -844,9 +864,9 @@ gtk_drag_dest_set   (GtkWidget            *widget,
     site->target_list = gtk_target_list_new (targets, n_targets);
   else
     site->target_list = NULL;
-
   site->actions = actions;
   site->do_proxy = FALSE;
+  site->proxy_window = NULL;
 
   gtk_drag_dest_set_internal (widget, site);
 }
@@ -1229,6 +1249,8 @@ gtk_drag_find_widget (GtkWidget       *widget,
                      GtkDragFindData *data)
 {
   GtkAllocation new_allocation;
+  gint allocation_to_window_x = 0;
+  gint allocation_to_window_y = 0;
   gint x_offset = 0;
   gint y_offset = 0;
 
@@ -1253,38 +1275,36 @@ gtk_drag_find_widget (GtkWidget       *widget,
 
   if (widget->parent)
     {
-      gint tx, ty, twidth, theight;
+      gint tx, ty;
       GdkWindow *window = widget->window;
 
-      /* Correct for the fact that the allocation is relative
-       * to the parent window for window widgets, not to widget->window.
+      /* Compute the offset from allocation-relative to
+       * window-relative coordinates.
        */
+      allocation_to_window_x = widget->allocation.x;
+      allocation_to_window_y = widget->allocation.y;
+
       if (!GTK_WIDGET_NO_WINDOW (widget))
        {
+         /* The allocation is relative to the parent window for
+          * window widgets, not to widget->window.
+          */
           gdk_window_get_position (window, &tx, &ty);
          
-          new_allocation.x -= tx;
-         new_allocation.y -= ty;
+          allocation_to_window_x -= tx;
+          allocation_to_window_y -= ty;
        }
 
+      new_allocation.x = 0 + allocation_to_window_x;
+      new_allocation.y = 0 + allocation_to_window_y;
+      
       while (window && window != widget->parent->window)
-       {       
-         gdk_window_get_size (window, &twidth, &theight);
+       {
+         GdkRectangle window_rect = { 0, 0, 0, 0 };
+         
+         gdk_window_get_size (window, &window_rect.width, &window_rect.height);
 
-         if (new_allocation.x < 0)
-           {
-             new_allocation.width += new_allocation.x;
-             new_allocation.x = 0;
-           }
-         if (new_allocation.y < 0)
-           {
-             new_allocation.height += new_allocation.y;
-             new_allocation.y = 0;
-           }
-         if (new_allocation.x + new_allocation.width > twidth)
-           new_allocation.width = twidth - new_allocation.x;
-         if (new_allocation.y + new_allocation.height > theight)
-           new_allocation.height = theight - new_allocation.y;
+         gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation);
 
          gdk_window_get_position (window, &tx, &ty);
          new_allocation.x += tx;
@@ -1342,8 +1362,8 @@ gtk_drag_find_widget (GtkWidget       *widget,
        {
          data->found = data->callback (widget,
                                        data->context,
-                                       data->x - new_allocation.x - x_offset,
-                                       data->y - new_allocation.y - y_offset,
+                                       data->x - x_offset - allocation_to_window_x,
+                                       data->y - y_offset - allocation_to_window_y,
                                        data->time);
          /* If so, send a "drag_leave" to the last widget */
          if (data->found)
@@ -1375,7 +1395,7 @@ gtk_drag_proxy_begin (GtkWidget       *widget,
       dest_info->proxy_source = NULL;
     }
   
-  ipc_widget = gtk_drag_get_ipc_widget ();
+  ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
   context = gdk_drag_begin (ipc_widget->window,
                            dest_info->context->targets);
 
@@ -1488,6 +1508,9 @@ gtk_drag_dest_site_destroy (gpointer data)
 {
   GtkDragDestSite *site = data;
 
+  if (site->proxy_window)
+    g_object_unref (site->proxy_window);
+    
   if (site->target_list)
     gtk_target_list_unref (site->target_list);
 
@@ -1786,7 +1809,7 @@ gtk_drag_begin (GtkWidget         *widget,
       tmp_list = tmp_list->prev;
     }
 
-  ipc_widget = gtk_drag_get_ipc_widget ();
+  ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
   source_widgets = g_slist_prepend (source_widgets, ipc_widget);
 
   context = gdk_drag_begin (ipc_widget->window, targets);
@@ -1816,7 +1839,7 @@ gtk_drag_begin (GtkWidget         *widget,
   gtk_drag_get_event_actions (event, info->button, actions,
                              &suggested_action, &possible_actions);
 
-  info->cursor = gtk_drag_get_cursor (suggested_action);
+  info->cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
 
   /* Set cur_x, cur_y here so if the "drag_begin" signal shows
    * the drag icon, it will be in the right place
@@ -1828,11 +1851,8 @@ gtk_drag_begin (GtkWidget         *widget,
     }
   else 
     {
-      gint x, y;
-      gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
-
-      info->cur_x = x;
-      info->cur_y = y;
+      gdk_window_get_pointer (gtk_widget_get_root_window (widget),
+                             &info->cur_x, &info->cur_y, NULL);
     }
 
   gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
@@ -1879,6 +1899,9 @@ gtk_drag_begin (GtkWidget         *widget,
        }
     }
 
+  info->have_grab = TRUE;
+  info->grab_time = time;
+
   return info->context;
 }
 
@@ -2163,13 +2186,19 @@ set_icon_stock_pixbuf (GdkDragContext    *context,
   gint width, height;
   GdkPixmap *pixmap;
   GdkPixmap *mask;
-  
+  GdkScreen *screen;
+  GdkColormap *colormap;
+
   g_return_if_fail (context != NULL);
   g_return_if_fail (pixbuf != NULL || stock_id != NULL);
   g_return_if_fail (pixbuf == NULL || stock_id == NULL);
-
-  gtk_widget_push_colormap (gdk_rgb_get_colormap ());
+  
+  screen = gdk_drawable_get_screen (context->source_window);
+  colormap = gdk_screen_get_rgb_colormap (screen);
+  
+  gtk_widget_push_colormap (colormap);
   window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (window), screen);
   gtk_widget_pop_colormap ();
 
   gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
@@ -2197,7 +2226,7 @@ set_icon_stock_pixbuf (GdkDragContext    *context,
                        gdk_pixbuf_get_height (pixbuf));
   gtk_widget_realize (window);
 
-  gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &mask, 128);
+  gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, colormap, &pixmap, &mask, 128);
   
   gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
   
@@ -2291,6 +2320,7 @@ gtk_drag_set_icon_pixmap (GdkDragContext    *context,
   gtk_widget_push_colormap (colormap);
 
   window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (window), gdk_drawable_get_screen (context->source_window));
   gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
   gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
 
@@ -2342,7 +2372,7 @@ gtk_drag_set_icon_default (GdkDragContext    *context)
  * Changes the default drag icon. GTK+ retains references for the
  * arguments, and will release them when they are no longer needed.
  * This function is obsolete. The default icon should now be changed
- * via the stock system by changing the stock pixbuf for %GTK_STOCK_DND.
+ * via the stock system by changing the stock pixbuf for #GTK_STOCK_DND.
  **/
 void 
 gtk_drag_set_default_icon (GdkColormap   *colormap,
@@ -2431,9 +2461,10 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
                  }
              }
          }
-       else
+       else if (info->have_grab)
          {
-           cursor = gtk_drag_get_cursor (event->dnd.context->action);
+           cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget),
+                                         event->dnd.context->action);
            if (info->cursor != cursor)
              {
                gdk_pointer_grab (widget->window, FALSE,
@@ -2441,7 +2472,7 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
                                  GDK_POINTER_MOTION_HINT_MASK |
                                  GDK_BUTTON_RELEASE_MASK,
                                  NULL,
-                                 cursor, event->dnd.time);
+                                 cursor, info->grab_time);
                info->cursor = cursor;
              }
            
@@ -2488,7 +2519,10 @@ gtk_drag_source_check_selection (GtkDragSourceInfo *info,
       tmp_list = tmp_list->next;
     }
 
-  gtk_selection_owner_set (info->ipc_widget, selection, time);
+  gtk_selection_owner_set_for_display (gtk_widget_get_display (info->widget),
+                                      info->ipc_widget,
+                                      selection,
+                                      time);
   info->selections = g_list_prepend (info->selections,
                                     GUINT_TO_POINTER (selection));
 
@@ -2580,12 +2614,15 @@ static void
 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
                                    guint32            time)
 {
+  GdkDisplay *display = gtk_widget_get_display (info->widget);
   GList *tmp_list = info->selections;
+  
   while (tmp_list)
     {
       GdkAtom selection = GDK_POINTER_TO_ATOM (tmp_list->data);
-      if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
-       gtk_selection_owner_set (NULL, selection, time);
+      if (gdk_selection_owner_get_for_display (display, selection) == info->ipc_widget->window)
+       gtk_selection_owner_set_for_display (display, NULL, selection, time);
+
       tmp_list = tmp_list->next;
     }
 
@@ -2988,10 +3025,12 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
 {
   GdkEvent send_event;
   GtkWidget *source_widget = info->widget;
+  GdkDisplay *display = gtk_widget_get_display (source_widget);
 
-  gdk_pointer_ungrab (time);
-  gdk_keyboard_ungrab (time);
-
+  info->have_grab = FALSE;
+  
+  gdk_display_pointer_ungrab (display, time);
+  gdk_display_keyboard_ungrab (display, time);
   gtk_grab_remove (info->ipc_widget);
 
   gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), 
@@ -3000,6 +3039,9 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
   gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), 
                                 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
                                 info);
+  gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), 
+                                GTK_SIGNAL_FUNC (gtk_drag_key_cb),
+                                info);
 
   /* Send on a release pair to the the original 
    * widget to convince it to release its grab. We need to
@@ -3009,7 +3051,7 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
    */
 
   send_event.button.type = GDK_BUTTON_RELEASE;
-  send_event.button.window = GDK_ROOT_PARENT ();
+  send_event.button.window = gtk_widget_get_root_window (source_widget);
   send_event.button.send_event = TRUE;
   send_event.button.time = time;
   send_event.button.x = 0;
@@ -3017,7 +3059,7 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
   send_event.button.axes = NULL;
   send_event.button.state = 0;
   send_event.button.button = info->button;
-  send_event.button.device = gdk_device_get_core_pointer ();
+  send_event.button.device = gdk_display_get_core_pointer (display);
   send_event.button.x_root = 0;
   send_event.button.y_root = 0;
 
@@ -3042,7 +3084,9 @@ gtk_drag_motion_cb (GtkWidget      *widget,
 
   if (event->is_hint)
     {
-      gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
+      GdkWindow *root_window = gtk_widget_get_root_window (widget);
+      
+      gdk_window_get_pointer (root_window, &x_root, &y_root, NULL);
       event->x_root = x_root;
       event->y_root = y_root;
     }
@@ -3067,6 +3111,7 @@ gtk_drag_key_cb (GtkWidget         *widget,
 {
   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
   GdkModifierType state;
+  GdkWindow *root_window;
   
   if (event->type == GDK_KEY_PRESS)
     {
@@ -3086,7 +3131,8 @@ gtk_drag_key_cb (GtkWidget         *widget,
    * to query it here. We could use XGetModifierMapping, but
    * that would be overkill.
    */
-  gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
+  root_window = gtk_widget_get_root_window (widget);
+  gdk_window_get_pointer (root_window, NULL, NULL, &state);
 
   event->state = state;
   gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
@@ -3154,11 +3200,11 @@ gtk_drag_abort_timeout (gpointer data)
  * @current_x: current X coordinate
  * @current_y: current Y coordinate
  * 
- * Checks to see if a mouse drag starting at (start_x, start_y) and ending
- * at (current_x, current_y) has passed the GTK drag threshhold, and thus
+ * Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
+ * at (@current_x, @current_y) has passed the GTK+ drag threshhold, and thus
  * should trigger the beginning of a drag-and-drop operation.
  *
- * Return Value: If the drag threshold has been passed.
+ * Return Value: %TRUE if the drag threshold has been passed.
  **/
 gboolean
 gtk_drag_check_threshold (GtkWidget *widget,