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;
} 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
*/

View File

@ -84,6 +84,10 @@ static pthread_t g_winClipboardProcThread;
int xfixes_event_base;
int xfixes_error_base;
Bool g_fHasModernClipboardApi = FALSE;
ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener;
REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener;
/*
* Local function prototypes
*/
@ -138,6 +142,11 @@ winClipboardProc(Bool fUseUnicode, char *szDisplay)
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();
/* Set error handler */

View File

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