forked from AuroraMiddleware/gtk
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:
parent
da746d5169
commit
88707e6912
@ -75,7 +75,7 @@ enum_monitor (HMONITOR hmonitor,
|
||||
DWORD dwFlags;
|
||||
CHAR szDevice[CCHDEVICENAME];
|
||||
} MONITORINFOEXA2;
|
||||
|
||||
|
||||
MONITORINFOEXA2 monitor_info;
|
||||
HDC hDC;
|
||||
|
||||
@ -239,7 +239,7 @@ gdk_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;
|
||||
|
||||
@ -291,7 +291,7 @@ gint
|
||||
gdk_display_get_n_screens (GdkDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -323,20 +323,194 @@ gdk_display_get_default_group (GdkDisplay *display)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gboolean
|
||||
gdk_display_supports_selection_notification (GdkDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
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;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_display_request_selection_notification (GdkDisplay *display,
|
||||
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;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -354,7 +528,7 @@ gdk_display_store_clipboard (GdkDisplay *display,
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
gboolean
|
||||
gdk_display_supports_shapes (GdkDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
@ -362,7 +536,7 @@ gdk_display_supports_shapes (GdkDisplay *display)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gboolean
|
||||
gdk_display_supports_input_shapes (GdkDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
|
@ -94,7 +94,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
|
||||
@ -194,7 +193,7 @@ generate_focus_event (GdkWindow *window,
|
||||
event->focus_change.window = window;
|
||||
event->focus_change.in = in;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -210,7 +209,7 @@ generate_grab_broken_event (GdkWindow *window,
|
||||
event->grab_broken.implicit = FALSE;
|
||||
event->grab_broken.grab_window = grab_window;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
|
||||
static LRESULT
|
||||
@ -984,8 +983,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;
|
||||
|
||||
@ -1231,7 +1230,7 @@ synthesize_enter_or_leave_event (GdkWindow *window,
|
||||
event->crossing.focus = TRUE; /* FIXME: Set correctly */
|
||||
event->crossing.state = 0; /* FIXME: Set correctly */
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
if (type == GDK_ENTER_NOTIFY &&
|
||||
((GdkWindowObject *) window)->extension_events != 0)
|
||||
@ -1276,7 +1275,7 @@ synthesize_expose_events (GdkWindow *window)
|
||||
event->expose.region = gdk_region_rectangle (&(event->expose.area));
|
||||
event->expose.count = 0;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
GDI_CALL (ReleaseDC, (impl->handle, hdc));
|
||||
}
|
||||
@ -1495,7 +1494,7 @@ handle_configure_event (MSG *msg,
|
||||
event->configure.x = point.x;
|
||||
event->configure.y = point.y;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1713,7 +1712,7 @@ generate_button_event (GdkEventType type,
|
||||
event->button.button = button;
|
||||
event->button.device = _gdk_display->core_pointer;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
if (type == GDK_BUTTON_PRESS)
|
||||
_gdk_event_button_generate (_gdk_display, event);
|
||||
@ -2148,7 +2147,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;
|
||||
@ -2221,7 +2220,7 @@ gdk_event_translate (MSG *msg,
|
||||
event->key.window = window;
|
||||
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
|
||||
if (((GdkWindowObject *) window)->event_mask & GDK_KEY_RELEASE_MASK)
|
||||
@ -2231,7 +2230,7 @@ gdk_event_translate (MSG *msg,
|
||||
event->key.window = window;
|
||||
build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
}
|
||||
return_val = TRUE;
|
||||
@ -2356,7 +2355,7 @@ gdk_event_translate (MSG *msg,
|
||||
event->motion.is_hint = FALSE;
|
||||
event->motion.device = _gdk_display->core_pointer;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
return_val = TRUE;
|
||||
break;
|
||||
@ -2427,7 +2426,7 @@ gdk_event_translate (MSG *msg,
|
||||
event->scroll.state = build_pointer_event_state (msg);
|
||||
event->scroll.device = _gdk_display->core_pointer;
|
||||
|
||||
append_event (event);
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
return_val = TRUE;
|
||||
break;
|
||||
@ -2627,7 +2626,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)
|
||||
{
|
||||
@ -3097,7 +3096,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 (GDK_WINDOW_OBJECT (window)->impl);
|
||||
|
||||
@ -3129,7 +3128,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;
|
||||
@ -3145,7 +3144,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
|
||||
{
|
||||
@ -3165,7 +3164,7 @@ gdk_event_translate (MSG *msg,
|
||||
}
|
||||
|
||||
/* We need to render to clipboard immediately, don't call
|
||||
* append_event()
|
||||
* _gdk_win32_append_event()
|
||||
*/
|
||||
if (_gdk_event_func)
|
||||
{
|
||||
@ -3281,7 +3280,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);
|
||||
|
||||
|
@ -490,6 +490,9 @@ HICON _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf,
|
||||
gint y_hotspot);
|
||||
gboolean _gdk_win32_pixbuf_to_hicon_supports_alpha (void);
|
||||
|
||||
void _gdk_win32_append_event (GdkEvent *event);
|
||||
|
||||
|
||||
/* Initialization */
|
||||
void _gdk_windowing_window_init (GdkScreen *screen);
|
||||
void _gdk_root_window_size_init (void);
|
||||
|
Loading…
Reference in New Issue
Block a user