diff --git a/hw/xwin/winclipboard/internal.h b/hw/xwin/winclipboard/internal.h index 6c26caf2e..d0d8fbda1 100644 --- a/hw/xwin/winclipboard/internal.h +++ b/hw/xwin/winclipboard/internal.h @@ -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 */ diff --git a/hw/xwin/winclipboard/thread.c b/hw/xwin/winclipboard/thread.c index 50e1e8cb5..fa57ada80 100644 --- a/hw/xwin/winclipboard/thread.c +++ b/hw/xwin/winclipboard/thread.c @@ -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 */ diff --git a/hw/xwin/winclipboard/wndproc.c b/hw/xwin/winclipboard/wndproc.c index d17cf2e86..d289f7755 100644 --- a/hw/xwin/winclipboard/wndproc.c +++ b/hw/xwin/winclipboard/wndproc.c @@ -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 ()