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