1706f2543Smrg/*
2706f2543Smrg *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
3706f2543Smrg *Copyright (C) Colin Harrison 2005-2008
4706f2543Smrg *
5706f2543Smrg *Permission is hereby granted, free of charge, to any person obtaining
6706f2543Smrg * a copy of this software and associated documentation files (the
7706f2543Smrg *"Software"), to deal in the Software without restriction, including
8706f2543Smrg *without limitation the rights to use, copy, modify, merge, publish,
9706f2543Smrg *distribute, sublicense, and/or sell copies of the Software, and to
10706f2543Smrg *permit persons to whom the Software is furnished to do so, subject to
11706f2543Smrg *the following conditions:
12706f2543Smrg *
13706f2543Smrg *The above copyright notice and this permission notice shall be
14706f2543Smrg *included in all copies or substantial portions of the Software.
15706f2543Smrg *
16706f2543Smrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17706f2543Smrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18706f2543Smrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19706f2543Smrg *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
20706f2543Smrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21706f2543Smrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22706f2543Smrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23706f2543Smrg *
24706f2543Smrg *Except as contained in this notice, the name of the copyright holder(s)
25706f2543Smrg *and author(s) shall not be used in advertising or otherwise to promote
26706f2543Smrg *the sale, use or other dealings in this Software without prior written
27706f2543Smrg *authorization from the copyright holder(s) and author(s).
28706f2543Smrg *
29706f2543Smrg * Authors:	Harold L Hunt II
30706f2543Smrg *              Colin Harrison
31706f2543Smrg */
32706f2543Smrg
33706f2543Smrg#ifdef HAVE_XWIN_CONFIG_H
34706f2543Smrg#include <xwin-config.h>
35706f2543Smrg#endif
36706f2543Smrg#include <sys/types.h>
37706f2543Smrg#include <sys/time.h>
38706f2543Smrg#include "winclipboard.h"
39706f2543Smrg#include "misc.h"
40706f2543Smrg
41706f2543Smrg/*
42706f2543Smrg * Constants
43706f2543Smrg */
44706f2543Smrg
45706f2543Smrg#define WIN_CLIPBOARD_PROP	"cyg_clipboard_prop"
46706f2543Smrg#define WIN_POLL_TIMEOUT	1
47706f2543Smrg
48706f2543Smrg
49706f2543Smrg/*
50706f2543Smrg * References to external symbols
51706f2543Smrg */
52706f2543Smrg
53706f2543Smrgextern Bool		g_fUseUnicode;
54706f2543Smrgextern Bool		g_fUnicodeSupport;
55706f2543Smrgextern void		*g_pClipboardDisplay;
56706f2543Smrgextern Window		g_iClipboardWindow;
57706f2543Smrgextern Atom		g_atomLastOwnedSelection;
58706f2543Smrg
59706f2543Smrg/* BPS - g_hwndClipboard needed for X app->Windows paste fix */
60706f2543Smrgextern HWND		g_hwndClipboard;
61706f2543Smrg
62706f2543Smrg/*
63706f2543Smrg * Local function prototypes
64706f2543Smrg */
65706f2543Smrg
66706f2543Smrgstatic int
67706f2543SmrgwinProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay,
68706f2543Smrg			  Bool fUseUnicode, int iTimeoutSec);
69706f2543Smrg
70706f2543Smrg
71706f2543Smrg/*
72706f2543Smrg * Process X events up to specified timeout
73706f2543Smrg */
74706f2543Smrg
75706f2543Smrgstatic int
76706f2543SmrgwinProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay,
77706f2543Smrg			  Bool fUseUnicode, int iTimeoutSec)
78706f2543Smrg{
79706f2543Smrg  int			iConnNumber;
80706f2543Smrg  struct timeval	tv;
81706f2543Smrg  int			iReturn;
82706f2543Smrg  DWORD			dwStopTime = (GetTickCount () / 1000) + iTimeoutSec;
83706f2543Smrg
84706f2543Smrg  /* We need to ensure that all pending events are processed */
85706f2543Smrg  XSync (pDisplay, FALSE);
86706f2543Smrg
87706f2543Smrg  /* Get our connection number */
88706f2543Smrg  iConnNumber = ConnectionNumber (pDisplay);
89706f2543Smrg
90706f2543Smrg  /* Loop for X events */
91706f2543Smrg  while (1)
92706f2543Smrg    {
93706f2543Smrg      fd_set		fdsRead;
94706f2543Smrg
95706f2543Smrg      /* Setup the file descriptor set */
96706f2543Smrg      FD_ZERO (&fdsRead);
97706f2543Smrg      FD_SET (iConnNumber, &fdsRead);
98706f2543Smrg
99706f2543Smrg      /* Adjust timeout */
100706f2543Smrg      tv.tv_sec = dwStopTime - (GetTickCount () / 1000);
101706f2543Smrg      tv.tv_usec = 0;
102706f2543Smrg
103706f2543Smrg      /* Break out if no time left */
104706f2543Smrg      if (tv.tv_sec < 0)
105706f2543Smrg	return WIN_XEVENTS_SUCCESS;
106706f2543Smrg
107706f2543Smrg      /* Wait for an X event */
108706f2543Smrg      iReturn = select (iConnNumber + 1,/* Highest fds number */
109706f2543Smrg			&fdsRead,	/* Read mask */
110706f2543Smrg			NULL,		/* No write mask */
111706f2543Smrg			NULL,		/* No exception mask */
112706f2543Smrg			&tv);		/* No timeout */
113706f2543Smrg      if (iReturn < 0)
114706f2543Smrg	{
115706f2543Smrg	  ErrorF ("winProcessXEventsTimeout - Call to select () failed: %d.  "
116706f2543Smrg		  "Bailing.\n", iReturn);
117706f2543Smrg	  break;
118706f2543Smrg	}
119706f2543Smrg
120706f2543Smrg      /* Branch on which descriptor became active */
121706f2543Smrg      if (FD_ISSET (iConnNumber, &fdsRead))
122706f2543Smrg	{
123706f2543Smrg	  /* Process X events */
124706f2543Smrg	  /* Exit when we see that server is shutting down */
125706f2543Smrg	  iReturn = winClipboardFlushXEvents (hwnd,
126706f2543Smrg					      iWindow,
127706f2543Smrg					      pDisplay,
128706f2543Smrg					      fUseUnicode);
129706f2543Smrg	  if (WIN_XEVENTS_NOTIFY == iReturn
130706f2543Smrg	      || WIN_XEVENTS_CONVERT == iReturn)
131706f2543Smrg	    {
132706f2543Smrg	      /* Bail out if convert or notify processed */
133706f2543Smrg	      return iReturn;
134706f2543Smrg	    }
135706f2543Smrg	}
136706f2543Smrg    }
137706f2543Smrg
138706f2543Smrg  return WIN_XEVENTS_SUCCESS;
139706f2543Smrg}
140706f2543Smrg
141706f2543Smrg
142706f2543Smrg/*
143706f2543Smrg * Process a given Windows message
144706f2543Smrg */
145706f2543Smrg
146706f2543Smrg/* BPS - Define our own message, which we'll post to ourselves to facilitate
147706f2543Smrg * resetting the delayed rendering mechanism after each paste from X app to
148706f2543Smrg * Windows app. TODO - Perhaps move to win.h with the other WM_USER messages.
149706f2543Smrg */
150706f2543Smrg#define WM_USER_PASTE_COMPLETE		(WM_USER + 1003)
151706f2543Smrg
152706f2543SmrgLRESULT CALLBACK
153706f2543SmrgwinClipboardWindowProc (HWND hwnd, UINT message,
154706f2543Smrg			WPARAM wParam, LPARAM lParam)
155706f2543Smrg{
156706f2543Smrg  static HWND		s_hwndNextViewer;
157706f2543Smrg  static Bool		s_fCBCInitialized;
158706f2543Smrg
159706f2543Smrg  /* Branch on message type */
160706f2543Smrg  switch (message)
161706f2543Smrg    {
162706f2543Smrg    case WM_DESTROY:
163706f2543Smrg      {
164706f2543Smrg	winDebug ("winClipboardWindowProc - WM_DESTROY\n");
165706f2543Smrg
166706f2543Smrg	/* Remove ourselves from the clipboard chain */
167706f2543Smrg	ChangeClipboardChain (hwnd, s_hwndNextViewer);
168706f2543Smrg
169706f2543Smrg	s_hwndNextViewer = NULL;
170706f2543Smrg
171706f2543Smrg	PostQuitMessage (0);
172706f2543Smrg      }
173706f2543Smrg      return 0;
174706f2543Smrg
175706f2543Smrg
176706f2543Smrg    case WM_CREATE:
177706f2543Smrg      {
178706f2543Smrg	HWND first, next;
179706f2543Smrg	DWORD error_code = 0;
180706f2543Smrg	winDebug ("winClipboardWindowProc - WM_CREATE\n");
181706f2543Smrg
182706f2543Smrg	first = GetClipboardViewer();			/* Get handle to first viewer in chain. */
183706f2543Smrg	if (first == hwnd) return 0;			/* Make sure it's not us! */
184706f2543Smrg	/* Add ourselves to the clipboard viewer chain */
185706f2543Smrg	next = SetClipboardViewer (hwnd);
186706f2543Smrg	error_code = GetLastError();
187706f2543Smrg	if (SUCCEEDED(error_code) && (next == first))	/* SetClipboardViewer must have succeeded, and the handle */
188706f2543Smrg		s_hwndNextViewer = next;		/* it returned must have been the first window in the chain */
189706f2543Smrg	else
190706f2543Smrg		s_fCBCInitialized = FALSE;
191706f2543Smrg      }
192706f2543Smrg      return 0;
193706f2543Smrg
194706f2543Smrg
195706f2543Smrg    case WM_CHANGECBCHAIN:
196706f2543Smrg      {
197706f2543Smrg	winDebug ("winClipboardWindowProc - WM_CHANGECBCHAIN: wParam(%x) "
198706f2543Smrg		  "lParam(%x) s_hwndNextViewer(%x)\n",
199706f2543Smrg		  wParam, lParam, s_hwndNextViewer);
200706f2543Smrg
201706f2543Smrg	if ((HWND) wParam == s_hwndNextViewer)
202706f2543Smrg	  {
203706f2543Smrg	    s_hwndNextViewer = (HWND) lParam;
204706f2543Smrg	    if (s_hwndNextViewer == hwnd)
205706f2543Smrg	      {
206706f2543Smrg		s_hwndNextViewer = NULL;
207706f2543Smrg		winErrorFVerb (1, "winClipboardWindowProc - WM_CHANGECBCHAIN: "
208706f2543Smrg			       "attempted to set next window to ourselves.");
209706f2543Smrg	      }
210706f2543Smrg	  }
211706f2543Smrg	else if (s_hwndNextViewer)
212706f2543Smrg	  SendMessage (s_hwndNextViewer, message,
213706f2543Smrg		       wParam, lParam);
214706f2543Smrg
215706f2543Smrg      }
216706f2543Smrg      winDebug ("winClipboardWindowProc - WM_CHANGECBCHAIN: Exit\n");
217706f2543Smrg      return 0;
218706f2543Smrg
219706f2543Smrg    case WM_WM_REINIT:
220706f2543Smrg      {
221706f2543Smrg        /* Ensure that we're in the clipboard chain.  Some apps,
222706f2543Smrg         * WinXP's remote desktop for one, don't play nice with the
223706f2543Smrg         * chain.  This message is called whenever we receive a
224706f2543Smrg         * WM_ACTIVATEAPP message to ensure that we continue to
225706f2543Smrg         * receive clipboard messages.
226706f2543Smrg	 *
227706f2543Smrg	 * It might be possible to detect if we're still in the chain
228706f2543Smrg	 * by calling SendMessage (GetClipboardViewer(),
229706f2543Smrg	 * WM_DRAWCLIPBOARD, 0, 0); and then seeing if we get the
230706f2543Smrg	 * WM_DRAWCLIPBOARD message.  That, however, might be more
231706f2543Smrg	 * expensive than just putting ourselves back into the chain.
232706f2543Smrg	 */
233706f2543Smrg
234706f2543Smrg	HWND first, next;
235706f2543Smrg	DWORD error_code = 0;
236706f2543Smrg	winDebug ("winClipboardWindowProc - WM_WM_REINIT: Enter\n");
237706f2543Smrg
238706f2543Smrg	first = GetClipboardViewer();			/* Get handle to first viewer in chain. */
239706f2543Smrg	if (first == hwnd) return 0;			/* Make sure it's not us! */
240706f2543Smrg	winDebug ("  WM_WM_REINIT: Replacing us(%x) with %x at head "
241706f2543Smrg		  "of chain\n", hwnd, s_hwndNextViewer);
242706f2543Smrg	s_fCBCInitialized = FALSE;
243706f2543Smrg	ChangeClipboardChain (hwnd, s_hwndNextViewer);
244706f2543Smrg	s_hwndNextViewer = NULL;
245706f2543Smrg	s_fCBCInitialized = FALSE;
246706f2543Smrg	winDebug ("  WM_WM_REINIT: Putting us back at head of chain.\n");
247706f2543Smrg	first = GetClipboardViewer();			/* Get handle to first viewer in chain. */
248706f2543Smrg	if (first == hwnd) return 0;			/* Make sure it's not us! */
249706f2543Smrg	next = SetClipboardViewer (hwnd);
250706f2543Smrg	error_code = GetLastError();
251706f2543Smrg	if (SUCCEEDED(error_code) && (next == first))	/* SetClipboardViewer must have succeeded, and the handle */
252706f2543Smrg		s_hwndNextViewer = next;		/* it returned must have been the first window in the chain */
253706f2543Smrg	else
254706f2543Smrg		s_fCBCInitialized = FALSE;
255706f2543Smrg      }
256706f2543Smrg      winDebug ("winClipboardWindowProc - WM_WM_REINIT: Exit\n");
257706f2543Smrg      return 0;
258706f2543Smrg
259706f2543Smrg
260706f2543Smrg    case WM_DRAWCLIPBOARD:
261706f2543Smrg      {
262706f2543Smrg	static Atom atomClipboard;
263706f2543Smrg	static int generation;
264706f2543Smrg	static Bool s_fProcessingDrawClipboard = FALSE;
265706f2543Smrg	Display	*pDisplay = g_pClipboardDisplay;
266706f2543Smrg	Window	iWindow = g_iClipboardWindow;
267706f2543Smrg	int	iReturn;
268706f2543Smrg
269706f2543Smrg	winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n");
270706f2543Smrg
271706f2543Smrg	if (generation != serverGeneration)
272706f2543Smrg          {
273706f2543Smrg            generation = serverGeneration;
274706f2543Smrg            atomClipboard = XInternAtom (pDisplay, "CLIPBOARD", False);
275706f2543Smrg          }
276706f2543Smrg
277706f2543Smrg	/*
278706f2543Smrg	 * We've occasionally seen a loop in the clipboard chain.
279706f2543Smrg	 * Try and fix it on the first hint of recursion.
280706f2543Smrg	 */
281706f2543Smrg	if (! s_fProcessingDrawClipboard)
282706f2543Smrg	  {
283706f2543Smrg	    s_fProcessingDrawClipboard = TRUE;
284706f2543Smrg	  }
285706f2543Smrg	else
286706f2543Smrg	  {
287706f2543Smrg	    /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */
288706f2543Smrg	    s_fCBCInitialized = FALSE;
289706f2543Smrg	    ChangeClipboardChain (hwnd, s_hwndNextViewer);
290706f2543Smrg	    winFixClipboardChain();
291706f2543Smrg	    winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
292706f2543Smrg			   "Nested calls detected.  Re-initing.\n");
293706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
294706f2543Smrg	    s_fProcessingDrawClipboard = FALSE;
295706f2543Smrg	    return 0;
296706f2543Smrg	  }
297706f2543Smrg
298706f2543Smrg	/* Bail on first message */
299706f2543Smrg	if (!s_fCBCInitialized)
300706f2543Smrg	  {
301706f2543Smrg	    s_fCBCInitialized = TRUE;
302706f2543Smrg	    s_fProcessingDrawClipboard = FALSE;
303706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
304706f2543Smrg	    return 0;
305706f2543Smrg	  }
306706f2543Smrg
307706f2543Smrg	/*
308706f2543Smrg	 * NOTE: We cannot bail out when NULL == GetClipboardOwner ()
309706f2543Smrg	 * because some applications deal with the clipboard in a manner
310706f2543Smrg	 * that causes the clipboard owner to be NULL when they are in
311706f2543Smrg	 * fact taking ownership.  One example of this is the Win32
312706f2543Smrg	 * native compile of emacs.
313706f2543Smrg	 */
314706f2543Smrg
315706f2543Smrg	/* Bail when we still own the clipboard */
316706f2543Smrg	if (hwnd == GetClipboardOwner ())
317706f2543Smrg	  {
318706f2543Smrg
319706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
320706f2543Smrg		    "We own the clipboard, returning.\n");
321706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
322706f2543Smrg	    s_fProcessingDrawClipboard = FALSE;
323706f2543Smrg	    if (s_hwndNextViewer)
324706f2543Smrg		SendMessage (s_hwndNextViewer, message, wParam, lParam);
325706f2543Smrg	    return 0;
326706f2543Smrg	  }
327706f2543Smrg
328706f2543Smrg	/*
329706f2543Smrg	 * Do not take ownership of the X11 selections when something
330706f2543Smrg	 * other than CF_TEXT or CF_UNICODETEXT has been copied
331706f2543Smrg	 * into the Win32 clipboard.
332706f2543Smrg	 */
333706f2543Smrg	if (!IsClipboardFormatAvailable (CF_TEXT)
334706f2543Smrg	    && !IsClipboardFormatAvailable (CF_UNICODETEXT))
335706f2543Smrg	  {
336706f2543Smrg
337706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
338706f2543Smrg		    "Clipboard does not contain CF_TEXT nor "
339706f2543Smrg		    "CF_UNICODETEXT.\n");
340706f2543Smrg
341706f2543Smrg	    /*
342706f2543Smrg	     * We need to make sure that the X Server has processed
343706f2543Smrg	     * previous XSetSelectionOwner messages.
344706f2543Smrg	     */
345706f2543Smrg	    XSync (pDisplay, FALSE);
346706f2543Smrg
347706f2543Smrg	    /* Release PRIMARY selection if owned */
348706f2543Smrg	    iReturn = XGetSelectionOwner (pDisplay, XA_PRIMARY);
349706f2543Smrg	    if (iReturn == g_iClipboardWindow)
350706f2543Smrg	      {
351706f2543Smrg		winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
352706f2543Smrg			"PRIMARY selection is owned by us.\n");
353706f2543Smrg		XSetSelectionOwner (pDisplay,
354706f2543Smrg				    XA_PRIMARY,
355706f2543Smrg				    None,
356706f2543Smrg				    CurrentTime);
357706f2543Smrg	      }
358706f2543Smrg	    else if (BadWindow == iReturn || BadAtom == iReturn)
359706f2543Smrg	      winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
360706f2543Smrg		      "XGetSelection failed for PRIMARY: %d\n", iReturn);
361706f2543Smrg
362706f2543Smrg	    /* Release CLIPBOARD selection if owned */
363706f2543Smrg	    iReturn = XGetSelectionOwner (pDisplay,
364706f2543Smrg					  atomClipboard);
365706f2543Smrg	    if (iReturn == g_iClipboardWindow)
366706f2543Smrg	      {
367706f2543Smrg		winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
368706f2543Smrg			"CLIPBOARD selection is owned by us.\n");
369706f2543Smrg		XSetSelectionOwner (pDisplay,
370706f2543Smrg				    atomClipboard,
371706f2543Smrg				    None,
372706f2543Smrg				    CurrentTime);
373706f2543Smrg	      }
374706f2543Smrg	    else if (BadWindow == iReturn || BadAtom == iReturn)
375706f2543Smrg	      winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
376706f2543Smrg		      "XGetSelection failed for CLIPBOARD: %d\n", iReturn);
377706f2543Smrg
378706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
379706f2543Smrg	    s_fProcessingDrawClipboard = FALSE;
380706f2543Smrg	    if (s_hwndNextViewer)
381706f2543Smrg		SendMessage (s_hwndNextViewer, message, wParam, lParam);
382706f2543Smrg	    return 0;
383706f2543Smrg	  }
384706f2543Smrg
385706f2543Smrg	/* Reassert ownership of PRIMARY */
386706f2543Smrg	iReturn = XSetSelectionOwner (pDisplay,
387706f2543Smrg				      XA_PRIMARY,
388706f2543Smrg				      iWindow,
389706f2543Smrg				      CurrentTime);
390706f2543Smrg	if (iReturn == BadAtom || iReturn == BadWindow ||
391706f2543Smrg	    XGetSelectionOwner (pDisplay, XA_PRIMARY) != iWindow)
392706f2543Smrg	  {
393706f2543Smrg	    winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
394706f2543Smrg		    "Could not reassert ownership of PRIMARY\n");
395706f2543Smrg	  }
396706f2543Smrg	else
397706f2543Smrg	  {
398706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
399706f2543Smrg		    "Reasserted ownership of PRIMARY\n");
400706f2543Smrg	  }
401706f2543Smrg
402706f2543Smrg	/* Reassert ownership of the CLIPBOARD */
403706f2543Smrg	iReturn = XSetSelectionOwner (pDisplay,
404706f2543Smrg				      atomClipboard,
405706f2543Smrg				      iWindow,
406706f2543Smrg				      CurrentTime);
407706f2543Smrg
408706f2543Smrg	if (iReturn == BadAtom || iReturn == BadWindow ||
409706f2543Smrg	    XGetSelectionOwner (pDisplay, atomClipboard) != iWindow)
410706f2543Smrg	  {
411706f2543Smrg	    winErrorFVerb (1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
412706f2543Smrg		    "Could not reassert ownership of CLIPBOARD\n");
413706f2543Smrg	  }
414706f2543Smrg	else
415706f2543Smrg	  {
416706f2543Smrg	    winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
417706f2543Smrg		    "Reasserted ownership of CLIPBOARD\n");
418706f2543Smrg	  }
419706f2543Smrg
420706f2543Smrg	/* Flush the pending SetSelectionOwner event now */
421706f2543Smrg	XFlush (pDisplay);
422706f2543Smrg
423706f2543Smrg	s_fProcessingDrawClipboard = FALSE;
424706f2543Smrg      }
425706f2543Smrg      winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
426706f2543Smrg      /* Pass the message on the next window in the clipboard viewer chain */
427706f2543Smrg      if (s_hwndNextViewer)
428706f2543Smrg	SendMessage (s_hwndNextViewer, message, wParam, lParam);
429706f2543Smrg      return 0;
430706f2543Smrg
431706f2543Smrg
432706f2543Smrg    case WM_DESTROYCLIPBOARD:
433706f2543Smrg      /*
434706f2543Smrg       * NOTE: Intentionally do nothing.
435706f2543Smrg       * Changes in the Win32 clipboard are handled by WM_DRAWCLIPBOARD
436706f2543Smrg       * above.  We only process this message to conform to the specs
437706f2543Smrg       * for delayed clipboard rendering in Win32.  You might think
438706f2543Smrg       * that we need to release ownership of the X11 selections, but
439706f2543Smrg       * we do not, because a WM_DRAWCLIPBOARD message will closely
440706f2543Smrg       * follow this message and reassert ownership of the X11
441706f2543Smrg       * selections, handling the issue for us.
442706f2543Smrg       */
443706f2543Smrg      winDebug ("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n");
444706f2543Smrg      return 0;
445706f2543Smrg
446706f2543Smrg    case WM_RENDERFORMAT:
447706f2543Smrg    case WM_RENDERALLFORMATS:
448706f2543Smrg      {
449706f2543Smrg	int	iReturn;
450706f2543Smrg	Display *pDisplay = g_pClipboardDisplay;
451706f2543Smrg	Window	iWindow = g_iClipboardWindow;
452706f2543Smrg	Bool	fConvertToUnicode;
453706f2543Smrg
454706f2543Smrg	winDebug ("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n");
455706f2543Smrg
456706f2543Smrg	/* Flag whether to convert to Unicode or not */
457706f2543Smrg	if (message == WM_RENDERALLFORMATS)
458706f2543Smrg	  fConvertToUnicode = FALSE;
459706f2543Smrg	else
460706f2543Smrg	  fConvertToUnicode = g_fUnicodeSupport && (CF_UNICODETEXT == wParam);
461706f2543Smrg
462706f2543Smrg	/* Request the selection contents */
463706f2543Smrg	iReturn = XConvertSelection (pDisplay,
464706f2543Smrg				     g_atomLastOwnedSelection,
465706f2543Smrg				     XInternAtom (pDisplay,
466706f2543Smrg						  "COMPOUND_TEXT", False),
467706f2543Smrg				     XInternAtom (pDisplay,
468706f2543Smrg						  "CYGX_CUT_BUFFER", False),
469706f2543Smrg				     iWindow,
470706f2543Smrg				     CurrentTime);
471706f2543Smrg	if (iReturn == BadAtom || iReturn == BadWindow)
472706f2543Smrg	  {
473706f2543Smrg	    winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMAT - "
474706f2543Smrg		    "XConvertSelection () failed\n");
475706f2543Smrg	    break;
476706f2543Smrg	  }
477706f2543Smrg
478706f2543Smrg	/* Special handling for WM_RENDERALLFORMATS */
479706f2543Smrg	if (message == WM_RENDERALLFORMATS)
480706f2543Smrg	  {
481706f2543Smrg	    /* We must open and empty the clipboard */
482706f2543Smrg
483706f2543Smrg	    /* Close clipboard if we have it open already */
484706f2543Smrg	    if (GetOpenClipboardWindow () == hwnd)
485706f2543Smrg	      {
486706f2543Smrg		CloseClipboard ();
487706f2543Smrg	      }
488706f2543Smrg
489706f2543Smrg	    if (!OpenClipboard (hwnd))
490706f2543Smrg	      {
491706f2543Smrg		winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
492706f2543Smrg			"OpenClipboard () failed: %08x\n",
493706f2543Smrg			GetLastError ());
494706f2543Smrg		break;
495706f2543Smrg	      }
496706f2543Smrg
497706f2543Smrg	    if (!EmptyClipboard ())
498706f2543Smrg	      {
499706f2543Smrg		winErrorFVerb (1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
500706f2543Smrg			"EmptyClipboard () failed: %08x\n",
501706f2543Smrg		      GetLastError ());
502706f2543Smrg		break;
503706f2543Smrg	      }
504706f2543Smrg	  }
505706f2543Smrg
506706f2543Smrg	/* Process the SelectionNotify event */
507706f2543Smrg	iReturn = winProcessXEventsTimeout (hwnd,
508706f2543Smrg					    iWindow,
509706f2543Smrg					    pDisplay,
510706f2543Smrg					    fConvertToUnicode,
511706f2543Smrg					    WIN_POLL_TIMEOUT);
512706f2543Smrg	if (WIN_XEVENTS_CONVERT == iReturn)
513706f2543Smrg	  {
514706f2543Smrg	    /*
515706f2543Smrg	     * The selection was offered for conversion first, so we have
516706f2543Smrg	     * to process a second SelectionNotify event to get the actual
517706f2543Smrg	     * data in the selection.
518706f2543Smrg	     */
519706f2543Smrg	    iReturn = winProcessXEventsTimeout (hwnd,
520706f2543Smrg						iWindow,
521706f2543Smrg						pDisplay,
522706f2543Smrg						fConvertToUnicode,
523706f2543Smrg						WIN_POLL_TIMEOUT);
524706f2543Smrg	  }
525706f2543Smrg
526706f2543Smrg	/*
527706f2543Smrg	 * The last of the up-to two calls to winProcessXEventsTimeout
528706f2543Smrg	 * from above had better have seen a notify event, or else we
529706f2543Smrg	 * are dealing with a buggy or old X11 app.  In these cases we
530706f2543Smrg	 * have to paste some fake data to the Win32 clipboard to
531706f2543Smrg	 * satisfy the requirement that we write something to it.
532706f2543Smrg	 */
533706f2543Smrg	if (WIN_XEVENTS_NOTIFY != iReturn)
534706f2543Smrg	  {
535706f2543Smrg	    /* Paste no data, to satisfy required call to SetClipboardData */
536706f2543Smrg	    if (g_fUnicodeSupport)
537706f2543Smrg	      SetClipboardData (CF_UNICODETEXT, NULL);
538706f2543Smrg	    SetClipboardData (CF_TEXT, NULL);
539706f2543Smrg
540706f2543Smrg            ErrorF("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY\n");
541706f2543Smrg	  }
542706f2543Smrg
543706f2543Smrg	/* BPS - Post ourselves a user message whose handler will reset the
544706f2543Smrg	 * delayed rendering mechanism after the paste is complete. This is
545706f2543Smrg	 * necessary because calling SetClipboardData() with a NULL argument
546706f2543Smrg	 * here will cause the data we just put on the clipboard to be lost!
547706f2543Smrg	 */
548706f2543Smrg	PostMessage(g_hwndClipboard, WM_USER_PASTE_COMPLETE, 0, 0);
549706f2543Smrg
550706f2543Smrg	/* Special handling for WM_RENDERALLFORMATS */
551706f2543Smrg	if (message == WM_RENDERALLFORMATS)
552706f2543Smrg	  {
553706f2543Smrg	    /* We must close the clipboard */
554706f2543Smrg
555706f2543Smrg	    if (!CloseClipboard ())
556706f2543Smrg	      {
557706f2543Smrg	      winErrorFVerb (1, "winClipboardWindowProc - WM_RENDERALLFORMATS - "
558706f2543Smrg		      "CloseClipboard () failed: %08x\n",
559706f2543Smrg		      GetLastError ());
560706f2543Smrg	      break;
561706f2543Smrg	      }
562706f2543Smrg	  }
563706f2543Smrg
564706f2543Smrg	winDebug ("winClipboardWindowProc - WM_RENDER*FORMAT - Returning.\n");
565706f2543Smrg	return 0;
566706f2543Smrg      }
567706f2543Smrg    /* BPS - This WM_USER message is posted by us. It gives us the opportunity
568706f2543Smrg     * to reset the delayed rendering mechanism after each and every paste
569706f2543Smrg     * from an X app to a Windows app. Without such a mechanism, subsequent
570706f2543Smrg     * changes of selection in the X app owning the selection are not
571706f2543Smrg     * reflected in pastes into Windows apps, since Windows won't send us the
572706f2543Smrg     * WM_RENDERFORMAT message unless someone has set changed data (or NULL)
573706f2543Smrg     * on the clipboard. */
574706f2543Smrg    case WM_USER_PASTE_COMPLETE:
575706f2543Smrg      {
576706f2543Smrg	if (hwnd != GetClipboardOwner ())
577706f2543Smrg	  /* In case we've lost the selection since posting the message */
578706f2543Smrg	  return 0;
579706f2543Smrg	winDebug ("winClipboardWindowProc - WM_USER_PASTE_COMPLETE\n");
580706f2543Smrg
581706f2543Smrg	/* Set up for another delayed rendering callback */
582706f2543Smrg	OpenClipboard (g_hwndClipboard);
583706f2543Smrg
584706f2543Smrg	/* Take ownership of the Windows clipboard */
585706f2543Smrg	EmptyClipboard ();
586706f2543Smrg
587706f2543Smrg	/* Advertise Unicode if we support it */
588706f2543Smrg	if (g_fUnicodeSupport)
589706f2543Smrg	  SetClipboardData (CF_UNICODETEXT, NULL);
590706f2543Smrg
591706f2543Smrg	/* Always advertise regular text */
592706f2543Smrg	SetClipboardData (CF_TEXT, NULL);
593706f2543Smrg
594706f2543Smrg	/* Release the clipboard */
595706f2543Smrg	CloseClipboard ();
596706f2543Smrg      }
597706f2543Smrg      return 0;
598706f2543Smrg    }
599706f2543Smrg
600706f2543Smrg  /* Let Windows perform default processing for unhandled messages */
601706f2543Smrg  return DefWindowProc (hwnd, message, wParam, lParam);
602706f2543Smrg}
603706f2543Smrg
604706f2543Smrg
605706f2543Smrg/*
606706f2543Smrg * Process any pending Windows messages
607706f2543Smrg */
608706f2543Smrg
609706f2543SmrgBOOL
610706f2543SmrgwinClipboardFlushWindowsMessageQueue (HWND hwnd)
611706f2543Smrg{
612706f2543Smrg  MSG			msg;
613706f2543Smrg
614706f2543Smrg  /* Flush the messaging window queue */
615706f2543Smrg  /* NOTE: Do not pass the hwnd of our messaging window to PeekMessage,
616706f2543Smrg   * as this will filter out many non-window-specific messages that
617706f2543Smrg   * are sent to our thread, such as WM_QUIT.
618706f2543Smrg   */
619706f2543Smrg  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
620706f2543Smrg    {
621706f2543Smrg      /* Dispatch the message if not WM_QUIT */
622706f2543Smrg      if (msg.message == WM_QUIT)
623706f2543Smrg	return FALSE;
624706f2543Smrg      else
625706f2543Smrg	DispatchMessage (&msg);
626706f2543Smrg    }
627706f2543Smrg
628706f2543Smrg  return TRUE;
629706f2543Smrg}
630