623 lines
18 KiB
C
623 lines
18 KiB
C
|
/*
|
||
|
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||
|
*
|
||
|
*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 Harold L Hunt II
|
||
|
*shall not be used in advertising or otherwise to promote the sale, use
|
||
|
*or other dealings in this Software without prior written authorization
|
||
|
*from Harold L Hunt II.
|
||
|
*
|
||
|
* Authors: Harold L Hunt II
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_XWIN_CONFIG_H
|
||
|
#include <xwin-config.h>
|
||
|
#endif
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/time.h>
|
||
|
#include "winclipboard.h"
|
||
|
|
||
|
extern void winFixClipboardChain();
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Constants
|
||
|
*/
|
||
|
|
||
|
#define WIN_CLIPBOARD_PROP "cyg_clipboard_prop"
|
||
|
#define WIN_POLL_TIMEOUT 1
|
||
|
|
||
|
|
||
|
/*
|
||
|
* References to external symbols
|
||
|
*/
|
||
|
|
||
|
extern Bool g_fUseUnicode;
|
||
|
extern Bool g_fUnicodeSupport;
|
||
|
extern void *g_pClipboardDisplay;
|
||
|
extern Window g_iClipboardWindow;
|
||
|
extern Atom g_atomLastOwnedSelection;
|
||
|
|
||
|
/* BPS - g_hwndClipboard needed for X app->Windows paste fix */
|
||
|
extern HWND g_hwndClipboard;
|
||
|
|
||
|
/*
|
||
|
* Local function prototypes
|
||
|
*/
|
||
|
|
||
|
static Bool
|
||
|
winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay,
|
||
|
Bool fUseUnicode, int iTimeoutSec);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Process X events up to specified timeout
|
||
|
*/
|
||
|
|
||
|
static int
|
||
|
winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay,
|
||
|
Bool fUseUnicode, int iTimeoutSec)
|
||
|
{
|
||
|
int iConnNumber;
|
||
|
struct timeval tv;
|
||
|
int iReturn;
|
||
|
DWORD dwStopTime = (GetTickCount () / 1000) + iTimeoutSec;
|
||
|
|
||
|
/* We need to ensure that all pending events are processed */
|
||
|
XSync (pDisplay, FALSE);
|
||
|
|
||
|
/* Get our connection number */
|
||
|
iConnNumber = ConnectionNumber (pDisplay);
|
||
|
|
||
|
/* Loop for X events */
|
||
|
while (1)
|
||
|
{
|
||
|
fd_set fdsRead;
|
||
|
|
||
|
/* Setup the file descriptor set */
|
||
|
FD_ZERO (&fdsRead);
|
||
|
FD_SET (iConnNumber, &fdsRead);
|
||
|
|
||
|
/* Adjust timeout */
|
||
|
tv.tv_sec = dwStopTime - (GetTickCount () / 1000);
|
||
|
tv.tv_usec = 0;
|
||
|
|
||
|
/* Break out if no time left */
|
||
|
if (tv.tv_sec < 0)
|
||
|
return WIN_XEVENTS_SUCCESS;
|
||
|
|
||
|
/* Wait for a Windows event or an X event */
|
||
|
iReturn = select (iConnNumber + 1,/* Highest fds number */
|
||
|
&fdsRead, /* Read mask */
|
||
|
NULL, /* No write mask */
|
||
|
NULL, /* No exception mask */
|
||
|
&tv); /* No timeout */
|
||
|
if (iReturn <= 0)
|
||
|
{
|
||
|
ErrorF ("winProcessXEventsTimeout - Call to select () failed: %d. "
|
||
|
"Bailing.\n", iReturn);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Branch on which descriptor became active */
|
||
|
if (FD_ISSET (iConnNumber, &fdsRead))
|
||
|
{
|
||
|
/* Process X events */
|
||
|
/* Exit when we see that server is shutting down */
|
||
|
iReturn = winClipboardFlushXEvents (hwnd,
|
||
|
iWindow,
|
||
|
pDisplay,
|
||
|
fUseUnicode);
|
||
|
if (WIN_XEVENTS_NOTIFY == iReturn
|
||
|
|| WIN_XEVENTS_CONVERT == iReturn)
|
||
|
{
|
||
|
/* Bail out if convert or notify processed */
|
||
|
return iReturn;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return WIN_XEVENTS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Process a given Windows message
|
||
|
*/
|
||
|
|
||
|
/* BPS - Define our own message, which we'll post to ourselves to facilitate
|
||
|
* resetting the delayed rendering mechanism after each paste from X app to
|
||
|
* Windows app. TODO - Perhaps move to win.h with the other WM_USER messages.
|
||
|
*/
|
||
|
#define WM_USER_PASTE_COMPLETE (WM_USER + 1003)
|
||
|
|
||
|
LRESULT CALLBACK
|
||
|
winClipboardWindowProc (HWND hwnd, UINT message,
|
||
|
WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
static HWND s_hwndNextViewer;
|
||
|
static Bool s_fCBCInitialized;
|
||
|
|
||
|
/* Branch on message type */
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_DESTROY:
|
||
|
{
|
||
|
winDebug ("winClipboardWindowProc - WM_DESTROY\n");
|
||
|
|
||
|
/* Remove ourselves from the clipboard chain */
|
||
|
ChangeClipboardChain (hwnd, s_hwndNextViewer);
|
||
|
|
||
|
s_hwndNextViewer = NULL;
|
||
|
|
||
|
PostQuitMessage (0);
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
|
||
|
case WM_CREATE:
|
||
|
{
|
||
|
HWND first, next;
|
||
|
DWORD error_code = 0;
|
||
|
winDebug ("winClipboardWindowProc - WM_CREATE\n");
|
||
|
|
||
|
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(%x) "
|
||
|
"lParam(%x) s_hwndNextViewer(%x)\n",
|
||
|
wParam, lParam, s_hwndNextViewer);
|
||
|
|
||
|
if ((HWND) wParam == s_hwndNextViewer)
|
||
|
{
|
||
|
s_hwndNextViewer = (HWND) lParam;
|
||
|
if (s_hwndNextViewer == hwnd)
|
||
|
{
|
||
|
s_hwndNextViewer = NULL;
|
||
|
winErrorFVerb (1, "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");
|
||
|
|
||
|
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(%x) with %x 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:
|
||
|
{
|
||
|
static Bool s_fProcessingDrawClipboard = FALSE;
|
||
|
Display *pDisplay = g_pClipboardDisplay;
|
||
|
Window iWindow = g_iClipboardWindow;
|
||
|
int iReturn;
|
||
|
|
||
|
winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: 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();
|
||
|
winErrorFVerb (1, "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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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);
|
||
|
|
||
|
/* Release PRIMARY selection if owned */
|
||
|
iReturn = XGetSelectionOwner (pDisplay, XA_PRIMARY);
|
||
|
if (iReturn == g_iClipboardWindow)
|
||
|
{
|
||
|
winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
||
|
"PRIMARY selection is owned by us.\n");
|
||
|
XSetSelectionOwner (pDisplay,
|
||
|
XA_PRIMARY,
|
||
|
None,
|
||
|
CurrentTime);
|
||
|
}
|
||
|
else if (BadWindow == iReturn || BadAtom == iReturn)
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
||
|
"XGetSelection failed for PRIMARY: %d\n", iReturn);
|
||
|
|
||
|
/* Release CLIPBOARD selection if owned */
|
||
|
iReturn = XGetSelectionOwner (pDisplay,
|
||
|
XInternAtom (pDisplay,
|
||
|
"CLIPBOARD",
|
||
|
False));
|
||
|
if (iReturn == g_iClipboardWindow)
|
||
|
{
|
||
|
winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
||
|
"CLIPBOARD selection is owned by us.\n");
|
||
|
XSetSelectionOwner (pDisplay,
|
||
|
XInternAtom (pDisplay,
|
||
|
"CLIPBOARD",
|
||
|
False),
|
||
|
None,
|
||
|
CurrentTime);
|
||
|
}
|
||
|
else if (BadWindow == iReturn || BadAtom == iReturn)
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
|
||
|
"XGetSelection 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)
|
||
|
{
|
||
|
winErrorFVerb (1, "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,
|
||
|
XInternAtom (pDisplay,
|
||
|
"CLIPBOARD",
|
||
|
False),
|
||
|
iWindow,
|
||
|
CurrentTime);
|
||
|
if (iReturn == BadAtom || iReturn == BadWindow)
|
||
|
{
|
||
|
winErrorFVerb (1, "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.
|
||
|
*/
|
||
|
return 0;
|
||
|
|
||
|
|
||
|
case WM_RENDERFORMAT:
|
||
|
case WM_RENDERALLFORMATS:
|
||
|
{
|
||
|
int iReturn;
|
||
|
Display *pDisplay = g_pClipboardDisplay;
|
||
|
Window iWindow = g_iClipboardWindow;
|
||
|
Bool fConvertToUnicode;
|
||
|
|
||
|
winDebug ("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n");
|
||
|
|
||
|
/* Flag whether to convert to Unicode or not */
|
||
|
if (message == WM_RENDERALLFORMATS)
|
||
|
fConvertToUnicode = FALSE;
|
||
|
else
|
||
|
fConvertToUnicode = g_fUnicodeSupport && (CF_UNICODETEXT == wParam);
|
||
|
|
||
|
/* Request the selection contents */
|
||
|
iReturn = XConvertSelection (pDisplay,
|
||
|
g_atomLastOwnedSelection,
|
||
|
XInternAtom (pDisplay,
|
||
|
"COMPOUND_TEXT", False),
|
||
|
XInternAtom (pDisplay,
|
||
|
"CYGX_CUT_BUFFER", False),
|
||
|
iWindow,
|
||
|
CurrentTime);
|
||
|
if (iReturn == BadAtom || iReturn == BadWindow)
|
||
|
{
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMAT - "
|
||
|
"XConvertSelection () failed\n");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Special handling for WM_RENDERALLFORMATS */
|
||
|
if (message == WM_RENDERALLFORMATS)
|
||
|
{
|
||
|
/* We must open and empty the clipboard */
|
||
|
|
||
|
/* Close clipboard if we have it open already */
|
||
|
if (GetOpenClipboardWindow () == hwnd)
|
||
|
{
|
||
|
CloseClipboard ();
|
||
|
}
|
||
|
|
||
|
if (!OpenClipboard (hwnd))
|
||
|
{
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
|
||
|
"OpenClipboard () failed: %08x\n",
|
||
|
GetLastError ());
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!EmptyClipboard ())
|
||
|
{
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
|
||
|
"EmptyClipboard () failed: %08x\n",
|
||
|
GetLastError ());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Process the SelectionNotify event */
|
||
|
iReturn = winProcessXEventsTimeout (hwnd,
|
||
|
iWindow,
|
||
|
pDisplay,
|
||
|
fConvertToUnicode,
|
||
|
WIN_POLL_TIMEOUT);
|
||
|
if (WIN_XEVENTS_CONVERT == iReturn)
|
||
|
{
|
||
|
/*
|
||
|
* The selection was offered for conversion first, so we have
|
||
|
* to process a second SelectionNotify event to get the actual
|
||
|
* data in the selection.
|
||
|
*/
|
||
|
iReturn = winProcessXEventsTimeout (hwnd,
|
||
|
iWindow,
|
||
|
pDisplay,
|
||
|
fConvertToUnicode,
|
||
|
WIN_POLL_TIMEOUT);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The last of the up-to two calls to winProcessXEventsTimeout
|
||
|
* from above had better have seen a notify event, or else we
|
||
|
* are dealing with a buggy or old X11 app. In these cases we
|
||
|
* have to paste some fake data to the Win32 clipboard to
|
||
|
* satisfy the requirement that we write something to it.
|
||
|
*/
|
||
|
if (WIN_XEVENTS_NOTIFY != iReturn)
|
||
|
{
|
||
|
/* Paste no data, to satisfy required call to SetClipboardData */
|
||
|
if (g_fUnicodeSupport)
|
||
|
SetClipboardData (CF_UNICODETEXT, NULL);
|
||
|
SetClipboardData (CF_TEXT, NULL);
|
||
|
}
|
||
|
|
||
|
/* BPS - Post ourselves a user message whose handler will reset the
|
||
|
* delayed rendering mechanism after the paste is complete. This is
|
||
|
* necessary because calling SetClipboardData() with a NULL argument
|
||
|
* here will cause the data we just put on the clipboard to be lost!
|
||
|
*/
|
||
|
PostMessage(g_hwndClipboard, WM_USER_PASTE_COMPLETE, 0, 0);
|
||
|
|
||
|
/* Special handling for WM_RENDERALLFORMATS */
|
||
|
if (message == WM_RENDERALLFORMATS)
|
||
|
{
|
||
|
/* We must close the clipboard */
|
||
|
|
||
|
if (!CloseClipboard ())
|
||
|
{
|
||
|
winErrorFVerb (1, "winClipboardWindowProc - WM_RENDERALLFORMATS - "
|
||
|
"CloseClipboard () failed: %08x\n",
|
||
|
GetLastError ());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
winDebug ("winClipboardWindowProc - WM_RENDER*FORMAT - Returning.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
/* BPS - This WM_USER message is posted by us. It gives us the opportunity
|
||
|
* to reset the delayed rendering mechanism after each and every paste
|
||
|
* from an X app to a Windows app. Without such a mechanism, subsequent
|
||
|
* changes of selection in the X app owning the selection are not
|
||
|
* reflected in pastes into Windows apps, since Windows won't send us the
|
||
|
* WM_RENDERFORMAT message unless someone has set changed data (or NULL)
|
||
|
* on the clipboard. */
|
||
|
case WM_USER_PASTE_COMPLETE:
|
||
|
{
|
||
|
if (hwnd != GetClipboardOwner ())
|
||
|
/* In case we've lost the selection since posting the message */
|
||
|
return 0;
|
||
|
winDebug ("winClipboardWindowProc - WM_USER_PASTE_COMPLETE\n");
|
||
|
|
||
|
/* Set up for another delayed rendering callback */
|
||
|
OpenClipboard (g_hwndClipboard);
|
||
|
|
||
|
/* Take ownership of the Windows clipboard */
|
||
|
EmptyClipboard ();
|
||
|
|
||
|
/* Advertise Unicode if we support it */
|
||
|
if (g_fUnicodeSupport)
|
||
|
SetClipboardData (CF_UNICODETEXT, NULL);
|
||
|
|
||
|
/* Always advertise regular text */
|
||
|
SetClipboardData (CF_TEXT, NULL);
|
||
|
|
||
|
/* Release the clipboard */
|
||
|
CloseClipboard ();
|
||
|
}
|
||
|
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;
|
||
|
}
|