win32: resurect Windows clipboard selection notification

This is a rewrite of e6fa7394ba, with
misc fixes that should help with some bugs Tim was talking about.

https://bugzilla.gnome.org/show_bug.cgi?id=652239
This commit is contained in:
Marc-André Lureau 2011-06-09 20:45:20 +02:00 committed by Alexander Larsson
parent db19fbd45c
commit 1afc29d869
3 changed files with 200 additions and 26 deletions

View File

@ -79,7 +79,7 @@ enum_monitor (HMONITOR hmonitor,
DWORD dwFlags;
CHAR szDevice[CCHDEVICENAME];
} MONITORINFOEXA2;
MONITORINFOEXA2 monitor_info;
HDC hDC;
@ -252,7 +252,7 @@ gdk_win32_display_get_name (GdkDisplay *display)
PFN_ProcessIdToSessionId processIdToSessionId;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
if (display_name_cache != NULL)
return display_name_cache;
@ -304,7 +304,7 @@ static gint
gdk_win32_display_get_n_screens (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
return 1;
}
@ -341,15 +341,189 @@ gdk_win32_display_supports_selection_notification (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
return FALSE;
return TRUE;
}
static HWND _hwnd_next_viewer = NULL;
static int debug_indent = 0;
/*
* maybe this should be integrated with the default message loop - or maybe not ;-)
*/
static LRESULT CALLBACK
inner_clipboard_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
switch (message)
{
case WM_DESTROY: /* remove us from chain */
{
ChangeClipboardChain (hwnd, _hwnd_next_viewer);
PostQuitMessage (0);
return 0;
}
case WM_CHANGECBCHAIN:
{
HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
HWND hwndNext = (HWND) lparam; /* handle of next window in chain */
if (hwndRemove == _hwnd_next_viewer)
_hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
else if (_hwnd_next_viewer != NULL)
return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
return 0;
}
#ifdef WM_CLIPBOARDUPDATE
case WM_CLIPBOARDUPDATE:
#endif
case WM_DRAWCLIPBOARD:
{
int success;
HWND hwndOwner;
UINT nFormat = 0;
GdkEvent *event;
GdkWindow *owner;
success = OpenClipboard (hwnd);
g_return_val_if_fail (success, 0);
hwndOwner = GetClipboardOwner ();
owner = gdk_win32_window_lookup_for_display (_gdk_display, hwndOwner);
if (owner == NULL)
owner = gdk_win32_window_foreign_new_for_display (_gdk_display, hwndOwner);
GDK_NOTE (DND, g_print (" drawclipboard owner: %p", hwndOwner));
if (_gdk_debug_flags & GDK_DEBUG_DND)
{
while ((nFormat = EnumClipboardFormats (nFormat)) != 0)
g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
}
GDK_NOTE (DND, g_print (" \n"));
event = gdk_event_new (GDK_OWNER_CHANGE);
event->owner_change.window = _gdk_root;
event->owner_change.owner = owner;
event->owner_change.reason = GDK_OWNER_CHANGE_NEW_OWNER;
event->owner_change.selection = GDK_SELECTION_CLIPBOARD;
event->owner_change.time = _gdk_win32_get_next_tick (0);
event->owner_change.selection_time = GDK_CURRENT_TIME;
_gdk_win32_append_event (event);
CloseClipboard ();
if (_hwnd_next_viewer != NULL)
return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
/* clear error to avoid confusing SetClipboardViewer() return */
SetLastError (0);
return 0;
}
default:
/* Otherwise call DefWindowProcW(). */
GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
return DefWindowProc (hwnd, message, wparam, lparam);
}
}
static LRESULT CALLBACK
_clipboard_window_procedure (HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
LRESULT retval;
GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
(debug_indent > 0 ? "\n" : ""),
debug_indent, "",
_gdk_win32_message_to_string (message), hwnd));
debug_indent += 2;
retval = inner_clipboard_window_procedure (hwnd, message, wparam, lparam);
debug_indent -= 2;
GDK_NOTE (EVENTS, g_print (" => %I64d%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
return retval;
}
/*
* Creates a hidden window and adds it to the clipboard chain
*/
static HWND
_gdk_win32_register_clipboard_notification (void)
{
WNDCLASS wclass = { 0, };
HWND hwnd;
ATOM klass;
wclass.lpszClassName = "GdkClipboardNotification";
wclass.lpfnWndProc = _clipboard_window_procedure;
wclass.hInstance = _gdk_app_hmodule;
klass = RegisterClass (&wclass);
if (!klass)
return NULL;
hwnd = CreateWindow (MAKEINTRESOURCE (klass),
NULL, WS_POPUP,
0, 0, 0, 0, NULL, NULL,
_gdk_app_hmodule, NULL);
if (!hwnd)
goto failed;
SetLastError (0);
_hwnd_next_viewer = SetClipboardViewer (hwnd);
if (_hwnd_next_viewer == NULL && GetLastError() != 0)
goto failed;
/* FIXME: http://msdn.microsoft.com/en-us/library/ms649033(v=VS.85).aspx */
/* This is only supported by Vista, and not yet by mingw64 */
/* if (AddClipboardFormatListener (hwnd) == FALSE) */
/* goto failed; */
return hwnd;
failed:
g_critical ("Failed to install clipboard viewer");
UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
return NULL;
}
static gboolean
gdk_win32_display_request_selection_notification (GdkDisplay *display,
GdkAtom selection)
GdkAtom selection)
{
return FALSE;
static HWND hwndViewer = NULL;
gboolean ret = FALSE;
GDK_NOTE (DND,
g_print ("gdk_display_request_selection_notification (..., %s)",
gdk_atom_name (selection)));
if (selection == GDK_SELECTION_CLIPBOARD ||
selection == GDK_SELECTION_PRIMARY)
{
if (!hwndViewer)
{
hwndViewer = _gdk_win32_register_clipboard_notification ();
GDK_NOTE (DND, g_print (" registered"));
}
ret = (hwndViewer != NULL);
}
else
{
GDK_NOTE (DND, g_print (" unsupported"));
ret = FALSE;
}
GDK_NOTE (DND, g_print (" -> %s\n", ret ? "TRUE" : "FALSE"));
return ret;
}
static gboolean

View File

@ -100,7 +100,6 @@ static gboolean gdk_event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void append_event (GdkEvent *event);
static gboolean is_modally_blocked (GdkWindow *window);
/* Private variable declarations
@ -206,7 +205,7 @@ generate_focus_event (GdkDeviceManager *device_manager,
event->focus_change.in = in;
gdk_event_set_device (event, device);
append_event (event);
_gdk_win32_append_event (event);
}
static void
@ -230,7 +229,7 @@ generate_grab_broken_event (GdkDeviceManager *device_manager,
event->grab_broken.grab_window = grab_window;
gdk_event_set_device (event, device);
append_event (event);
_gdk_win32_append_event (event);
}
static LRESULT
@ -895,8 +894,8 @@ fixup_event (GdkEvent *event)
event->any.send_event = InSendMessage ();
}
static void
append_event (GdkEvent *event)
void
_gdk_win32_append_event (GdkEvent *event)
{
GList *link;
@ -1164,13 +1163,13 @@ synthesize_enter_or_leave_event (GdkWindow *window,
event->crossing.state = 0; /* FIXME: Set correctly */
gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
_gdk_win32_append_event (event);
if (type == GDK_ENTER_NOTIFY &&
window->extension_events != 0)
_gdk_device_wintab_update_window_coords (window);
}
/* The check_extended flag controls whether to check if the windows want
* events from extended input devices and if the message should be skipped
* because an extended input device is active
@ -1329,7 +1328,7 @@ handle_configure_event (MSG *msg,
event->configure.x = point.x;
event->configure.y = point.y;
append_event (event);
_gdk_win32_append_event (event);
}
}
@ -1547,7 +1546,7 @@ generate_button_event (GdkEventType type,
event->button.button = button;
gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
_gdk_win32_append_event (event);
}
static void
@ -1982,7 +1981,7 @@ gdk_event_translate (MSG *msg,
if (msg->wParam == VK_MENU)
event->key.state &= ~GDK_MOD1_MASK;
append_event (event);
_gdk_win32_append_event (event);
return_val = TRUE;
break;
@ -2057,7 +2056,7 @@ gdk_event_translate (MSG *msg,
gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
append_event (event);
_gdk_win32_append_event (event);
}
if (window->event_mask & GDK_KEY_RELEASE_MASK)
@ -2068,7 +2067,7 @@ gdk_event_translate (MSG *msg,
gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
append_event (event);
_gdk_win32_append_event (event);
}
}
return_val = TRUE;
@ -2193,7 +2192,7 @@ gdk_event_translate (MSG *msg,
event->motion.is_hint = FALSE;
gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
_gdk_win32_append_event (event);
return_val = TRUE;
break;
@ -2264,7 +2263,7 @@ gdk_event_translate (MSG *msg,
event->scroll.state = build_pointer_event_state (msg);
gdk_event_set_device (event, _gdk_display->core_pointer);
append_event (event);
_gdk_win32_append_event (event);
return_val = TRUE;
break;
@ -2424,7 +2423,7 @@ gdk_event_translate (MSG *msg,
event = gdk_event_new (msg->wParam ? GDK_MAP : GDK_UNMAP);
event->any.window = window;
append_event (event);
_gdk_win32_append_event (event);
if (event->any.type == GDK_UNMAP)
{
@ -2894,7 +2893,7 @@ gdk_event_translate (MSG *msg,
event = gdk_event_new (GDK_DELETE);
event->any.window = window;
append_event (event);
_gdk_win32_append_event (event);
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
@ -2926,7 +2925,7 @@ gdk_event_translate (MSG *msg,
event = gdk_event_new (GDK_DESTROY);
event->any.window = window;
append_event (event);
_gdk_win32_append_event (event);
return_val = TRUE;
break;
@ -2942,7 +2941,7 @@ gdk_event_translate (MSG *msg,
event->selection.window = window;
event->selection.selection = GDK_SELECTION_CLIPBOARD;
event->selection.time = _gdk_win32_get_next_tick (msg->time);
append_event (event);
_gdk_win32_append_event (event);
}
else
{
@ -2962,7 +2961,7 @@ gdk_event_translate (MSG *msg,
}
/* We need to render to clipboard immediately, don't call
* append_event()
* _gdk_win32_append_event()
*/
event = gdk_event_new (GDK_SELECTION_REQUEST);
event->selection.window = window;
@ -3075,7 +3074,7 @@ gdk_event_translate (MSG *msg,
g_object_ref (window);
if (_gdk_input_other_event (event, msg, window))
append_event (event);
_gdk_win32_append_event (event);
else
gdk_event_free (event);

View File

@ -493,6 +493,7 @@ GdkAtom _gdk_win32_display_manager_atom_intern (GdkDisplayManager *manager,
gint only_if_exists);
gchar *_gdk_win32_display_manager_get_atom_name (GdkDisplayManager *manager,
GdkAtom atom);
void _gdk_win32_append_event (GdkEvent *event);
/* Initialization */
void _gdk_win32_windowing_init (void);