628 lines
22 KiB
C
628 lines
22 KiB
C
/*
|
|
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
|
*Copyright (C) Colin Harrison 2005-2008
|
|
*
|
|
*Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
*"Software"), to deal in the Software without restriction, including
|
|
*without limitation the rights to use, copy, modify, merge, publish,
|
|
*distribute, sublicense, and/or sell copies of the Software, and to
|
|
*permit persons to whom the Software is furnished to do so, subject to
|
|
*the following conditions:
|
|
*
|
|
*The above copyright notice and this permission notice shall be
|
|
*included in all copies or substantial portions of the Software.
|
|
*
|
|
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
|
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*Except as contained in this notice, the name of the copyright holder(s)
|
|
*and author(s) shall not be used in advertising or otherwise to promote
|
|
*the sale, use or other dealings in this Software without prior written
|
|
*authorization from the copyright holder(s) and author(s).
|
|
*
|
|
* Authors: Harold L Hunt II
|
|
* Colin Harrison
|
|
*/
|
|
|
|
#ifdef HAVE_XWIN_CONFIG_H
|
|
#include <xwin-config.h>
|
|
#endif
|
|
|
|
/*
|
|
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
|
|
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
|
|
* So let's undef that macro if necessary.
|
|
*/
|
|
#ifdef _XSERVER64
|
|
#undef _XSERVER64
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <limits.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include "internal.h"
|
|
#include "winclipboard.h"
|
|
|
|
/*
|
|
* Constants
|
|
*/
|
|
|
|
#define WIN_POLL_TIMEOUT 1
|
|
|
|
#ifndef WM_CLIPBOARDUPDATE
|
|
#define WM_CLIPBOARDUPDATE 0x031D
|
|
#endif
|
|
|
|
/*
|
|
* Process X events up to specified timeout
|
|
*/
|
|
|
|
static int
|
|
winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
|
|
ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec)
|
|
{
|
|
int iConnNumber;
|
|
struct timeval tv;
|
|
int iReturn;
|
|
DWORD dwStopTime = GetTickCount() + iTimeoutSec * 1000;
|
|
|
|
winDebug("winProcessXEventsTimeout () - pumping X events for %d seconds\n",
|
|
iTimeoutSec);
|
|
|
|
/* Get our connection number */
|
|
iConnNumber = ConnectionNumber(pDisplay);
|
|
|
|
/* Loop for X events */
|
|
while (1) {
|
|
fd_set fdsRead;
|
|
long remainingTime;
|
|
|
|
/* Process X events */
|
|
iReturn = winClipboardFlushXEvents(hwnd, iWindow, pDisplay, data, atoms);
|
|
|
|
winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn);
|
|
|
|
if ((WIN_XEVENTS_NOTIFY_DATA == iReturn) || (WIN_XEVENTS_NOTIFY_TARGETS == iReturn) || (WIN_XEVENTS_FAILED == iReturn)) {
|
|
/* Bail out */
|
|
return iReturn;
|
|
}
|
|
|
|
/* We need to ensure that all pending requests are sent */
|
|
XFlush(pDisplay);
|
|
|
|
/* Setup the file descriptor set */
|
|
FD_ZERO(&fdsRead);
|
|
FD_SET(iConnNumber, &fdsRead);
|
|
|
|
/* Adjust timeout */
|
|
remainingTime = dwStopTime - GetTickCount();
|
|
tv.tv_sec = remainingTime / 1000;
|
|
tv.tv_usec = (remainingTime % 1000) * 1000;
|
|
winDebug("winProcessXEventsTimeout () - %ld milliseconds left\n",
|
|
remainingTime);
|
|
|
|
/* Break out if no time left */
|
|
if (remainingTime <= 0)
|
|
return WIN_XEVENTS_SUCCESS;
|
|
|
|
/* Wait for an X event */
|
|
iReturn = select(iConnNumber + 1, /* Highest fds number */
|
|
&fdsRead, /* Read mask */
|
|
NULL, /* No write mask */
|
|
NULL, /* No exception mask */
|
|
&tv); /* Timeout */
|
|
if (iReturn < 0) {
|
|
ErrorF("winProcessXEventsTimeout - Call to select () failed: %d. "
|
|
"Bailing.\n", iReturn);
|
|
break;
|
|
}
|
|
|
|
if (!FD_ISSET(iConnNumber, &fdsRead)) {
|
|
winDebug("winProcessXEventsTimeout - Spurious wake, select() returned %d\n", iReturn);
|
|
}
|
|
}
|
|
|
|
return WIN_XEVENTS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Process a given Windows message
|
|
*/
|
|
|
|
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;
|
|
static Bool fRunning;
|
|
|
|
/* Branch on message type */
|
|
switch (message) {
|
|
case WM_DESTROY:
|
|
{
|
|
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;
|
|
}
|
|
return 0;
|
|
|
|
case WM_WM_QUIT:
|
|
{
|
|
winDebug("winClipboardWindowProc - WM_WM_QUIT\n");
|
|
fRunning = FALSE;
|
|
PostQuitMessage(0);
|
|
}
|
|
return 0;
|
|
|
|
case WM_CREATE:
|
|
{
|
|
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
|
|
|
|
winDebug("winClipboardWindowProc - WM_CREATE\n");
|
|
|
|
pDisplay = cwcp->pClipboardDisplay;
|
|
iWindow = cwcp->iClipboardWindow;
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NOTE: We cannot bail out when NULL == GetClipboardOwner ()
|
|
* because some applications deal with the clipboard in a manner
|
|
* that causes the clipboard owner to be NULL when they are in
|
|
* fact taking ownership. One example of this is the Win32
|
|
* native compile of emacs.
|
|
*/
|
|
|
|
/* Bail when we still own the clipboard */
|
|
if (hwnd == GetClipboardOwner()) {
|
|
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"We own the clipboard, returning.\n");
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
|
|
s_fProcessingDrawClipboard = FALSE;
|
|
if (s_hwndNextViewer)
|
|
SendMessage(s_hwndNextViewer, message, wParam, lParam);
|
|
return 0;
|
|
}
|
|
|
|
/* Bail when shutting down */
|
|
if (!fRunning)
|
|
return 0;
|
|
|
|
/*
|
|
* Do not take ownership of the X11 selections when something
|
|
* other than CF_TEXT or CF_UNICODETEXT has been copied
|
|
* into the Win32 clipboard.
|
|
*/
|
|
if (!IsClipboardFormatAvailable(CF_TEXT)
|
|
&& !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
|
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"Clipboard does not contain CF_TEXT nor "
|
|
"CF_UNICODETEXT.\n");
|
|
|
|
/*
|
|
* We need to make sure that the X Server has processed
|
|
* previous XSetSelectionOwner messages.
|
|
*/
|
|
XSync(pDisplay, FALSE);
|
|
|
|
winDebug("winClipboardWindowProc - XSync done.\n");
|
|
|
|
/* Release PRIMARY selection if owned */
|
|
iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
|
|
if (iReturn == iWindow) {
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"PRIMARY selection is owned by us.\n");
|
|
XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
|
|
}
|
|
else if (BadWindow == iReturn || BadAtom == iReturn)
|
|
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"XGetSelectionOwner failed for PRIMARY: %d\n",
|
|
iReturn);
|
|
|
|
/* Release CLIPBOARD selection if owned */
|
|
iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
|
|
if (iReturn == iWindow) {
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"CLIPBOARD selection is owned by us, releasing\n");
|
|
XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
|
|
}
|
|
else if (BadWindow == iReturn || BadAtom == iReturn)
|
|
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"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);
|
|
return 0;
|
|
}
|
|
|
|
/* Reassert ownership of PRIMARY */
|
|
iReturn = XSetSelectionOwner(pDisplay,
|
|
XA_PRIMARY, iWindow, CurrentTime);
|
|
if (iReturn == BadAtom || iReturn == BadWindow ||
|
|
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
|
|
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"Could not reassert ownership of PRIMARY\n");
|
|
}
|
|
else {
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"Reasserted ownership of PRIMARY\n");
|
|
}
|
|
|
|
/* Reassert ownership of the CLIPBOARD */
|
|
iReturn = XSetSelectionOwner(pDisplay,
|
|
atoms->atomClipboard, iWindow, CurrentTime);
|
|
|
|
if (iReturn == BadAtom || iReturn == BadWindow ||
|
|
XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
|
|
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"Could not reassert ownership of CLIPBOARD\n");
|
|
}
|
|
else {
|
|
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
|
"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);
|
|
return 0;
|
|
|
|
case WM_DESTROYCLIPBOARD:
|
|
/*
|
|
* NOTE: Intentionally do nothing.
|
|
* Changes in the Win32 clipboard are handled by WM_DRAWCLIPBOARD
|
|
* 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
|
|
* follow this message and reassert ownership of the X11
|
|
* selections, handling the issue for us.
|
|
*/
|
|
winDebug("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n");
|
|
return 0;
|
|
|
|
case WM_RENDERALLFORMATS:
|
|
winDebug("winClipboardWindowProc - WM_RENDERALLFORMATS - Hello.\n");
|
|
|
|
/*
|
|
WM_RENDERALLFORMATS is sent as we are shutting down, to render the
|
|
clipboard so it's contents remains available to other applications.
|
|
|
|
Unfortunately, this can't work without major changes. The server is
|
|
already waiting for us to stop, so we can't ask for the rendering of
|
|
clipboard text now.
|
|
*/
|
|
|
|
return 0;
|
|
|
|
case WM_RENDERFORMAT:
|
|
{
|
|
int iReturn;
|
|
Bool fConvertToUnicode;
|
|
Bool pasted = FALSE;
|
|
Atom selection;
|
|
ClipboardConversionData data;
|
|
int best_target = 0;
|
|
|
|
winDebug("winClipboardWindowProc - WM_RENDERFORMAT %d - Hello.\n",
|
|
(int)wParam);
|
|
|
|
/* Flag whether to convert to Unicode or not */
|
|
fConvertToUnicode = (CF_UNICODETEXT == wParam);
|
|
|
|
selection = winClipboardGetLastOwnedSelectionAtom(atoms);
|
|
if (selection == None) {
|
|
ErrorF("winClipboardWindowProc - no monitored selection is owned\n");
|
|
goto fake_paste;
|
|
}
|
|
|
|
winDebug("winClipboardWindowProc - requesting targets for selection from owner\n");
|
|
|
|
/* Request the selection's supported conversion targets */
|
|
XConvertSelection(pDisplay,
|
|
selection,
|
|
atoms->atomTargets,
|
|
atoms->atomLocalProperty,
|
|
iWindow, CurrentTime);
|
|
|
|
/* Process X events */
|
|
data.fUseUnicode = fConvertToUnicode;
|
|
iReturn = winProcessXEventsTimeout(hwnd,
|
|
iWindow,
|
|
pDisplay,
|
|
&data,
|
|
atoms,
|
|
WIN_POLL_TIMEOUT);
|
|
|
|
if (WIN_XEVENTS_NOTIFY_TARGETS != iReturn) {
|
|
ErrorF
|
|
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_TARGETS\n");
|
|
goto fake_paste;
|
|
}
|
|
|
|
/* Choose the most preferred target */
|
|
{
|
|
struct target_priority
|
|
{
|
|
Atom target;
|
|
unsigned int priority;
|
|
};
|
|
|
|
struct target_priority target_priority_table[] =
|
|
{
|
|
{ atoms->atomCompoundText, 0 },
|
|
#ifdef X_HAVE_UTF8_STRING
|
|
{ atoms->atomUTF8String, 1 },
|
|
#endif
|
|
{ XA_STRING, 2 },
|
|
};
|
|
|
|
int best_priority = INT_MAX;
|
|
|
|
int i,j;
|
|
for (i = 0 ; data.targetList[i] != 0; i++)
|
|
{
|
|
for (j = 0; j < ARRAY_SIZE(target_priority_table); j ++)
|
|
{
|
|
if ((data.targetList[i] == target_priority_table[j].target) &&
|
|
(target_priority_table[j].priority < best_priority))
|
|
{
|
|
best_target = target_priority_table[j].target;
|
|
best_priority = target_priority_table[j].priority;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free(data.targetList);
|
|
data.targetList = 0;
|
|
|
|
winDebug("winClipboardWindowProc - best target is %d\n", best_target);
|
|
|
|
/* No useful targets found */
|
|
if (best_target == 0)
|
|
goto fake_paste;
|
|
|
|
winDebug("winClipboardWindowProc - requesting selection from owner\n");
|
|
|
|
/* Request the selection contents */
|
|
XConvertSelection(pDisplay,
|
|
selection,
|
|
best_target,
|
|
atoms->atomLocalProperty,
|
|
iWindow, CurrentTime);
|
|
|
|
/* Process X events */
|
|
iReturn = winProcessXEventsTimeout(hwnd,
|
|
iWindow,
|
|
pDisplay,
|
|
&data,
|
|
atoms,
|
|
WIN_POLL_TIMEOUT);
|
|
|
|
/*
|
|
* winProcessXEventsTimeout had better have seen a notify event,
|
|
* or else we are dealing with a buggy or old X11 app.
|
|
*/
|
|
if (WIN_XEVENTS_NOTIFY_DATA != iReturn) {
|
|
ErrorF
|
|
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_DATA\n");
|
|
}
|
|
else {
|
|
pasted = TRUE;
|
|
}
|
|
|
|
/*
|
|
* If we couldn't get the data from the X clipboard, we
|
|
* have to paste some fake data to the Win32 clipboard to
|
|
* satisfy the requirement that we write something to it.
|
|
*/
|
|
fake_paste:
|
|
if (!pasted)
|
|
{
|
|
/* Paste no data, to satisfy required call to SetClipboardData */
|
|
SetClipboardData(CF_UNICODETEXT, NULL);
|
|
SetClipboardData(CF_TEXT, NULL);
|
|
}
|
|
|
|
winDebug("winClipboardWindowProc - WM_RENDERFORMAT - Returning.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Let Windows perform default processing for unhandled messages */
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
/*
|
|
* Process any pending Windows messages
|
|
*/
|
|
|
|
Bool
|
|
winClipboardFlushWindowsMessageQueue(HWND hwnd)
|
|
{
|
|
MSG msg;
|
|
|
|
/* Flush the messaging window queue */
|
|
/* NOTE: Do not pass the hwnd of our messaging window to PeekMessage,
|
|
* as this will filter out many non-window-specific messages that
|
|
* are sent to our thread, such as WM_QUIT.
|
|
*/
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
/* Dispatch the message if not WM_QUIT */
|
|
if (msg.message == WM_QUIT)
|
|
return FALSE;
|
|
else
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|