Index: gtk/gtktreeview.c =================================================================== --- gtk/gtktreeview.c (revision 21770) +++ gtk/gtktreeview.c (working copy) @@ -99,6 +99,9 @@ guint source_set : 1; guint dest_set : 1; + + GtkTreePath* path; + GtkTreeModel* model; }; @@ -6967,6 +6970,17 @@ return path; } +#ifdef GDK_WINDOWING_QUARTZ +static void +gtk_tree_view_catch_drag_begin (GtkWidget* widget, + GdkDragContext* context, + gpointer user_data) +{ + TreeViewDragInfo* drag_info = (TreeViewDragInfo*) user_data; + set_source_row (context, drag_info->model, drag_info->path); +} +#endif + static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view, GdkEventMotion *event) @@ -6979,6 +6993,7 @@ gint cell_x, cell_y; GtkTreeModel *model; gboolean retval = FALSE; + gint drag_begin_id; di = get_info (tree_view); @@ -7025,13 +7040,25 @@ retval = TRUE; +#ifdef GDK_WINDOWING_QUARTZ + /* catch drag-being signal */ + di->model = model; + di->path = path; + drag_begin_id = g_signal_connect (tree_view, "drag-begin", G_CALLBACK (gtk_tree_view_catch_drag_begin), (gpointer) di); +#endif + context = gtk_drag_begin (widget, gtk_drag_source_get_target_list (widget), di->source_actions, button, (GdkEvent*)event); +#ifndef GDK_WINDOWING_QUARTZ set_source_row (context, model, path); +#else + /* disconnect drag-begin and catch drag-end */ + g_signal_handler_disconnect (tree_view, drag_begin_id); +#endif out: if (path) Index: gtk/gtkquartz.c =================================================================== --- gtk/gtkquartz.c (revision 21770) +++ gtk/gtkquartz.c (working copy) @@ -24,6 +24,23 @@ #include "gtkalias.h" NSImage * +_gtk_quartz_create_image_from_drawable (GdkDrawable* drawable) +{ + GdkPixbuf* pixbuf; + NSImage* image = NULL; + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, drawable, NULL, + 0, 0, /* src */ + 0, 0, /* dst */ + -1, -1); + if (pixbuf) + image = _gtk_quartz_create_image_from_pixbuf (pixbuf); + + return image; +} + + +NSImage * _gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf) { CGColorSpaceRef colorspace; Index: gtk/gtkquartz.h =================================================================== --- gtk/gtkquartz.h (revision 21770) +++ gtk/gtkquartz.h (working copy) @@ -41,6 +41,7 @@ GtkSelectionData *selection_data); NSImage *_gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf); +NSImage *_gtk_quartz_create_image_from_drawable (GdkDrawable *drawable); G_END_DECLS Index: gtk/gtktooltip.c =================================================================== --- gtk/gtktooltip.c (revision 21770) +++ gtk/gtktooltip.c (working copy) @@ -426,6 +426,7 @@ gtk_tooltip_trigger_tooltip_query (GdkDisplay *display) { gint x, y; + gint rx, ry; GdkWindow *window; GdkEvent event; @@ -434,10 +435,14 @@ if (!window) return; + gdk_window_get_origin (window, &rx, &ry); + event.type = GDK_MOTION_NOTIFY; event.motion.window = window; event.motion.x = x; + event.motion.x_root = rx + x; event.motion.y = y; + event.motion.y_root = ry + y; event.motion.is_hint = FALSE; _gtk_tooltip_handle_event (&event); Index: gtk/gtkdnd-quartz.c =================================================================== --- gtk/gtkdnd-quartz.c (revision 21770) +++ gtk/gtkdnd-quartz.c (working copy) @@ -63,6 +63,11 @@ 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; @@ -89,6 +94,7 @@ struct _GtkDragSourceInfo { + GtkWidget *source_widget; GtkWidget *widget; GtkTargetList *target_list; /* Targets for drag data */ GdkDragAction possible_actions; /* Actions allowed by source */ @@ -96,6 +102,8 @@ gint hot_x, hot_y; /* Hot spot for drag */ GdkPixbuf *icon_pixbuf; + gboolean success; + gboolean delete; }; struct _GtkDragDestSite @@ -223,7 +231,9 @@ selection_data, 0, time); } + + if (site && site->flags & GTK_DEST_DEFAULT_DROP) { gtk_drag_finish (context, @@ -233,19 +243,24 @@ } } - -GtkWidget * -gtk_drag_get_source_widget (GdkDragContext *context) -{ - return NULL; -} - 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,6 +322,22 @@ g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL); } +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: * Callback for expose_event for highlighted widgets. @@ -857,6 +888,8 @@ gtk_drag_get_data (widget, context, target, time); } + /* leave a note for the source-side context about the action chosen */ + g_signal_emit_by_name (widget, "drag-drop", context, x, y, time, &retval); @@ -1052,6 +1085,7 @@ info = gtk_drag_get_source_info (context, TRUE); + info->source_widget = g_object_ref (widget); info->widget = g_object_ref (widget); info->target_list = target_list; gtk_target_list_ref (target_list); @@ -1086,13 +1120,13 @@ 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, + gdk_pixbuf_fill (pixbuf, 0xffffff); + + gtk_drag_set_icon_pixbuf (context, + pixbuf, 0, 0); - g_object_unref (pixbuf); + g_object_unref (pixbuf); } break; case GTK_IMAGE_PIXBUF: @@ -1668,7 +1702,20 @@ gint hot_x, gint hot_y) { - g_warning ("gtk_drag_set_icon_pixmap is not supported on Mac OS X"); + GdkPixbuf *pixbuf; + + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + g_return_if_fail (GDK_IS_PIXMAP (pixmap)); + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, colormap, + 0, 0, /* src */ + 0, 0, /* dst */ + -1, -1); + + gtk_drag_set_icon_pixbuf (context, pixbuf, hot_x, hot_y); + g_object_unref (pixbuf); } /** @@ -1760,6 +1807,9 @@ 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); @@ -1781,6 +1831,10 @@ 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. Index: gdk/quartz/gdkevents-quartz.c =================================================================== --- gdk/quartz/gdkevents-quartz.c (revision 21770) +++ gdk/quartz/gdkevents-quartz.c (working copy) @@ -112,6 +112,18 @@ return ((GdkEventPrivate *) event)->windowing_data; } +/* A category that exposes the protected carbon event for an NSEvent. */ +@interface NSEvent (GdkQuartzNSEvent) +- (void *)gdk_quartz_event_ref; +@end + +@implementation NSEvent (GdkQuartzNSEvent) +- (void *)gdk_quartz_event_ref +{ + return _eventRef; +} +@end + void _gdk_events_init (void) { @@ -1668,6 +1680,65 @@ } static gboolean +_gdk_quartz_possibly_forward_accelerator (NSEvent* nsevent) +{ + /* Special-case menu shortcut events. We create command events for + * those and forward to the corresponding menu. + */ + if ((!_gdk_quartz_keyboard_grab_window || + (_gdk_quartz_keyboard_grab_window && keyboard_grab_owner_events)) && + [nsevent type] == NSKeyDown) + { + EventRef event_ref; + MenuRef menu_ref; + MenuItemIndex index; + + event_ref = [nsevent gdk_quartz_event_ref]; + if (IsMenuKeyEvent (NULL, event_ref, + kMenuEventQueryOnly, + &menu_ref, &index)) + { + MenuCommand menu_command; + HICommand hi_command; + + if (GetMenuItemCommandID (menu_ref, index, &menu_command) != noErr) + return FALSE; + + hi_command.commandID = menu_command; + hi_command.menu.menuRef = menu_ref; + hi_command.menu.menuItemIndex = index; + + CreateEvent (NULL, kEventClassCommand, kEventCommandProcess, + 0, kEventAttributeUserEvent, &event_ref); + SetEventParameter (event_ref, kEventParamDirectObject, + typeHICommand, + sizeof (HICommand), &hi_command); + + SendEventToEventTarget (event_ref, GetMenuEventTarget (menu_ref)); + + ReleaseEvent (event_ref); + + return TRUE; + } + } + return FALSE; +} + +gboolean +gdk_quartz_possibly_forward (GdkEvent* event) +{ + NSEvent *nsevent; + g_return_val_if_fail (event != NULL, FALSE); + + nsevent = ((GdkEventPrivate*)event)->windowing_data; + + if (nsevent) + return _gdk_quartz_possibly_forward_accelerator (nsevent); + + return FALSE; +} + +static gboolean gdk_event_translate (NSEvent *nsevent) { NSWindow *nswindow; Index: gdk/quartz/gdkdnd-quartz.c =================================================================== --- gdk/quartz/gdkdnd-quartz.c (revision 21770) +++ gdk/quartz/gdkdnd-quartz.c (working copy) @@ -101,6 +101,12 @@ GdkDragContext *_gdk_quartz_drag_source_context = NULL; +GdkDragContext* +gdk_quartz_drag_source_context() +{ + return _gdk_quartz_drag_source_context; +} + GdkDragContext * gdk_drag_begin (GdkWindow *window, GList *targets) Index: gdk/quartz/GdkQuartzWindow.c =================================================================== --- gdk/quartz/GdkQuartzWindow.c (revision 21770) +++ gdk/quartz/GdkQuartzWindow.c (working copy) @@ -461,8 +461,29 @@ { GdkDragAction result = 0; + /* GDK and Quartz drag operations do not map 1:1. + This mapping represents about the best that we + can come up. + + Note that NSDragOperationPrivate and GDK_ACTION_PRIVATE + have almost opposite meanings: the GDK one means that the + destination is solely responsible for the action; the Quartz + one means that the source and destination will agree + privately on the action. NSOperationGeneric is close in meaning + to GDK_ACTION_PRIVATE but there is a problem: it will be + sent for any ordinary drag, and likely not understood + by any intra-widget drag (since the source & dest are the + same) + */ + if (operation & NSDragOperationGeneric) + result |= GDK_ACTION_MOVE; + if (operation & NSDragOperationCopy) result |= GDK_ACTION_COPY; + if (operation & NSDragOperationMove) + result |= GDK_ACTION_MOVE; + if (operation & NSDragOperationLink) + result |= GDK_ACTION_LINK; return result; } @@ -474,6 +495,10 @@ if (action & GDK_ACTION_COPY) result |= NSDragOperationCopy; + if (action & GDK_ACTION_LINK) + result |= NSDragOperationLink; + if (action & GDK_ACTION_MOVE) + result |= NSDragOperationMove; return result; } @@ -485,6 +510,7 @@ GDK_DRAG_CONTEXT_PRIVATE (current_context)->dragging_info = sender; current_context->suggested_action = drag_operation_to_drag_action ([sender draggingSourceOperationMask]); + current_context->actions = current_context->suggested_action; } - (NSDragOperation)draggingEntered:(id )sender @@ -510,6 +536,10 @@ - (void)draggingEnded:(id )sender { + /* leave a note for the source about what action was taken */ + if (_gdk_quartz_drag_source_context && current_context) + _gdk_quartz_drag_source_context->action = current_context->action; + if (current_context) g_object_unref (current_context); current_context = NULL;