Commit 9f51dfde authored by Jon Turney's avatar Jon Turney

hw/xwin: Remove support for pre-Vista Win32 clipboard API

The original Win32 clipboard API is widely regarded as terrible, since
it relies on clients co-operatively managing the clipboard viewer chain,
and a single buggy client can break it for all other clients.

The last Windows version only supporting that API was Windows XP (5.1),
EOLed in 2014.

(This requires MinGW-w64 w32api 6.0.0 or later for
Add/RemoveClipboardListener correctly exported by the x86_64 user32
implib)
parent 9a4b6279
......@@ -42,7 +42,6 @@
#define WIN_XEVENTS_NOTIFY_DATA 3
#define WIN_XEVENTS_NOTIFY_TARGETS 4
#define WM_WM_REINIT (WM_USER + 1)
#define WM_WM_QUIT (WM_USER + 2)
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
......@@ -79,14 +78,6 @@ typedef struct
Atom atomIncr;
} 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
*/
......
......@@ -84,10 +84,6 @@ 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
*/
......@@ -142,11 +138,6 @@ 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 */
......@@ -506,11 +497,3 @@ winClipboardWindowDestroy(void)
SendMessage(g_hwndClipboard, WM_WM_QUIT, 0, 0);
}
}
void
winFixClipboardChain(void)
{
if (g_hwndClipboard) {
PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0);
}
}
......@@ -30,6 +30,8 @@
* Colin Harrison
*/
#define WINVER 0x0600
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
......@@ -58,10 +60,6 @@
#define WIN_POLL_TIMEOUT 1
#ifndef WM_CLIPBOARDUPDATE
#define WM_CLIPBOARDUPDATE 0x031D
#endif
/*
* Process X events up to specified timeout
*/
......@@ -138,8 +136,6 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND s_hwndNextViewer;
static Bool s_fCBCInitialized;
static Display *pDisplay;
static Window iWindow;
static ClipboardAtoms *atoms;
......@@ -151,18 +147,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
winDebug("winClipboardWindowProc - WM_DESTROY\n");
if (g_fHasModernClipboardApi)
{
/* Remove clipboard listener */
g_fpRemoveClipboardFormatListener(hwnd);
}
else
{
/* Remove ourselves from the clipboard chain */
ChangeClipboardChain(hwnd, s_hwndNextViewer);
}
s_hwndNextViewer = NULL;
/* Remove clipboard listener */
RemoveClipboardFormatListener(hwnd);
}
return 0;
......@@ -185,138 +171,15 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
atoms = cwcp->atoms;
fRunning = TRUE;
if (g_fHasModernClipboardApi)
{
g_fpAddClipboardFormatListener(hwnd);
}
else
{
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;
case WM_CHANGECBCHAIN:
{
winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: wParam(%p) "
"lParam(%p) s_hwndNextViewer(%p)\n",
(HWND)wParam, (HWND)lParam, s_hwndNextViewer);
if ((HWND) wParam == s_hwndNextViewer) {
s_hwndNextViewer = (HWND) lParam;
if (s_hwndNextViewer == hwnd) {
s_hwndNextViewer = NULL;
ErrorF("winClipboardWindowProc - WM_CHANGECBCHAIN: "
"attempted to set next window to ourselves.");
}
}
else if (s_hwndNextViewer)
SendMessage(s_hwndNextViewer, message, wParam, lParam);
}
winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: Exit\n");
return 0;
case WM_WM_REINIT:
{
/* Ensure that we're in the clipboard chain. Some apps,
* WinXP's remote desktop for one, don't play nice with the
* chain. This message is called whenever we receive a
* WM_ACTIVATEAPP message to ensure that we continue to
* receive clipboard messages.
*
* It might be possible to detect if we're still in the chain
* by calling SendMessage (GetClipboardViewer(),
* WM_DRAWCLIPBOARD, 0, 0); and then seeing if we get the
* WM_DRAWCLIPBOARD message. That, however, might be more
* expensive than just putting ourselves back into the chain.
*/
HWND first, next;
DWORD error_code = 0;
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! */
winDebug(" WM_WM_REINIT: Replacing us(%p) with %p at head "
"of chain\n", hwnd, s_hwndNextViewer);
s_fCBCInitialized = FALSE;
ChangeClipboardChain(hwnd, s_hwndNextViewer);
s_hwndNextViewer = NULL;
s_fCBCInitialized = FALSE;
winDebug(" WM_WM_REINIT: Putting us back at head of chain.\n");
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */
if (first == hwnd)
return 0; /* Make sure it's not us! */
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;
AddClipboardFormatListener(hwnd);
}
winDebug("winClipboardWindowProc - WM_WM_REINIT: Exit\n");
return 0;
case WM_DRAWCLIPBOARD:
case WM_CLIPBOARDUPDATE:
{
static Bool s_fProcessingDrawClipboard = FALSE;
int iReturn;
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.
*/
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;
}
}
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n");
/*
* NOTE: We cannot bail out when NULL == GetClipboardOwner ()
......@@ -329,12 +192,10 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Bail when we still own the clipboard */
if (hwnd == GetClipboardOwner()) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"We own the clipboard, returning.\n");
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
s_fProcessingDrawClipboard = FALSE;
if (s_hwndNextViewer)
SendMessage(s_hwndNextViewer, message, wParam, lParam);
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
}
......@@ -350,7 +211,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
if (!IsClipboardFormatAvailable(CF_TEXT)
&& !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Clipboard does not contain CF_TEXT nor "
"CF_UNICODETEXT.\n");
......@@ -365,31 +226,29 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Release PRIMARY selection if owned */
iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"PRIMARY selection is owned by us.\n");
XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"XGetSelectionOwner failed for PRIMARY: %d\n",
iReturn);
/* Release CLIPBOARD selection if owned */
iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"CLIPBOARD selection is owned by us, releasing\n");
XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"XGetSelectionOwner failed for CLIPBOARD: %d\n",
iReturn);
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
s_fProcessingDrawClipboard = FALSE;
if (s_hwndNextViewer)
SendMessage(s_hwndNextViewer, message, wParam, lParam);
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
}
......@@ -398,11 +257,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
XA_PRIMARY, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Could not reassert ownership of PRIMARY\n");
}
else {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Reasserted ownership of PRIMARY\n");
}
......@@ -412,33 +271,28 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Could not reassert ownership of CLIPBOARD\n");
}
else {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Reasserted ownership of CLIPBOARD\n");
}
/* Flush the pending SetSelectionOwner event now */
XFlush(pDisplay);
s_fProcessingDrawClipboard = FALSE;
}
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
/* Pass the message on the next window in the clipboard viewer chain */
if (s_hwndNextViewer)
SendMessage(s_hwndNextViewer, message, wParam, lParam);
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
case WM_DESTROYCLIPBOARD:
/*
* NOTE: Intentionally do nothing.
* Changes in the Win32 clipboard are handled by WM_DRAWCLIPBOARD
* Changes in the Win32 clipboard are handled by WM_CLIPBOARDUPDATE
* above. We only process this message to conform to the specs
* for delayed clipboard rendering in Win32. You might think
* that we need to release ownership of the X11 selections, but
* we do not, because a WM_DRAWCLIPBOARD message will closely
* we do not, because a WM_CLIPBOARDUPDATE message will closely
* follow this message and reassert ownership of the X11
* selections, handling the issue for us.
*/
......
......@@ -1113,9 +1113,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
ShowCursor(TRUE);
}
/* Make sure the clipboard chain is ok. */
winFixClipboardChain();
/* Call engine specific screen activation/deactivation function */
(*s_pScreenPriv->pwinActivateApp) (s_pScreen);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment