xwin: Use WM_CLIPBOARDUPDATE clipboard API

Windows Vista and later have a saner clipboard API where the clipboard
viewer linked list is no longer maintained by applications.  Use it
where available.

Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
This commit is contained in:
Jon Turney 2014-10-18 17:31:57 +01:00 committed by Adam Jackson
parent de7f1fd6f8
commit 008efebda8
3 changed files with 87 additions and 39 deletions

View File

@ -77,6 +77,14 @@ typedef struct
Atom atomTargets; Atom atomTargets;
} ClipboardAtoms; } ClipboardAtoms;
/* Modern clipboard API functions */
typedef wBOOL WINAPI (*ADDCLIPBOARDFORMATLISTENERPROC)(HWND hwnd);
typedef wBOOL WINAPI (*REMOVECLIPBOARDFORMATLISTENERPROC)(HWND hwnd);
extern Bool g_fHasModernClipboardApi;
extern ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener;
extern REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener;
/* /*
* winclipboardwndproc.c * winclipboardwndproc.c
*/ */

View File

@ -84,6 +84,10 @@ static pthread_t g_winClipboardProcThread;
int xfixes_event_base; int xfixes_event_base;
int xfixes_error_base; int xfixes_error_base;
Bool g_fHasModernClipboardApi = FALSE;
ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener;
REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener;
/* /*
* Local function prototypes * Local function prototypes
*/ */
@ -138,6 +142,11 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay)
ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); ErrorF("winClipboardProc - Warning: Locale not supported by X.\n");
} }
g_fpAddClipboardFormatListener = (ADDCLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"AddClipboardFormatListener");
g_fpRemoveClipboardFormatListener = (REMOVECLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"RemoveClipboardFormatListener");
g_fHasModernClipboardApi = g_fpAddClipboardFormatListener && g_fpRemoveClipboardFormatListener;
ErrorF("OS maintains clipboard viewer chain: %s\n", g_fHasModernClipboardApi ? "yes" : "no");
g_winClipboardProcThread = pthread_self(); g_winClipboardProcThread = pthread_self();
/* Set error handler */ /* Set error handler */

View File

@ -58,6 +58,9 @@
#define WIN_POLL_TIMEOUT 1 #define WIN_POLL_TIMEOUT 1
#ifndef WM_CLIPBOARDUPDATE
#define WM_CLIPBOARDUPDATE 0x031D
#endif
/* /*
* Process X events up to specified timeout * Process X events up to specified timeout
@ -151,8 +154,16 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
winDebug("winClipboardWindowProc - WM_DESTROY\n"); winDebug("winClipboardWindowProc - WM_DESTROY\n");
/* Remove ourselves from the clipboard chain */ if (g_fHasModernClipboardApi)
ChangeClipboardChain(hwnd, s_hwndNextViewer); {
/* Remove clipboard listener */
g_fpRemoveClipboardFormatListener(hwnd);
}
else
{
/* Remove ourselves from the clipboard chain */
ChangeClipboardChain(hwnd, s_hwndNextViewer);
}
s_hwndNextViewer = NULL; s_hwndNextViewer = NULL;
} }
@ -168,8 +179,6 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_CREATE: case WM_CREATE:
{ {
HWND first, next;
DWORD error_code = 0;
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams; ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
winDebug("winClipboardWindowProc - WM_CREATE\n"); winDebug("winClipboardWindowProc - WM_CREATE\n");
@ -179,16 +188,26 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
atoms = cwcp->atoms; atoms = cwcp->atoms;
fRunning = TRUE; fRunning = TRUE;
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ if (g_fHasModernClipboardApi)
if (first == hwnd) {
return 0; /* Make sure it's not us! */ g_fpAddClipboardFormatListener(hwnd);
/* Add ourselves to the clipboard viewer chain */ }
next = SetClipboardViewer(hwnd);
error_code = GetLastError();
if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */
s_hwndNextViewer = next; /* it returned must have been the first window in the chain */
else else
s_fCBCInitialized = FALSE; {
HWND first, next;
DWORD error_code = 0;
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */
if (first == hwnd)
return 0; /* Make sure it's not us! */
/* Add ourselves to the clipboard viewer chain */
next = SetClipboardViewer(hwnd);
error_code = GetLastError();
if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */
s_hwndNextViewer = next; /* it returned must have been the first window in the chain */
else
s_fCBCInitialized = FALSE;
}
} }
return 0; return 0;
@ -233,6 +252,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
winDebug("winClipboardWindowProc - WM_WM_REINIT: Enter\n"); winDebug("winClipboardWindowProc - WM_WM_REINIT: Enter\n");
if (g_fHasModernClipboardApi)
{
return 0;
}
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ first = GetClipboardViewer(); /* Get handle to first viewer in chain. */
if (first == hwnd) if (first == hwnd)
return 0; /* Make sure it's not us! */ return 0; /* Make sure it's not us! */
@ -257,38 +281,45 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
return 0; return 0;
case WM_DRAWCLIPBOARD: case WM_DRAWCLIPBOARD:
case WM_CLIPBOARDUPDATE:
{ {
static Bool s_fProcessingDrawClipboard = FALSE; static Bool s_fProcessingDrawClipboard = FALSE;
int iReturn; int iReturn;
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n"); if (message == WM_DRAWCLIPBOARD)
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n");
else
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n");
/* if (!g_fHasModernClipboardApi)
* We've occasionally seen a loop in the clipboard chain. {
* Try and fix it on the first hint of recursion. /*
*/ * We've occasionally seen a loop in the clipboard chain.
if (!s_fProcessingDrawClipboard) { * Try and fix it on the first hint of recursion.
s_fProcessingDrawClipboard = TRUE; */
} if (!s_fProcessingDrawClipboard) {
else { s_fProcessingDrawClipboard = TRUE;
/* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */ }
s_fCBCInitialized = FALSE; else {
ChangeClipboardChain(hwnd, s_hwndNextViewer); /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */
winFixClipboardChain(); s_fCBCInitialized = FALSE;
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - " ChangeClipboardChain(hwnd, s_hwndNextViewer);
"Nested calls detected. Re-initing.\n"); winFixClipboardChain();
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
s_fProcessingDrawClipboard = FALSE; "Nested calls detected. Re-initing.\n");
return 0; winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
} s_fProcessingDrawClipboard = FALSE;
return 0;
}
/* Bail on first message */ /* Bail on first message */
if (!s_fCBCInitialized) { if (!s_fCBCInitialized) {
s_fCBCInitialized = TRUE; s_fCBCInitialized = TRUE;
s_fProcessingDrawClipboard = FALSE; s_fProcessingDrawClipboard = FALSE;
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
return 0; return 0;
} }
}
/* /*
* NOTE: We cannot bail out when NULL == GetClipboardOwner () * NOTE: We cannot bail out when NULL == GetClipboardOwner ()