diff options
Diffstat (limited to 'gtk/gtkdnd.c')
-rw-r--r-- | gtk/gtkdnd.c | 464 |
1 files changed, 309 insertions, 155 deletions
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 5d14a4e8d..bff1b76b4 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -39,9 +39,11 @@ #include "gdk/gdkkeysyms.h" #include "gtkdnd.h" +#include "gtkimage.h" #include "gtkinvisible.h" #include "gtkmain.h" #include "gtksignal.h" +#include "gtkstock.h" #include "gtkwindow.h" static GSList *drag_widgets = NULL; @@ -67,9 +69,17 @@ struct _GtkDragSourceSite GdkModifierType start_button_mask; GtkTargetList *target_list; /* Targets for drag data */ GdkDragAction actions; /* Possible actions */ + + /* Drag icon */ + GtkImageType icon_type; + union + { + GtkImagePixmapData pixmap; + GtkImagePixbufData pixbuf; + GtkImageStockData stock; + } icon_data; + GdkColormap *colormap; /* Colormap for drag icon */ - GdkPixmap *pixmap; /* Icon for drag data */ - GdkBitmap *mask; /* Stored button press information to detect drag beginning */ gint state; @@ -349,45 +359,6 @@ static struct { static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]); -/* XPM */ -static const char *drag_default_xpm[] = { -"32 32 3 1", -" c None", -". c #000000", -"+ c #FFFFFF", -" ", -" ", -" .. ", -" ..+. ", -" ..++.. ", -" ...++++. ", -" ...++++++.. ", -" ...+++++++++. ", -" ...+++++++++++.. ", -" ..+.++++++++++++.. ", -" .++.++++++++++++.. ", -" .+++.++++++++++++.. ", -" .++++.++++++++++++. ", -" .+++.+++++++++++++.. ", -" .++.+++++++++++++++.. ", -" .+.+++++++++++++++++.. ", -" ..+++++++++++++++++++.. ", -" ..++++++++++++++++++++. ", -" .++++++++++++++++++++.. ", -" ..+++++++++++++++++.. ", -" .++++++++++++++++.. ", -" ..+++++++++++++... ", -" .++++++++++++.. ", -" ..+++++++++.. ", -" .++++++++.. ", -" ..++++++.. ", -" .+++++.. ", -" .++.. ", -" ... ", -" .. ", -" ", -" "}; - /********************* * Utility functions * *********************/ @@ -983,7 +954,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, } if (target_list) - gtk_target_list_ref (site->target_list); + gtk_target_list_ref (target_list); if (site->target_list) gtk_target_list_unref (site->target_list); @@ -993,7 +964,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, /************************************************************* - * gtk_drag_dest_handle_event: + * _gtk_drag_dest_handle_event: * Called from widget event handling code on Drag events * for destinations. * @@ -1004,7 +975,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, *************************************************************/ void -gtk_drag_dest_handle_event (GtkWidget *toplevel, +_gtk_drag_dest_handle_event (GtkWidget *toplevel, GdkEvent *event) { GtkDragDestInfo *info; @@ -1894,6 +1865,8 @@ gtk_drag_source_set (GtkWidget *widget, else { site = g_new0 (GtkDragSourceSite, 1); + + site->icon_type = GTK_IMAGE_EMPTY; gtk_signal_connect (GTK_OBJECT (widget), "button_press_event", GTK_SIGNAL_FUNC (gtk_drag_source_event_cb), @@ -1942,16 +1915,48 @@ gtk_drag_source_unset (GtkWidget *widget) } } -/************************************************************* - * gtk_drag_source_set_icon: - * Set an icon for drags from this source. - * arguments: - * colormap: Colormap for this icon - * pixmap: - * mask - * results: - *************************************************************/ +static void +gtk_drag_source_unset_icon (GtkDragSourceSite *site) +{ + switch (site->icon_type) + { + case GTK_IMAGE_EMPTY: + break; + case GTK_IMAGE_PIXMAP: + if (site->icon_data.pixmap.pixmap) + gdk_pixmap_unref (site->icon_data.pixmap.pixmap); + if (site->icon_data.pixmap.mask) + gdk_pixmap_unref (site->icon_data.pixmap.mask); + break; + case GTK_IMAGE_PIXBUF: + g_object_unref (G_OBJECT (site->icon_data.pixbuf.pixbuf)); + break; + case GTK_IMAGE_STOCK: + g_free (G_OBJECT (site->icon_data.stock.stock_id)); + break; + default: + g_assert_not_reached(); + break; + } + site->icon_type = GTK_IMAGE_EMPTY; + + if (site->colormap) + gdk_colormap_unref (site->colormap); + site->colormap = NULL; +} +/** + * gtk_drag_source_set_icon: + * @widget: a #GtkWidget + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for an image. + * + * Sets the icon that will be used for drags from a particular widget + * from a pixmap/mask. GTK+ retains a reference count for the + * arguments, and will release them when they are no longer needed. + * Use gtk_drag_source_set_icon_pixbuf() instead. + **/ void gtk_drag_source_set_icon (GtkWidget *widget, GdkColormap *colormap, @@ -1961,40 +1966,81 @@ gtk_drag_source_set_icon (GtkWidget *widget, GtkDragSourceSite *site; g_return_if_fail (widget != NULL); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + g_return_if_fail (GDK_IS_PIXMAP (pixmap)); + g_return_if_fail (!mask || GDK_IS_PIXMAP (mask)); site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); g_return_if_fail (site != NULL); - if (site->colormap) - gdk_colormap_unref (site->colormap); - if (site->pixmap) - gdk_pixmap_unref (site->pixmap); - if (site->mask) - gdk_pixmap_unref (site->mask); + gdk_colormap_ref (colormap); + gdk_pixmap_ref (pixmap); + if (mask) + gdk_pixmap_ref (mask); + gtk_drag_source_unset_icon (site); + + site->icon_type = GTK_IMAGE_PIXMAP; + + site->icon_data.pixmap.pixmap = pixmap; + site->icon_data.pixmap.mask = mask; site->colormap = colormap; - if (colormap) - gdk_colormap_ref (colormap); +} + +/** + * gtk_drag_source_set_icon_pixbuf: + * @widget: a #GtkWidget + * @pixbuf: the #GdkPixbuf for the drag icon + * + * Sets the icon that will be used for drags from a particular widget + * from a #GdkPixbuf. GTK+ retains a reference count @pixbuf. + * and will release it when it is no longer needed. + **/ +void +gtk_drag_source_set_icon_pixbuf (GtkWidget *widget, + GdkPixbuf *pixbuf) +{ + GtkDragSourceSite *site; - site->pixmap = pixmap; - if (pixmap) - gdk_pixmap_ref (pixmap); + g_return_if_fail (widget != NULL); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); - site->mask = mask; - if (mask) - gdk_pixmap_ref (mask); + site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); + g_return_if_fail (site != NULL); + + gdk_pixbuf_ref (pixbuf); + + gtk_drag_source_unset_icon (site); + + site->icon_type = GTK_IMAGE_PIXBUF; + site->icon_data.pixbuf.pixbuf = pixbuf; } -/************************************************************* - * gtk_drag_set_icon_window: - * Set a widget as the icon for a drag. - * arguments: - * context: - * widget: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ +/** + * gtk_drag_source_set_icon_stock: + * @widget: a #GtkWidget + * @stock: the ID of the stock icon to use.. + * @size: size at which to render the stock icon + * + * Sets the icon that will be used for drags from a particular to + * a stock icon. + **/ +void +gtk_drag_source_set_icon_stock (GtkWidget *widget, + const gchar *stock_id) +{ + GtkDragSourceSite *site; + + g_return_if_fail (widget != NULL); + g_return_if_fail (stock_id != NULL); + + site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); + g_return_if_fail (site != NULL); + + gtk_drag_source_unset_icon (site); + + site->icon_data.stock.stock_id = g_strdup (stock_id); +} static void gtk_drag_set_icon_window (GdkDragContext *context, @@ -2028,17 +2074,19 @@ gtk_drag_set_icon_window (GdkDragContext *context, info->destroy_icon = destroy_on_release; } -/************************************************************* +/** * gtk_drag_set_icon_widget: - * Set a widget as the icon for a drag. - * arguments: - * context: - * widget: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ - + * @context: the context for a drag. (This must be called + with a context for the source side of a drag) + * @widget: a toplevel window to use as an icon. + * @hot_x: the X offset within @widget of the hotspot. + * @hot_y: the Y offset within @widget of the hotspot. + * + * Changes the icon for a widget to a given widget. GTK+ + * will not destroy the icon, so if you don't want + * it to persist, you should connect to the "drag_end" + * signal and destroy it yourself. + **/ void gtk_drag_set_icon_widget (GdkDragContext *context, GtkWidget *widget, @@ -2051,19 +2099,123 @@ gtk_drag_set_icon_widget (GdkDragContext *context, gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE); } -/************************************************************* - * gtk_drag_set_icon_pixmap: - * Set a widget as the icon for a drag. - * arguments: - * context: - * colormap: Colormap for the icon window. - * pixmap: - * mask: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ +static void +set_icon_stock_pixbuf (GdkDragContext *context, + const gchar *stock_id, + GdkPixbuf *pixbuf, + gint hot_x, + gint hot_y) +{ + GtkWidget *window; + gint width, height; + GdkPixmap *pixmap; + GdkPixmap *mask; + + 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 ()); + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_pop_colormap (); + + gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); + + if (stock_id) + { + pixbuf = gtk_widget_render_icon (window, stock_id, + GTK_ICON_SIZE_DND, NULL); + + if (!pixbuf) + { + g_warning ("Cannot load drag icon from stock_id %s", stock_id); + gtk_widget_destroy (window); + return; + } + + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_width (pixbuf); + + gtk_widget_set_usize (window, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + gtk_widget_realize (window); + + gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &mask, 128); + + gdk_window_set_back_pixmap (window->window, pixmap, FALSE); + + if (mask) + gtk_widget_shape_combine_mask (window, mask, 0, 0); + + g_object_unref (G_OBJECT (pixmap)); + g_object_unref (G_OBJECT (mask)); + + gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE); +} + +/** + * gtk_drag_set_icon_pixbuf: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @pixbuf: the #GdkPixbuf to use as the drag icon. + * @hot_x: the X offset within @widget of the hotspot. + * @hot_y: the Y offset within @widget of the hotspot. + * + * Sets @pixbuf as the icon for a given drag. + **/ +void +gtk_drag_set_icon_pixbuf (GdkDragContext *context, + GdkPixbuf *pixbuf, + gint hot_x, + gint hot_y) +{ + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y); +} +/** + * gtk_drag_set_icon_pixbuf: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @stock: the ID of the stock icon to use for the drag. + * @hot_x: the X offset within the icon of the hotspot. + * @hot_y: the Y offset within the icon of the hotspot. + * + * Sets the the icon for a given drag from a stock ID. + **/ +void +gtk_drag_set_icon_stock (GdkDragContext *context, + const gchar *stock_id, + gint hot_x, + gint hot_y) +{ + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (stock_id != NULL); + + set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y); +} + +/** + * gtk_drag_set_icon_pixmap: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for the icon + * @hot_x: the X offset within @pixmap of the hotspot. + * @hot_y: the Y offset within @pixmap of the hotspot. + * + * Sets @pixmap as the icon for a given drag. GTK+ retains a + * reference count for the arguments, and will release them when + * they are no longer needed. In general, gtk_drag_set_icon_pixbuf() + * will be more convenient to use. + **/ void gtk_drag_set_icon_pixmap (GdkDragContext *context, GdkColormap *colormap, @@ -2100,51 +2252,43 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE); } -/************************************************************* +/** * gtk_drag_set_icon_default: - * Set the icon for a drag to the default icon. - * arguments: - * context: - * results: - *************************************************************/ - + * @context: the context for a drag. (This must be called + with a context for the source side of a drag) + * + * Sets the icon for a particular drag to the default + * icon. + **/ void gtk_drag_set_icon_default (GdkDragContext *context) { g_return_if_fail (context != NULL); if (!default_icon_pixmap) - { - default_icon_colormap = gdk_colormap_get_system (); - default_icon_pixmap = - gdk_pixmap_colormap_create_from_xpm_d (NULL, - default_icon_colormap, - &default_icon_mask, - NULL, (gchar **)drag_default_xpm); - default_icon_hot_x = -2; - default_icon_hot_y = -2; - } - - gtk_drag_set_icon_pixmap (context, - default_icon_colormap, - default_icon_pixmap, - default_icon_mask, - default_icon_hot_x, - default_icon_hot_y); + gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2); + else + gtk_drag_set_icon_pixmap (context, + default_icon_colormap, + default_icon_pixmap, + default_icon_mask, + default_icon_hot_x, + default_icon_hot_y); } -/************************************************************* +/** * gtk_drag_set_default_icon: - * Set a default icon for all drags as a pixmap. - * arguments: - * colormap: Colormap for the icon window. - * pixmap: - * mask: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ - + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for an image. + * @hot_x: The X offset within @widget of the hotspot. + * @hot_y: The Y offset within @widget of the hotspot. + * + * Changes the default drag icon. GTK+ retains a reference count 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. + **/ void gtk_drag_set_default_icon (GdkColormap *colormap, GdkPixmap *pixmap, @@ -2178,7 +2322,7 @@ gtk_drag_set_default_icon (GdkColormap *colormap, /************************************************************* - * gtk_drag_source_handle_event: + * _gtk_drag_source_handle_event: * Called from widget event handling code on Drag events * for drag sources. * @@ -2189,8 +2333,8 @@ gtk_drag_set_default_icon (GdkColormap *colormap, *************************************************************/ void -gtk_drag_source_handle_event (GtkWidget *widget, - GdkEvent *event) +_gtk_drag_source_handle_event (GtkWidget *widget, + GdkEvent *event) { GtkDragSourceInfo *info; GdkDragContext *context; @@ -2477,16 +2621,12 @@ gtk_drag_source_event_cb (GtkWidget *widget, site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1)); site->x = event->button.x; site->y = event->button.y; - retval = TRUE; } break; case GDK_BUTTON_RELEASE: if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) - { - site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); - retval = TRUE; - } + site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); break; case GDK_MOTION_NOTIFY: @@ -2518,13 +2658,32 @@ gtk_drag_source_event_cb (GtkWidget *widget, if (!info->icon_window) { - if (site->pixmap) - gtk_drag_set_icon_pixmap (context, - site->colormap, - site->pixmap, - site->mask, -2, -2); - else - gtk_drag_set_icon_default (context); + switch (site->icon_type) + { + case GTK_IMAGE_EMPTY: + gtk_drag_set_icon_default (context); + break; + case GTK_IMAGE_PIXMAP: + gtk_drag_set_icon_pixmap (context, + site->colormap, + site->icon_data.pixmap.pixmap, + site->icon_data.pixmap.mask, + -2, -2); + break; + case GTK_IMAGE_PIXBUF: + gtk_drag_set_icon_pixbuf (context, + site->icon_data.pixbuf.pixbuf, + -2, -2); + break; + case GTK_IMAGE_STOCK: + gtk_drag_set_icon_stock (context, + site->icon_data.stock.stock_id, + -2, -2); + break; + default: + g_assert_not_reached(); + break; + } } retval = TRUE; @@ -2547,12 +2706,7 @@ gtk_drag_source_site_destroy (gpointer data) if (site->target_list) gtk_target_list_unref (site->target_list); - if (site->pixmap) - gdk_pixmap_unref (site->pixmap); - - if (site->mask) - gdk_pixmap_unref (site->mask); - + gtk_drag_source_unset_icon (site); g_free (site); } |