Bug 626499 - GtkClipboard unnotified on change of OS X pasteboard owner

pasteboardChangedOwner is not called as reliably as we'd want to get it,
so keep track of [pasteboard changeCount] and drop clipboard ownership
when a change happened. Also better unset the clipboard content redundantly
in a few places rather than missing one, and reorder the code in
gtk_clipboard_set_contents() so that the new aggressive unsetting
won't unset the clipboard under our feet when we call
[pasteboard declareTypes].
(cherry picked from commit f2b74db5dc)
This commit is contained in:
Michael Natterer 2012-12-04 14:31:13 +01:00
parent c74d79bb55
commit f08fc12741

View File

@ -45,6 +45,7 @@ struct _GtkClipboard
GObject parent_instance; GObject parent_instance;
NSPasteboard *pasteboard; NSPasteboard *pasteboard;
NSInteger change_count;
GdkAtom selection; GdkAtom selection;
@ -76,13 +77,18 @@ struct _GtkClipboardClass
GdkEventOwnerChange *event); GdkEventOwnerChange *event);
}; };
static void gtk_clipboard_class_init (GtkClipboardClass *class);
static void gtk_clipboard_finalize (GObject *object);
static void gtk_clipboard_owner_change (GtkClipboard *clipboard,
GdkEventOwnerChange *event);
static void clipboard_unset (GtkClipboard *clipboard);
static GtkClipboard *clipboard_peek (GdkDisplay *display,
GdkAtom selection,
gboolean only_if_exists);
@interface GtkClipboardOwner : NSObject { @interface GtkClipboardOwner : NSObject {
GtkClipboard *clipboard; GtkClipboard *clipboard;
GtkClipboardGetFunc get_func;
GtkClipboardClearFunc clear_func;
gpointer user_data;
} }
@end @end
@ -117,10 +123,15 @@ struct _GtkClipboardClass
} }
} }
/* pasteboardChangedOwner is not called immediately, and it's not called
* reliably. It is somehow documented in the apple api docs, but the docs
* suck and don't really give clear instructions. Therefore we track
* changeCount in several places below and clear the clipboard if it
* changed.
*/
- (void)pasteboardChangedOwner:(NSPasteboard *)sender - (void)pasteboardChangedOwner:(NSPasteboard *)sender
{ {
if (clear_func) clipboard_unset (clipboard);
clear_func (clipboard, user_data);
[self release]; [self release];
} }
@ -139,15 +150,6 @@ struct _GtkClipboardClass
@end @end
static void gtk_clipboard_class_init (GtkClipboardClass *class);
static void gtk_clipboard_finalize (GObject *object);
static void gtk_clipboard_owner_change (GtkClipboard *clipboard,
GdkEventOwnerChange *event);
static void clipboard_unset (GtkClipboard *clipboard);
static GtkClipboard *clipboard_peek (GdkDisplay *display,
GdkAtom selection,
gboolean only_if_exists);
static const gchar clipboards_owned_key[] = "gtk-clipboards-owned"; static const gchar clipboards_owned_key[] = "gtk-clipboards-owned";
static GQuark clipboards_owned_key_id = 0; static GQuark clipboards_owned_key_id = 0;
@ -360,6 +362,15 @@ gtk_clipboard_set_contents (GtkClipboard *clipboard,
} }
} }
/* call declareTypes before setting the clipboard members because
* declareTypes might clear the clipboard
*/
types = _gtk_quartz_target_entries_to_pasteboard_types (targets, n_targets);
clipboard->change_count = [clipboard->pasteboard declareTypes: [types allObjects]
owner: owner];
[types release];
[pool release];
clipboard->user_data = user_data; clipboard->user_data = user_data;
clipboard->have_owner = have_owner; clipboard->have_owner = have_owner;
if (have_owner) if (have_owner)
@ -371,12 +382,6 @@ gtk_clipboard_set_contents (GtkClipboard *clipboard,
gtk_target_list_unref (clipboard->target_list); gtk_target_list_unref (clipboard->target_list);
clipboard->target_list = gtk_target_list_new (targets, n_targets); clipboard->target_list = gtk_target_list_new (targets, n_targets);
types = _gtk_quartz_target_entries_to_pasteboard_types (targets, n_targets);
[clipboard->pasteboard declareTypes:[types allObjects] owner:owner];
[types release];
[pool release];
return TRUE; return TRUE;
} }
@ -420,6 +425,12 @@ gtk_clipboard_get_owner (GtkClipboard *clipboard)
{ {
g_return_val_if_fail (clipboard != NULL, NULL); g_return_val_if_fail (clipboard != NULL, NULL);
if (clipboard->change_count < [clipboard->pasteboard changeCount])
{
clipboard_unset (clipboard);
clipboard->change_count = [clipboard->pasteboard changeCount];
}
if (clipboard->have_owner) if (clipboard->have_owner)
return clipboard->user_data; return clipboard->user_data;
else else
@ -473,6 +484,8 @@ clipboard_unset (GtkClipboard *clipboard)
void void
gtk_clipboard_clear (GtkClipboard *clipboard) gtk_clipboard_clear (GtkClipboard *clipboard)
{ {
clipboard_unset (clipboard);
[clipboard->pasteboard declareTypes:nil owner:nil]; [clipboard->pasteboard declareTypes:nil owner:nil];
} }
@ -656,6 +669,12 @@ gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GtkSelectionData *selection_data = NULL; GtkSelectionData *selection_data = NULL;
if (clipboard->change_count < [clipboard->pasteboard changeCount])
{
clipboard_unset (clipboard);
clipboard->change_count = [clipboard->pasteboard changeCount];
}
if (target == gdk_atom_intern_static_string ("TARGETS")) if (target == gdk_atom_intern_static_string ("TARGETS"))
{ {
NSArray *types = [clipboard->pasteboard types]; NSArray *types = [clipboard->pasteboard types];