X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkdnd-quartz.c;h=57601055703f225ccc7b96fdb4f321e7752bdbdc;hb=e1edc998a2e9c557030d207533932b3120e13fe5;hp=8284eea94b8bb611b799ae6d8b7b5e5338ad5218;hpb=b699ac5853f69f617bb1d388c8bb8a8c0d5347e9;p=~andy%2Fgtk diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c index 8284eea94..576010557 100644 --- a/gtk/gtkdnd-quartz.c +++ b/gtk/gtkdnd-quartz.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -29,23 +27,21 @@ #include #include -#include "gdkconfig.h" - -#include "gdk/gdkkeysyms.h" +#include "gdk/gdk.h" #include "gtkdnd.h" #include "gtkiconfactory.h" #include "gtkicontheme.h" -#include "gtkimage.h" +#include "gtkimageprivate.h" #include "gtkinvisible.h" #include "gtkmain.h" -#include "gtkplug.h" #include "gtkstock.h" #include "gtkwindow.h" #include "gtkintl.h" #include "gtkquartz.h" -#include "gtkalias.h" #include "gdk/quartz/gdkquartz.h" +#include "gtkselectionprivate.h" +#include "gtksettings.h" typedef struct _GtkDragSourceSite GtkDragSourceSite; typedef struct _GtkDragSourceInfo GtkDragSourceInfo; @@ -63,6 +59,11 @@ static GtkDragDestInfo *gtk_drag_get_dest_info (GdkDragContext *context, gboolean create); static void gtk_drag_source_site_destroy (gpointer data); +static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context, + gboolean create); + +extern GdkDragContext *gdk_quartz_drag_source_context (); /* gdk/quartz/gdkdnd-quartz.c */ + struct _GtkDragSourceSite { GdkModifierType start_button_mask; @@ -73,14 +74,10 @@ struct _GtkDragSourceSite GtkImageType icon_type; union { - GtkImagePixmapData pixmap; GtkImagePixbufData pixbuf; GtkImageStockData stock; GtkImageIconNameData name; } icon_data; - GdkBitmap *icon_mask; - - GdkColormap *colormap; /* Colormap for drag icon */ /* Stored button press information to detect drag beginning */ gint state; @@ -89,13 +86,16 @@ struct _GtkDragSourceSite struct _GtkDragSourceInfo { + GtkWidget *source_widget; GtkWidget *widget; GtkTargetList *target_list; /* Targets for drag data */ GdkDragAction possible_actions; /* Actions allowed by source */ GdkDragContext *context; /* drag context */ - + NSEvent *nsevent; /* what started it */ gint hot_x, hot_y; /* Hot spot for drag */ GdkPixbuf *icon_pixbuf; + gboolean success; + gboolean delete; }; struct _GtkDragDestSite @@ -145,6 +145,7 @@ struct _GtkDragFindData selection_data.data = NULL; selection_data.length = -1; selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type); + selection_data.display = gdk_display_get_default (); if (gtk_target_list_find (info->target_list, selection_data.target, @@ -177,6 +178,16 @@ struct _GtkDragFindData @end +/** + * gtk_drag_get_data: (method) + * @widget: the widget that will receive the + * #GtkWidget::drag-data-received signal. + * @context: the drag context + * @target: the target (form of the data) to retrieve. + * @time_: a timestamp for retrieving the data. This will + * generally be the time received in a #GtkWidget::drag-motion" + * or #GtkWidget::drag-drop" signal. + */ void gtk_drag_get_data (GtkWidget *widget, GdkDragContext *context, @@ -228,24 +239,37 @@ gtk_drag_get_data (GtkWidget *widget, { gtk_drag_finish (context, (selection_data->length >= 0), - (context->action == GDK_ACTION_MOVE), + (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE), time); } } - -GtkWidget * -gtk_drag_get_source_widget (GdkDragContext *context) -{ - return NULL; -} - +/** + * gtk_drag_finish: (method) + * @context: the drag context. + * @success: a flag indicating whether the drop was successful + * @del: a flag indicating whether the source should delete the + * original data. (This should be %TRUE for a move) + * @time_: the timestamp from the #GtkWidget::drag-drop signal. + */ void gtk_drag_finish (GdkDragContext *context, gboolean success, gboolean del, guint32 time) { + GtkDragSourceInfo *info; + GdkDragContext* source_context = gdk_quartz_drag_source_context (); + + if (source_context) + { + info = gtk_drag_get_source_info (source_context, FALSE); + if (info) + { + info->success = success; + info->delete = del; + } + } } static void @@ -307,8 +331,28 @@ gtk_drag_clear_source_info (GdkDragContext *context) g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL); } +/** + * gtk_drag_get_source_widget: (method) + * @context: a (destination side) drag context + */ +GtkWidget * +gtk_drag_get_source_widget (GdkDragContext *context) +{ + GtkDragSourceInfo *info; + GdkDragContext* real_source_context = gdk_quartz_drag_source_context(); + + if (!real_source_context) + return NULL; + + info = gtk_drag_get_source_info (real_source_context, FALSE); + if (!info) + return NULL; + + return info->source_widget; +} + /************************************************************* - * gtk_drag_highlight_expose: + * gtk_drag_highlight_draw: * Callback for expose_event for highlighted widgets. * arguments: * widget: @@ -318,83 +362,58 @@ gtk_drag_clear_source_info (GdkDragContext *context) *************************************************************/ static gboolean -gtk_drag_highlight_expose (GtkWidget *widget, - GdkEventExpose *event, - gpointer data) +gtk_drag_highlight_draw (GtkWidget *widget, + cairo_t *cr, + gpointer data) { - gint x, y, width, height; - - if (GTK_WIDGET_DRAWABLE (widget)) - { - cairo_t *cr; - - if (GTK_WIDGET_NO_WINDOW (widget)) - { - x = widget->allocation.x; - y = widget->allocation.y; - width = widget->allocation.width; - height = widget->allocation.height; - } - else - { - x = 0; - y = 0; - gdk_drawable_get_size (widget->window, &width, &height); - } - - gtk_paint_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, widget, "dnd", - x, y, width, height); - - cr = gdk_cairo_create (widget->window); - cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ - cairo_set_line_width (cr, 1.0); - cairo_rectangle (cr, - x + 0.5, y + 0.5, - width - 1, height - 1); - cairo_stroke (cr); - cairo_destroy (cr); - } + int width = gtk_widget_get_allocated_width (widget); + int height = gtk_widget_get_allocated_height (widget); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND); + + gtk_render_frame (context, cr, 0, 0, width, height); + gtk_style_context_restore (context); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + cairo_set_line_width (cr, 1.0); + cairo_rectangle (cr, + 0.5, 0.5, + width - 1, height - 1); + cairo_stroke (cr); + return FALSE; } -/************************************************************* - * gtk_drag_highlight: - * Highlight the given widget in the default manner. - * arguments: - * widget: - * results: - *************************************************************/ - +/** + * gtk_drag_highlight: (method) + * @widget: a widget to highlight + */ void gtk_drag_highlight (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); - g_signal_connect_after (widget, "expose-event", - G_CALLBACK (gtk_drag_highlight_expose), + g_signal_connect_after (widget, "draw", + G_CALLBACK (gtk_drag_highlight_draw), NULL); gtk_widget_queue_draw (widget); } -/************************************************************* - * gtk_drag_unhighlight: - * Refresh the given widget to remove the highlight. - * arguments: - * widget: - * results: - *************************************************************/ - +/** + * gtk_drag_unhighlight: (method) + * @widget: a widget to remove the highlight from. + */ void gtk_drag_unhighlight (GtkWidget *widget) { g_return_if_fail (GTK_IS_WIDGET (widget)); g_signal_handlers_disconnect_by_func (widget, - gtk_drag_highlight_expose, + gtk_drag_highlight_draw, NULL); gtk_widget_queue_draw (widget); @@ -404,9 +423,10 @@ static NSWindow * get_toplevel_nswindow (GtkWidget *widget) { GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + GdkWindow *window = gtk_widget_get_window (toplevel); - if (GTK_WIDGET_TOPLEVEL (toplevel) && toplevel->window) - return [gdk_quartz_window_get_nsview (toplevel->window) window]; + if (gtk_widget_is_toplevel (toplevel) && window) + return [gdk_quartz_window_get_nsview (window) window]; else return NULL; } @@ -417,7 +437,7 @@ register_types (GtkWidget *widget, GtkDragDestSite *site) if (site->target_list) { NSWindow *nswindow = get_toplevel_nswindow (widget); - NSArray *types; + NSSet *types; NSAutoreleasePool *pool; if (!nswindow) @@ -426,7 +446,9 @@ register_types (GtkWidget *widget, GtkDragDestSite *site) pool = [[NSAutoreleasePool alloc] init]; types = _gtk_quartz_target_list_to_pasteboard_types (site->target_list); - [nswindow registerForDraggedTypes:types]; + [nswindow registerForDraggedTypes:[types allObjects]]; + + [types release]; [pool release]; } } @@ -461,6 +483,17 @@ gtk_drag_dest_site_destroy (gpointer data) g_free (site); } +/** + * gtk_drag_dest_set: (method) + * @widget: a #GtkWidget + * @flags: which types of default drag behavior to use + * @targets: (allow-none) (array length=n_targets): a pointer to an array of #GtkTargetEntrys + * indicating the drop types that this @widget will accept, or %NULL. + * Later you can access the list with gtk_drag_dest_get_target_list() + * and gtk_drag_dest_find_target(). + * @n_targets: the number of entries in @targets + * @actions: a bitmask of possible actions for a drop onto this @widget. + */ void gtk_drag_dest_set (GtkWidget *widget, GtkDestDefaults flags, @@ -474,8 +507,6 @@ gtk_drag_dest_set (GtkWidget *widget, old_site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); - gtk_drag_dest_unset (widget); - site = g_new (GtkDragDestSite, 1); site->flags = flags; site->have_drag = FALSE; @@ -490,7 +521,9 @@ gtk_drag_dest_set (GtkWidget *widget, else site->track_motion = FALSE; - if (GTK_WIDGET_REALIZED (widget)) + gtk_drag_dest_unset (widget); + + if (gtk_widget_get_realized (widget)) gtk_drag_dest_realized (widget, site); g_signal_connect (widget, "realize", @@ -502,6 +535,16 @@ gtk_drag_dest_set (GtkWidget *widget, site, gtk_drag_dest_site_destroy); } +/** + * gtk_drag_dest_set_proxy: (method) + * @widget: a #GtkWidget + * @proxy_window: the window to which to forward drag events + * @protocol: the drag protocol which the @proxy_window accepts + * (You can use gdk_drag_get_protocol() to determine this) + * @use_coordinates: If %TRUE, send the same coordinates to the + * destination, because it is an embedded + * subwindow. + */ void gtk_drag_dest_set_proxy (GtkWidget *widget, GdkWindow *proxy_window, @@ -511,6 +554,10 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, g_warning ("gtk_drag_dest_set_proxy is not supported on Mac OS X."); } +/** + * gtk_drag_dest_unset: (method) + * @widget: a #GtkWidget + */ void gtk_drag_dest_unset (GtkWidget *widget) { @@ -532,6 +579,10 @@ gtk_drag_dest_unset (GtkWidget *widget) g_object_set_data (G_OBJECT (widget), I_("gtk-drag-dest"), NULL); } +/** + * gtk_drag_dest_get_target_list: (method) + * @widget: a #GtkWidget + */ GtkTargetList* gtk_drag_dest_get_target_list (GtkWidget *widget) { @@ -544,6 +595,11 @@ gtk_drag_dest_get_target_list (GtkWidget *widget) return site ? site->target_list : NULL; } +/** + * gtk_drag_dest_set_target_list: (method) + * @widget: a #GtkWidget that's a drag destination + * @target_list: (allow-none): list of droppable targets, or %NULL for none + */ void gtk_drag_dest_set_target_list (GtkWidget *widget, GtkTargetList *target_list) @@ -572,6 +628,10 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, register_types (widget, site); } +/** + * gtk_drag_dest_add_text_targets: (method) + * @widget: a #GtkWidget that's a drag destination + */ void gtk_drag_dest_add_text_targets (GtkWidget *widget) { @@ -587,6 +647,11 @@ gtk_drag_dest_add_text_targets (GtkWidget *widget) gtk_target_list_unref (target_list); } + +/** + * gtk_drag_dest_add_image_targets: (method) + * @widget: a #GtkWidget that's a drag destination + */ void gtk_drag_dest_add_image_targets (GtkWidget *widget) { @@ -602,6 +667,10 @@ gtk_drag_dest_add_image_targets (GtkWidget *widget) gtk_target_list_unref (target_list); } +/** + * gtk_drag_dest_add_uri_targets: (method) + * @widget: a #GtkWidget that's a drag destination + */ void gtk_drag_dest_add_uri_targets (GtkWidget *widget) { @@ -636,7 +705,7 @@ gtk_drag_find_widget (GtkWidget *widget, gint x_offset = 0; gint y_offset = 0; - if (data->found || !GTK_WIDGET_MAPPED (widget) || !GTK_WIDGET_SENSITIVE (widget)) + if (data->found || !gtk_widget_get_mapped (widget) || !gtk_widget_get_sensitive (widget)) return; /* Note that in the following code, we only count the @@ -653,20 +722,25 @@ gtk_drag_find_widget (GtkWidget *widget, * our coordinates to be relative to widget->window and * recurse. */ - new_allocation = widget->allocation; + gtk_widget_get_allocation (widget, &new_allocation); - if (widget->parent) + if (gtk_widget_get_parent (widget)) { gint tx, ty; - GdkWindow *window = widget->window; + GdkWindow *window = gtk_widget_get_window (widget); + GdkWindow *parent_window; + GtkAllocation allocation; + + parent_window = gtk_widget_get_window (gtk_widget_get_parent (widget)); /* Compute the offset from allocation-relative to * window-relative coordinates. */ - allocation_to_window_x = widget->allocation.x; - allocation_to_window_y = widget->allocation.y; + gtk_widget_get_allocation (widget, &allocation); + allocation_to_window_x = allocation.x; + allocation_to_window_y = allocation.y; - if (!GTK_WIDGET_NO_WINDOW (widget)) + if (gtk_widget_get_has_window (widget)) { /* The allocation is relative to the parent window for * window widgets, not to widget->window. @@ -680,11 +754,12 @@ gtk_drag_find_widget (GtkWidget *widget, new_allocation.x = 0 + allocation_to_window_x; new_allocation.y = 0 + allocation_to_window_y; - while (window && window != widget->parent->window) + while (window && window != parent_window) { GdkRectangle window_rect = { 0, 0, 0, 0 }; - gdk_drawable_get_size (window, &window_rect.width, &window_rect.height); + window_rect.width = gdk_window_get_width (window); + window_rect.height = gdk_window_get_height (window); gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation); @@ -726,7 +801,7 @@ gtk_drag_find_widget (GtkWidget *widget, gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_widget, &children); for (tmp_list = children; tmp_list; tmp_list = tmp_list->next) { - if (!new_data.found && GTK_WIDGET_DRAWABLE (tmp_list->data)) + if (!new_data.found && gtk_widget_is_drawable (tmp_list->data)) gtk_drag_find_widget (tmp_list->data, &new_data); g_object_unref (tmp_list->data); } @@ -796,8 +871,8 @@ gtk_drag_dest_motion (GtkWidget *widget, if (site->track_motion || site->flags & GTK_DEST_DEFAULT_MOTION) { - if (context->suggested_action & site->actions) - action = context->suggested_action; + if (gdk_drag_context_get_suggested_action (context) & site->actions) + action = gdk_drag_context_get_suggested_action (context); if (action && gtk_drag_dest_find_target (widget, context, NULL)) { @@ -863,6 +938,11 @@ gtk_drag_dest_drop (GtkWidget *widget, return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval; } +/** + * gtk_drag_dest_set_track_motion: (method) + * @widget: a #GtkWidget that's a drag destination + * @track_motion: whether to accept all targets + */ void gtk_drag_dest_set_track_motion (GtkWidget *widget, gboolean track_motion) @@ -878,6 +958,10 @@ gtk_drag_dest_set_track_motion (GtkWidget *widget, site->track_motion = track_motion != FALSE; } +/** + * gtk_drag_dest_get_track_motion: (method) + * @widget: a #GtkWidget that's a drag destination + */ gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget) { @@ -940,7 +1024,7 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel, } } - gdk_window_get_position (toplevel->window, &tx, &ty); + gdk_window_get_position (gtk_widget_get_window (toplevel), &tx, &ty); data.x = event->dnd.x_root - tx; data.y = event->dnd.y_root - ty; @@ -976,6 +1060,13 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel, } +/** + * gtk_drag_dest_find_target: (method) + * @widget: drag destination widget + * @context: drag context + * @target_list: (allow-none): list of droppable targets, or %NULL to use + * gtk_drag_dest_get_target_list (@widget). + */ GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, GdkDragContext *context, @@ -990,7 +1081,6 @@ gtk_drag_dest_find_target (GtkWidget *widget, g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE); g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE); - g_return_val_if_fail (!context->is_source, GDK_NONE); dragging_info = gdk_quartz_drag_context_get_dragging_info_libgtk_only (context); pasteboard = [dragging_info draggingPasteboard]; @@ -1031,6 +1121,73 @@ gtk_drag_dest_find_target (GtkWidget *widget, return GDK_NONE; } +static gboolean +gtk_drag_begin_idle (gpointer arg) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GdkDragContext* context = (GdkDragContext*) arg; + GtkDragSourceInfo* info = gtk_drag_get_source_info (context, FALSE); + NSWindow *nswindow; + NSPasteboard *pasteboard; + GtkDragSourceOwner *owner; + NSPoint point; + NSSet *types; + NSImage *drag_image; + + g_assert (info != NULL); + + pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + owner = [[GtkDragSourceOwner alloc] initWithInfo:info]; + + types = _gtk_quartz_target_list_to_pasteboard_types (info->target_list); + + [pasteboard declareTypes:[types allObjects] owner:owner]; + + [owner release]; + [types release]; + + if ((nswindow = get_toplevel_nswindow (info->source_widget)) == NULL) + return G_SOURCE_REMOVE; + + /* Ref the context. It's unreffed when the drag has been aborted */ + g_object_ref (info->context); + + /* FIXME: If the event isn't a mouse event, use the global cursor position instead */ + point = [info->nsevent locationInWindow]; + + drag_image = _gtk_quartz_create_image_from_pixbuf (info->icon_pixbuf); + if (drag_image == NULL) + { + g_object_unref (info->context); + return G_SOURCE_REMOVE; + } + + point.x -= info->hot_x; + point.y -= info->hot_y; + + [nswindow dragImage:drag_image + at:point + offset:NSZeroSize + event:info->nsevent + pasteboard:pasteboard + source:nswindow + slideBack:YES]; + + [info->nsevent release]; + [drag_image release]; + + [pool release]; + + return G_SOURCE_REMOVE; +} +/* Fake protocol to let us call GdkNSView gdkWindow without including + * gdk/GdkNSView.h (which we can't because it pulls in the internal-only + * gdkwindow.h). + */ +@protocol GdkNSView +- (GdkWindow *)gdkWindow; +@end + static GdkDragContext * gtk_drag_begin_internal (GtkWidget *widget, GtkDragSourceSite *site, @@ -1040,24 +1197,71 @@ gtk_drag_begin_internal (GtkWidget *widget, GdkEvent *event) { GtkDragSourceInfo *info; + GdkDevice *pointer; + GdkWindow *window; GdkDragContext *context; - NSWindow *nswindow; - NSPasteboard *pasteboard; - GtkDragSourceOwner *owner; + NSWindow *nswindow = get_toplevel_nswindow (widget); + NSPoint point = {0, 0}; + gdouble x, y; + double time = (double)g_get_real_time (); NSEvent *nsevent; - NSPoint point; + NSTimeInterval nstime; + + if (event) + { + if (gdk_event_get_coords (event, &x, &y)) + { + /* We need to translate (x, y) to coordinates relative to the + * toplevel GdkWindow, which should be the GdkWindow backing + * nswindow. Then, we convert to the NSWindow coordinate system. + */ + GdkWindow *window = event->any.window; + GdkWindow *toplevel = gdk_window_get_effective_toplevel (window); + + while (window != toplevel) + { + double old_x = x; + double old_y = y; + + gdk_window_coords_to_parent (window, old_x, old_y, + &x, &y); + window = gdk_window_get_effective_parent (window); + } + + point.x = x; + point.y = gdk_window_get_height (window) - y; + } + time = (double)gdk_event_get_time (event); + } + + nstime = [[NSDate dateWithTimeIntervalSince1970: time / 1000] timeIntervalSinceReferenceDate]; + nsevent = [NSEvent mouseEventWithType: NSLeftMouseDown + location: point + modifierFlags: 0 + timestamp: nstime + windowNumber: [nswindow windowNumber] + context: [nswindow graphicsContext] + eventNumber: 0 + clickCount: 1 + pressure: 0.0 ]; - context = gdk_drag_begin (NULL, NULL); - context->is_source = TRUE; + window = [(id)[nswindow contentView] gdkWindow]; + g_return_val_if_fail (nsevent != NULL, NULL); + + context = gdk_drag_begin (window, NULL); + g_return_val_if_fail (context != NULL, NULL); info = gtk_drag_get_source_info (context, TRUE); - + info->nsevent = nsevent; + [info->nsevent retain]; + + info->source_widget = g_object_ref (widget); info->widget = g_object_ref (widget); info->target_list = target_list; gtk_target_list_ref (target_list); info->possible_actions = actions; - + g_signal_emit_by_name (widget, "drag-begin", info->context); /* Ensure that we have an icon before we start the drag; the @@ -1067,83 +1271,53 @@ gtk_drag_begin_internal (GtkWidget *widget, if (!info->icon_pixbuf) { if (!site || site->icon_type == GTK_IMAGE_EMPTY) - gtk_drag_set_icon_default (context); + gtk_drag_set_icon_default (context); else - switch (site->icon_type) - { - case GTK_IMAGE_PIXMAP: - /* This is not supported, so just set a small transparent pixbuf - * since we need to have something. - */ - if (0) - gtk_drag_set_icon_pixmap (context, - site->colormap, - site->icon_data.pixmap.pixmap, - site->icon_mask, - -2, -2); - else - { - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 1, 1); - gdk_pixbuf_fill (pixbuf, 0xffffff); - - gtk_drag_set_icon_pixbuf (context, - pixbuf, - 0, 0); - - g_object_unref (pixbuf); - } - 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; - case GTK_IMAGE_ICON_NAME: - gtk_drag_set_icon_name (context, - site->icon_data.name.icon_name, - -2, -2); - break; - case GTK_IMAGE_EMPTY: - default: - g_assert_not_reached(); - break; - } + { + switch (site->icon_type) + { + 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; + case GTK_IMAGE_ICON_NAME: + gtk_drag_set_icon_name (context, + site->icon_data.name.icon_name, + -2, -2); + break; + case GTK_IMAGE_EMPTY: + default: + g_assert_not_reached(); + break; + } + } } - gdk_pointer_ungrab (0); - - pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - owner = [[GtkDragSourceOwner alloc] initWithInfo:info]; - - [pasteboard declareTypes:_gtk_quartz_target_list_to_pasteboard_types (target_list) owner:owner]; - - /* Ref the context. It's unreffed when the drag has been aborted */ - g_object_ref (info->context); + /* drag will begin in an idle handler to avoid nested run loops */ - nswindow = get_toplevel_nswindow (widget); + g_idle_add_full (G_PRIORITY_HIGH_IDLE, gtk_drag_begin_idle, context, NULL); - /* FIXME: If the event isn't a mouse event, use the global cursor position instead */ - nsevent = [nswindow currentEvent]; - point = [nsevent locationInWindow]; + pointer = gdk_drag_context_get_device (info->context); + gdk_device_ungrab (pointer, 0); - [nswindow dragImage:_gtk_quartz_create_image_from_pixbuf (info->icon_pixbuf) - at:point - offset:NSMakeSize(0, 0) - event:nsevent - pasteboard:pasteboard - source:nswindow - slideBack:YES]; - - return info->context; + return context; } +/** + * gtk_drag_begin: (method) + * @widget: the source widget. + * @targets: The targets (data formats) in which the + * source can provide the data. + * @actions: A bitmask of the allowed drag actions for this drag. + * @button: The button the user clicked to start the drag. + * @event: The event that triggered the start of the drag. + */ GdkDragContext * gtk_drag_begin (GtkWidget *widget, GtkTargetList *targets, @@ -1152,7 +1326,7 @@ gtk_drag_begin (GtkWidget *widget, GdkEvent *event) { g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); + g_return_val_if_fail (gtk_widget_get_realized (widget), NULL); g_return_val_if_fail (targets != NULL, NULL); return gtk_drag_begin_internal (widget, NULL, targets, @@ -1219,6 +1393,15 @@ gtk_drag_source_event_cb (GtkWidget *widget, return retval; } +/** + * gtk_drag_source_set: (method) + * @widget: a #GtkWidget + * @start_button_mask: the bitmask of buttons that can start the drag + * @targets: (allow-none) (array length=n_targets): the table of targets that the drag will support, + * may be %NULL + * @n_targets: the number of items in @targets + * @actions: the bitmask of possible actions for a drag from this widget + */ void gtk_drag_source_set (GtkWidget *widget, GdkModifierType start_button_mask, @@ -1270,14 +1453,10 @@ gtk_drag_source_set (GtkWidget *widget, site->actions = actions; } -/************************************************************* - * gtk_drag_source_unset - * Unregister this widget as a drag source. - * arguments: - * widget: - * results: - *************************************************************/ - +/** + * gtk_drag_source_unset: (method) + * @widget: a #GtkWidget + */ void gtk_drag_source_unset (GtkWidget *widget) { @@ -1296,6 +1475,10 @@ gtk_drag_source_unset (GtkWidget *widget) } } +/** + * gtk_drag_source_get_target_list: (method) + * @widget: a #GtkWidget + */ GtkTargetList * gtk_drag_source_get_target_list (GtkWidget *widget) { @@ -1309,6 +1492,11 @@ gtk_drag_source_get_target_list (GtkWidget *widget) } +/** + * gtk_drag_source_set_target_list: (method) + * @widget: a #GtkWidget that's a drag source + * @target_list: (allow-none): list of draggable targets, or %NULL for none + */ void gtk_drag_source_set_target_list (GtkWidget *widget, GtkTargetList *target_list) @@ -1361,6 +1549,10 @@ gtk_drag_source_add_text_targets (GtkWidget *widget) gtk_target_list_unref (target_list); } +/** + * gtk_drag_source_add_image_targets: (method) + * @widget: a #GtkWidget that's is a drag source + */ void gtk_drag_source_add_image_targets (GtkWidget *widget) { @@ -1376,6 +1568,10 @@ gtk_drag_source_add_image_targets (GtkWidget *widget) gtk_target_list_unref (target_list); } +/** + * gtk_drag_source_add_uri_targets: (method) + * @widget: a #GtkWidget that's is a drag source + */ void gtk_drag_source_add_uri_targets (GtkWidget *widget) { @@ -1398,12 +1594,6 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site) { case GTK_IMAGE_EMPTY: break; - case GTK_IMAGE_PIXMAP: - if (site->icon_data.pixmap.pixmap) - g_object_unref (site->icon_data.pixmap.pixmap); - if (site->icon_mask) - g_object_unref (site->icon_mask); - break; case GTK_IMAGE_PIXBUF: g_object_unref (site->icon_data.pixbuf.pixbuf); break; @@ -1418,10 +1608,6 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site) break; } site->icon_type = GTK_IMAGE_EMPTY; - - if (site->colormap) - g_object_unref (site->colormap); - site->colormap = NULL; } static void @@ -1436,36 +1622,11 @@ gtk_drag_source_site_destroy (gpointer data) g_free (site); } -void -gtk_drag_source_set_icon (GtkWidget *widget, - GdkColormap *colormap, - GdkPixmap *pixmap, - GdkBitmap *mask) -{ - GtkDragSourceSite *site; - - g_return_if_fail (GTK_IS_WIDGET (widget)); - 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 = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); - g_return_if_fail (site != NULL); - - g_object_ref (colormap); - g_object_ref (pixmap); - if (mask) - g_object_ref (mask); - - gtk_drag_source_unset_icon (site); - - site->icon_type = GTK_IMAGE_PIXMAP; - - site->icon_data.pixmap.pixmap = pixmap; - site->icon_mask = mask; - site->colormap = colormap; -} - +/** + * gtk_drag_source_set_icon_pixbuf: (method) + * @widget: a #GtkWidget + * @pixbuf: the #GdkPixbuf for the drag icon + */ void gtk_drag_source_set_icon_pixbuf (GtkWidget *widget, GdkPixbuf *pixbuf) @@ -1560,7 +1721,6 @@ gtk_drag_set_icon_widget (GdkDragContext *context, gint hot_y) { g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (context->is_source); g_return_if_fail (GTK_IS_WIDGET (widget)); g_warning ("gtk_drag_set_icon_widget is not supported on Mac OS X"); @@ -1579,8 +1739,8 @@ set_icon_stock_pixbuf (GdkDragContext *context, if (stock_id) { - pixbuf = gtk_widget_render_icon (info->widget, stock_id, - GTK_ICON_SIZE_DND, NULL); + pixbuf = gtk_widget_render_icon_pixbuf (info->widget, stock_id, + GTK_ICON_SIZE_DND); if (!pixbuf) { @@ -1615,7 +1775,6 @@ gtk_drag_set_icon_pixbuf (GdkDragContext *context, gint hot_y) { g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (context->is_source); g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y); @@ -1639,36 +1798,83 @@ gtk_drag_set_icon_stock (GdkDragContext *context, { g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (context->is_source); g_return_if_fail (stock_id != NULL); set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y); } + +/* XXX: This function is in gdk, too. Should it be in Cairo? */ +static gboolean +_gtk_cairo_surface_extents (cairo_surface_t *surface, + GdkRectangle *extents) +{ + double x1, x2, y1, y2; + cairo_t *cr; + + g_return_val_if_fail (surface != NULL, FALSE); + g_return_val_if_fail (extents != NULL, FALSE); + + cr = cairo_create (surface); + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + + x1 = floor (x1); + y1 = floor (y1); + x2 = ceil (x2); + y2 = ceil (y2); + x2 -= x1; + y2 -= y1; + + if (x1 < G_MININT || x1 > G_MAXINT || + y1 < G_MININT || y1 > G_MAXINT || + x2 > G_MAXINT || y2 > G_MAXINT) + { + extents->x = extents->y = extents->width = extents->height = 0; + return FALSE; + } + + extents->x = x1; + extents->y = y1; + extents->width = x2; + extents->height = y2; + + return TRUE; +} + /** - * 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 + * gtk_drag_set_icon_surface: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @surface: the surface to use as icon + * + * Sets @surface as the icon for a given drag. GTK+ retains * references 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. + * they are no longer needed. + * + * To position the surface relative to the mouse, use + * cairo_surface_set_device_offset() on @surface. The mouse + * cursor will be positioned at the (0,0) coordinate of the + * surface. **/ -void -gtk_drag_set_icon_pixmap (GdkDragContext *context, - GdkColormap *colormap, - GdkPixmap *pixmap, - GdkBitmap *mask, - gint hot_x, - gint hot_y) +void +gtk_drag_set_icon_surface (GdkDragContext *context, + cairo_surface_t *surface) { - g_warning ("gtk_drag_set_icon_pixmap is not supported on Mac OS X"); + GdkPixbuf *pixbuf; + GdkRectangle extents; + double x_offset, y_offset; + + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (surface != NULL); + + _gtk_cairo_surface_extents (surface, &extents); + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + + pixbuf = gdk_pixbuf_get_from_surface (surface, + extents.x, extents.y, + extents.width, extents.height); + gtk_drag_set_icon_pixbuf (context, pixbuf, -x_offset, -y_offset); + g_object_unref (pixbuf); } /** @@ -1700,10 +1906,9 @@ gtk_drag_set_icon_name (GdkDragContext *context, gint width, height, icon_size; g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (context->is_source); g_return_if_fail (icon_name != NULL); - screen = gdk_drawable_get_screen (context->source_window); + screen = gdk_window_get_screen (gdk_drag_context_get_source_window (context)); g_return_if_fail (screen != NULL); settings = gtk_settings_get_for_screen (screen); @@ -1736,51 +1941,61 @@ void gtk_drag_set_icon_default (GdkDragContext *context) { g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (context->is_source); gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2); } -void -gtk_drag_set_default_icon (GdkColormap *colormap, - GdkPixmap *pixmap, - GdkBitmap *mask, - gint hot_x, - gint hot_y) -{ - g_warning ("gtk_drag_set_default_icon is not supported on Mac OS X."); -} - static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info) { + NSPasteboard *pasteboard; + NSAutoreleasePool *pool; + if (info->icon_pixbuf) g_object_unref (info->icon_pixbuf); g_signal_emit_by_name (info->widget, "drag-end", info->context); + if (info->source_widget) + g_object_unref (info->source_widget); + if (info->widget) g_object_unref (info->widget); gtk_target_list_unref (info->target_list); + pool = [[NSAutoreleasePool alloc] init]; + + /* Empty the pasteboard, so that it will not accidentally access + * info->context after it has been destroyed. + */ + pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard]; + [pasteboard declareTypes: nil owner: nil]; + + [pool release]; + gtk_drag_clear_source_info (info->context); g_object_unref (info->context); g_free (info); + info = NULL; } static gboolean drag_drop_finished_idle_cb (gpointer data) { gtk_drag_source_info_destroy (data); - return FALSE; + return G_SOURCE_REMOVE; } static void gtk_drag_drop_finished (GtkDragSourceInfo *info) { + if (info->success && info->delete) + g_signal_emit_by_name (info->source_widget, "drag-data-delete", + info->context); + /* Workaround for the fact that the NS API blocks until the drag is * over. This way the context is still valid when returning from * drag_begin, even if it will still be quite useless. See bug #501588. @@ -1824,7 +2039,14 @@ _gtk_drag_source_handle_event (GtkWidget *widget, } } - +/** + * gtk_drag_check_threshold: (method) + * @widget: a #GtkWidget + * @start_x: X coordinate of start of drag + * @start_y: Y coordinate of start of drag + * @current_x: current X coordinate + * @current_y: current Y coordinate + */ gboolean gtk_drag_check_threshold (GtkWidget *widget, gint start_x, @@ -1843,6 +2065,3 @@ gtk_drag_check_threshold (GtkWidget *widget, return (ABS (current_x - start_x) > drag_threshold || ABS (current_y - start_y) > drag_threshold); } - -#define __GTK_DND_C__ -#include "gtkaliasdef.c"