xref: /OK3568_Linux_fs/external/xserver/hw/xwin/winclipboard/wndproc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
3*4882a593Smuzhiyun  *Copyright (C) Colin Harrison 2005-2008
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *Permission is hereby granted, free of charge, to any person obtaining
6*4882a593Smuzhiyun  * a copy of this software and associated documentation files (the
7*4882a593Smuzhiyun  *"Software"), to deal in the Software without restriction, including
8*4882a593Smuzhiyun  *without limitation the rights to use, copy, modify, merge, publish,
9*4882a593Smuzhiyun  *distribute, sublicense, and/or sell copies of the Software, and to
10*4882a593Smuzhiyun  *permit persons to whom the Software is furnished to do so, subject to
11*4882a593Smuzhiyun  *the following conditions:
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *The above copyright notice and this permission notice shall be
14*4882a593Smuzhiyun  *included in all copies or substantial portions of the Software.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*4882a593Smuzhiyun  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*4882a593Smuzhiyun  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*4882a593Smuzhiyun  *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
20*4882a593Smuzhiyun  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21*4882a593Smuzhiyun  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22*4882a593Smuzhiyun  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *Except as contained in this notice, the name of the copyright holder(s)
25*4882a593Smuzhiyun  *and author(s) shall not be used in advertising or otherwise to promote
26*4882a593Smuzhiyun  *the sale, use or other dealings in this Software without prior written
27*4882a593Smuzhiyun  *authorization from the copyright holder(s) and author(s).
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * Authors:	Harold L Hunt II
30*4882a593Smuzhiyun  *              Colin Harrison
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #ifdef HAVE_XWIN_CONFIG_H
34*4882a593Smuzhiyun #include <xwin-config.h>
35*4882a593Smuzhiyun #endif
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun  * Including any server header might define the macro _XSERVER64 on 64 bit machines.
39*4882a593Smuzhiyun  * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
40*4882a593Smuzhiyun  * So let's undef that macro if necessary.
41*4882a593Smuzhiyun  */
42*4882a593Smuzhiyun #ifdef _XSERVER64
43*4882a593Smuzhiyun #undef _XSERVER64
44*4882a593Smuzhiyun #endif
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #include <sys/types.h>
47*4882a593Smuzhiyun #include <sys/time.h>
48*4882a593Smuzhiyun #include <limits.h>
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #include <X11/Xatom.h>
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #include "internal.h"
53*4882a593Smuzhiyun #include "winclipboard.h"
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun  * Constants
57*4882a593Smuzhiyun  */
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define WIN_POLL_TIMEOUT	1
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #ifndef WM_CLIPBOARDUPDATE
62*4882a593Smuzhiyun #define WM_CLIPBOARDUPDATE 0x031D
63*4882a593Smuzhiyun #endif
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * Process X events up to specified timeout
67*4882a593Smuzhiyun  */
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun static int
winProcessXEventsTimeout(HWND hwnd,Window iWindow,Display * pDisplay,ClipboardConversionData * data,ClipboardAtoms * atoms,int iTimeoutSec)70*4882a593Smuzhiyun winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
71*4882a593Smuzhiyun                          ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun     int iConnNumber;
74*4882a593Smuzhiyun     struct timeval tv;
75*4882a593Smuzhiyun     int iReturn;
76*4882a593Smuzhiyun     DWORD dwStopTime = GetTickCount() + iTimeoutSec * 1000;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun     winDebug("winProcessXEventsTimeout () - pumping X events for %d seconds\n",
79*4882a593Smuzhiyun              iTimeoutSec);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun     /* Get our connection number */
82*4882a593Smuzhiyun     iConnNumber = ConnectionNumber(pDisplay);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun     /* Loop for X events */
85*4882a593Smuzhiyun     while (1) {
86*4882a593Smuzhiyun         fd_set fdsRead;
87*4882a593Smuzhiyun         long remainingTime;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun         /* Process X events */
90*4882a593Smuzhiyun         iReturn = winClipboardFlushXEvents(hwnd, iWindow, pDisplay, data, atoms);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun         winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun         if ((WIN_XEVENTS_NOTIFY_DATA == iReturn) || (WIN_XEVENTS_NOTIFY_TARGETS == iReturn) || (WIN_XEVENTS_FAILED == iReturn)) {
95*4882a593Smuzhiyun           /* Bail out */
96*4882a593Smuzhiyun           return iReturn;
97*4882a593Smuzhiyun         }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun         /* We need to ensure that all pending requests are sent */
100*4882a593Smuzhiyun         XFlush(pDisplay);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun         /* Setup the file descriptor set */
103*4882a593Smuzhiyun         FD_ZERO(&fdsRead);
104*4882a593Smuzhiyun         FD_SET(iConnNumber, &fdsRead);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun         /* Adjust timeout */
107*4882a593Smuzhiyun         remainingTime = dwStopTime - GetTickCount();
108*4882a593Smuzhiyun         tv.tv_sec = remainingTime / 1000;
109*4882a593Smuzhiyun         tv.tv_usec = (remainingTime % 1000) * 1000;
110*4882a593Smuzhiyun         winDebug("winProcessXEventsTimeout () - %ld milliseconds left\n",
111*4882a593Smuzhiyun                  remainingTime);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun         /* Break out if no time left */
114*4882a593Smuzhiyun         if (remainingTime <= 0)
115*4882a593Smuzhiyun             return WIN_XEVENTS_SUCCESS;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun         /* Wait for an X event */
118*4882a593Smuzhiyun         iReturn = select(iConnNumber + 1,       /* Highest fds number */
119*4882a593Smuzhiyun                          &fdsRead,      /* Read mask */
120*4882a593Smuzhiyun                          NULL,  /* No write mask */
121*4882a593Smuzhiyun                          NULL,  /* No exception mask */
122*4882a593Smuzhiyun                          &tv);  /* Timeout */
123*4882a593Smuzhiyun         if (iReturn < 0) {
124*4882a593Smuzhiyun             ErrorF("winProcessXEventsTimeout - Call to select () failed: %d.  "
125*4882a593Smuzhiyun                    "Bailing.\n", iReturn);
126*4882a593Smuzhiyun             break;
127*4882a593Smuzhiyun         }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun         if (!FD_ISSET(iConnNumber, &fdsRead)) {
130*4882a593Smuzhiyun             winDebug("winProcessXEventsTimeout - Spurious wake, select() returned %d\n", iReturn);
131*4882a593Smuzhiyun         }
132*4882a593Smuzhiyun     }
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun     return WIN_XEVENTS_SUCCESS;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun /*
138*4882a593Smuzhiyun  * Process a given Windows message
139*4882a593Smuzhiyun  */
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)142*4882a593Smuzhiyun winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun     static HWND s_hwndNextViewer;
145*4882a593Smuzhiyun     static Bool s_fCBCInitialized;
146*4882a593Smuzhiyun     static Display *pDisplay;
147*4882a593Smuzhiyun     static Window iWindow;
148*4882a593Smuzhiyun     static ClipboardAtoms *atoms;
149*4882a593Smuzhiyun     static Bool fRunning;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun     /* Branch on message type */
152*4882a593Smuzhiyun     switch (message) {
153*4882a593Smuzhiyun     case WM_DESTROY:
154*4882a593Smuzhiyun     {
155*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_DESTROY\n");
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun         if (g_fHasModernClipboardApi)
158*4882a593Smuzhiyun             {
159*4882a593Smuzhiyun                 /* Remove clipboard listener */
160*4882a593Smuzhiyun                 g_fpRemoveClipboardFormatListener(hwnd);
161*4882a593Smuzhiyun             }
162*4882a593Smuzhiyun         else
163*4882a593Smuzhiyun             {
164*4882a593Smuzhiyun                 /* Remove ourselves from the clipboard chain */
165*4882a593Smuzhiyun                 ChangeClipboardChain(hwnd, s_hwndNextViewer);
166*4882a593Smuzhiyun             }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun         s_hwndNextViewer = NULL;
169*4882a593Smuzhiyun     }
170*4882a593Smuzhiyun         return 0;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun     case WM_WM_QUIT:
173*4882a593Smuzhiyun     {
174*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_WM_QUIT\n");
175*4882a593Smuzhiyun         fRunning = FALSE;
176*4882a593Smuzhiyun         PostQuitMessage(0);
177*4882a593Smuzhiyun     }
178*4882a593Smuzhiyun         return 0;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun     case WM_CREATE:
181*4882a593Smuzhiyun     {
182*4882a593Smuzhiyun         ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_CREATE\n");
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun         pDisplay = cwcp->pClipboardDisplay;
187*4882a593Smuzhiyun         iWindow = cwcp->iClipboardWindow;
188*4882a593Smuzhiyun         atoms = cwcp->atoms;
189*4882a593Smuzhiyun         fRunning = TRUE;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun         if (g_fHasModernClipboardApi)
192*4882a593Smuzhiyun             {
193*4882a593Smuzhiyun                 g_fpAddClipboardFormatListener(hwnd);
194*4882a593Smuzhiyun             }
195*4882a593Smuzhiyun         else
196*4882a593Smuzhiyun             {
197*4882a593Smuzhiyun                 HWND first, next;
198*4882a593Smuzhiyun                 DWORD error_code = 0;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun                 first = GetClipboardViewer();   /* Get handle to first viewer in chain. */
201*4882a593Smuzhiyun                 if (first == hwnd)
202*4882a593Smuzhiyun                     return 0;           /* Make sure it's not us! */
203*4882a593Smuzhiyun                 /* Add ourselves to the clipboard viewer chain */
204*4882a593Smuzhiyun                 next = SetClipboardViewer(hwnd);
205*4882a593Smuzhiyun                 error_code = GetLastError();
206*4882a593Smuzhiyun                 if (SUCCEEDED(error_code) && (next == first))   /* SetClipboardViewer must have succeeded, and the handle */
207*4882a593Smuzhiyun                     s_hwndNextViewer = next;    /* it returned must have been the first window in the chain */
208*4882a593Smuzhiyun                 else
209*4882a593Smuzhiyun                     s_fCBCInitialized = FALSE;
210*4882a593Smuzhiyun             }
211*4882a593Smuzhiyun     }
212*4882a593Smuzhiyun         return 0;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun     case WM_CHANGECBCHAIN:
215*4882a593Smuzhiyun     {
216*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: wParam(%p) "
217*4882a593Smuzhiyun                  "lParam(%p) s_hwndNextViewer(%p)\n",
218*4882a593Smuzhiyun                  (HWND)wParam, (HWND)lParam, s_hwndNextViewer);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun         if ((HWND) wParam == s_hwndNextViewer) {
221*4882a593Smuzhiyun             s_hwndNextViewer = (HWND) lParam;
222*4882a593Smuzhiyun             if (s_hwndNextViewer == hwnd) {
223*4882a593Smuzhiyun                 s_hwndNextViewer = NULL;
224*4882a593Smuzhiyun                 ErrorF("winClipboardWindowProc - WM_CHANGECBCHAIN: "
225*4882a593Smuzhiyun                        "attempted to set next window to ourselves.");
226*4882a593Smuzhiyun             }
227*4882a593Smuzhiyun         }
228*4882a593Smuzhiyun         else if (s_hwndNextViewer)
229*4882a593Smuzhiyun             SendMessage(s_hwndNextViewer, message, wParam, lParam);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun     }
232*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: Exit\n");
233*4882a593Smuzhiyun         return 0;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun     case WM_WM_REINIT:
236*4882a593Smuzhiyun     {
237*4882a593Smuzhiyun         /* Ensure that we're in the clipboard chain.  Some apps,
238*4882a593Smuzhiyun          * WinXP's remote desktop for one, don't play nice with the
239*4882a593Smuzhiyun          * chain.  This message is called whenever we receive a
240*4882a593Smuzhiyun          * WM_ACTIVATEAPP message to ensure that we continue to
241*4882a593Smuzhiyun          * receive clipboard messages.
242*4882a593Smuzhiyun          *
243*4882a593Smuzhiyun          * It might be possible to detect if we're still in the chain
244*4882a593Smuzhiyun          * by calling SendMessage (GetClipboardViewer(),
245*4882a593Smuzhiyun          * WM_DRAWCLIPBOARD, 0, 0); and then seeing if we get the
246*4882a593Smuzhiyun          * WM_DRAWCLIPBOARD message.  That, however, might be more
247*4882a593Smuzhiyun          * expensive than just putting ourselves back into the chain.
248*4882a593Smuzhiyun          */
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun         HWND first, next;
251*4882a593Smuzhiyun         DWORD error_code = 0;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_WM_REINIT: Enter\n");
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun         if (g_fHasModernClipboardApi)
256*4882a593Smuzhiyun             {
257*4882a593Smuzhiyun                 return 0;
258*4882a593Smuzhiyun             }
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun         first = GetClipboardViewer();   /* Get handle to first viewer in chain. */
261*4882a593Smuzhiyun         if (first == hwnd)
262*4882a593Smuzhiyun             return 0;           /* Make sure it's not us! */
263*4882a593Smuzhiyun         winDebug("  WM_WM_REINIT: Replacing us(%p) with %p at head "
264*4882a593Smuzhiyun                  "of chain\n", hwnd, s_hwndNextViewer);
265*4882a593Smuzhiyun         s_fCBCInitialized = FALSE;
266*4882a593Smuzhiyun         ChangeClipboardChain(hwnd, s_hwndNextViewer);
267*4882a593Smuzhiyun         s_hwndNextViewer = NULL;
268*4882a593Smuzhiyun         s_fCBCInitialized = FALSE;
269*4882a593Smuzhiyun         winDebug("  WM_WM_REINIT: Putting us back at head of chain.\n");
270*4882a593Smuzhiyun         first = GetClipboardViewer();   /* Get handle to first viewer in chain. */
271*4882a593Smuzhiyun         if (first == hwnd)
272*4882a593Smuzhiyun             return 0;           /* Make sure it's not us! */
273*4882a593Smuzhiyun         next = SetClipboardViewer(hwnd);
274*4882a593Smuzhiyun         error_code = GetLastError();
275*4882a593Smuzhiyun         if (SUCCEEDED(error_code) && (next == first))   /* SetClipboardViewer must have succeeded, and the handle */
276*4882a593Smuzhiyun             s_hwndNextViewer = next;    /* it returned must have been the first window in the chain */
277*4882a593Smuzhiyun         else
278*4882a593Smuzhiyun             s_fCBCInitialized = FALSE;
279*4882a593Smuzhiyun     }
280*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_WM_REINIT: Exit\n");
281*4882a593Smuzhiyun         return 0;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun     case WM_DRAWCLIPBOARD:
284*4882a593Smuzhiyun     case WM_CLIPBOARDUPDATE:
285*4882a593Smuzhiyun     {
286*4882a593Smuzhiyun         static Bool s_fProcessingDrawClipboard = FALSE;
287*4882a593Smuzhiyun         int iReturn;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun         if (message == WM_DRAWCLIPBOARD)
290*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n");
291*4882a593Smuzhiyun         else
292*4882a593Smuzhiyun             winDebug("winClipboardWindowProc -  WM_CLIPBOARDUPDATE: Enter\n");
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun         if (!g_fHasModernClipboardApi)
295*4882a593Smuzhiyun             {
296*4882a593Smuzhiyun                 /*
297*4882a593Smuzhiyun                  * We've occasionally seen a loop in the clipboard chain.
298*4882a593Smuzhiyun                  * Try and fix it on the first hint of recursion.
299*4882a593Smuzhiyun                  */
300*4882a593Smuzhiyun                 if (!s_fProcessingDrawClipboard) {
301*4882a593Smuzhiyun                     s_fProcessingDrawClipboard = TRUE;
302*4882a593Smuzhiyun                 }
303*4882a593Smuzhiyun                 else {
304*4882a593Smuzhiyun                     /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */
305*4882a593Smuzhiyun                     s_fCBCInitialized = FALSE;
306*4882a593Smuzhiyun                     ChangeClipboardChain(hwnd, s_hwndNextViewer);
307*4882a593Smuzhiyun                     winFixClipboardChain();
308*4882a593Smuzhiyun                     ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
309*4882a593Smuzhiyun                            "Nested calls detected.  Re-initing.\n");
310*4882a593Smuzhiyun                     winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
311*4882a593Smuzhiyun                     s_fProcessingDrawClipboard = FALSE;
312*4882a593Smuzhiyun                     return 0;
313*4882a593Smuzhiyun                 }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun                 /* Bail on first message */
316*4882a593Smuzhiyun                 if (!s_fCBCInitialized) {
317*4882a593Smuzhiyun                     s_fCBCInitialized = TRUE;
318*4882a593Smuzhiyun                     s_fProcessingDrawClipboard = FALSE;
319*4882a593Smuzhiyun                     winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
320*4882a593Smuzhiyun                     return 0;
321*4882a593Smuzhiyun                 }
322*4882a593Smuzhiyun             }
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun         /*
325*4882a593Smuzhiyun          * NOTE: We cannot bail out when NULL == GetClipboardOwner ()
326*4882a593Smuzhiyun          * because some applications deal with the clipboard in a manner
327*4882a593Smuzhiyun          * that causes the clipboard owner to be NULL when they are in
328*4882a593Smuzhiyun          * fact taking ownership.  One example of this is the Win32
329*4882a593Smuzhiyun          * native compile of emacs.
330*4882a593Smuzhiyun          */
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun         /* Bail when we still own the clipboard */
333*4882a593Smuzhiyun         if (hwnd == GetClipboardOwner()) {
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
336*4882a593Smuzhiyun                      "We own the clipboard, returning.\n");
337*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
338*4882a593Smuzhiyun             s_fProcessingDrawClipboard = FALSE;
339*4882a593Smuzhiyun             if (s_hwndNextViewer)
340*4882a593Smuzhiyun                 SendMessage(s_hwndNextViewer, message, wParam, lParam);
341*4882a593Smuzhiyun             return 0;
342*4882a593Smuzhiyun         }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun         /* Bail when shutting down */
345*4882a593Smuzhiyun         if (!fRunning)
346*4882a593Smuzhiyun             return 0;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun         /*
349*4882a593Smuzhiyun          * Do not take ownership of the X11 selections when something
350*4882a593Smuzhiyun          * other than CF_TEXT or CF_UNICODETEXT has been copied
351*4882a593Smuzhiyun          * into the Win32 clipboard.
352*4882a593Smuzhiyun          */
353*4882a593Smuzhiyun         if (!IsClipboardFormatAvailable(CF_TEXT)
354*4882a593Smuzhiyun             && !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
357*4882a593Smuzhiyun                      "Clipboard does not contain CF_TEXT nor "
358*4882a593Smuzhiyun                      "CF_UNICODETEXT.\n");
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun             /*
361*4882a593Smuzhiyun              * We need to make sure that the X Server has processed
362*4882a593Smuzhiyun              * previous XSetSelectionOwner messages.
363*4882a593Smuzhiyun              */
364*4882a593Smuzhiyun             XSync(pDisplay, FALSE);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - XSync done.\n");
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun             /* Release PRIMARY selection if owned */
369*4882a593Smuzhiyun             iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
370*4882a593Smuzhiyun             if (iReturn == iWindow) {
371*4882a593Smuzhiyun                 winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
372*4882a593Smuzhiyun                          "PRIMARY selection is owned by us.\n");
373*4882a593Smuzhiyun                 XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
374*4882a593Smuzhiyun             }
375*4882a593Smuzhiyun             else if (BadWindow == iReturn || BadAtom == iReturn)
376*4882a593Smuzhiyun                 ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
377*4882a593Smuzhiyun                        "XGetSelectionOwner failed for PRIMARY: %d\n",
378*4882a593Smuzhiyun                        iReturn);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun             /* Release CLIPBOARD selection if owned */
381*4882a593Smuzhiyun             iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
382*4882a593Smuzhiyun             if (iReturn == iWindow) {
383*4882a593Smuzhiyun                 winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
384*4882a593Smuzhiyun                          "CLIPBOARD selection is owned by us, releasing\n");
385*4882a593Smuzhiyun                 XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
386*4882a593Smuzhiyun             }
387*4882a593Smuzhiyun             else if (BadWindow == iReturn || BadAtom == iReturn)
388*4882a593Smuzhiyun                 ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
389*4882a593Smuzhiyun                        "XGetSelectionOwner failed for CLIPBOARD: %d\n",
390*4882a593Smuzhiyun                        iReturn);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
393*4882a593Smuzhiyun             s_fProcessingDrawClipboard = FALSE;
394*4882a593Smuzhiyun             if (s_hwndNextViewer)
395*4882a593Smuzhiyun                 SendMessage(s_hwndNextViewer, message, wParam, lParam);
396*4882a593Smuzhiyun             return 0;
397*4882a593Smuzhiyun         }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun         /* Reassert ownership of PRIMARY */
400*4882a593Smuzhiyun         iReturn = XSetSelectionOwner(pDisplay,
401*4882a593Smuzhiyun                                      XA_PRIMARY, iWindow, CurrentTime);
402*4882a593Smuzhiyun         if (iReturn == BadAtom || iReturn == BadWindow ||
403*4882a593Smuzhiyun             XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
404*4882a593Smuzhiyun             ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
405*4882a593Smuzhiyun                    "Could not reassert ownership of PRIMARY\n");
406*4882a593Smuzhiyun         }
407*4882a593Smuzhiyun         else {
408*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
409*4882a593Smuzhiyun                      "Reasserted ownership of PRIMARY\n");
410*4882a593Smuzhiyun         }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun         /* Reassert ownership of the CLIPBOARD */
413*4882a593Smuzhiyun         iReturn = XSetSelectionOwner(pDisplay,
414*4882a593Smuzhiyun                                      atoms->atomClipboard, iWindow, CurrentTime);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun         if (iReturn == BadAtom || iReturn == BadWindow ||
417*4882a593Smuzhiyun             XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
418*4882a593Smuzhiyun             ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
419*4882a593Smuzhiyun                     "Could not reassert ownership of CLIPBOARD\n");
420*4882a593Smuzhiyun         }
421*4882a593Smuzhiyun         else {
422*4882a593Smuzhiyun             winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
423*4882a593Smuzhiyun                      "Reasserted ownership of CLIPBOARD\n");
424*4882a593Smuzhiyun         }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun         /* Flush the pending SetSelectionOwner event now */
427*4882a593Smuzhiyun         XFlush(pDisplay);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun         s_fProcessingDrawClipboard = FALSE;
430*4882a593Smuzhiyun     }
431*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
432*4882a593Smuzhiyun         /* Pass the message on the next window in the clipboard viewer chain */
433*4882a593Smuzhiyun         if (s_hwndNextViewer)
434*4882a593Smuzhiyun             SendMessage(s_hwndNextViewer, message, wParam, lParam);
435*4882a593Smuzhiyun         return 0;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun     case WM_DESTROYCLIPBOARD:
438*4882a593Smuzhiyun         /*
439*4882a593Smuzhiyun          * NOTE: Intentionally do nothing.
440*4882a593Smuzhiyun          * Changes in the Win32 clipboard are handled by WM_DRAWCLIPBOARD
441*4882a593Smuzhiyun          * above.  We only process this message to conform to the specs
442*4882a593Smuzhiyun          * for delayed clipboard rendering in Win32.  You might think
443*4882a593Smuzhiyun          * that we need to release ownership of the X11 selections, but
444*4882a593Smuzhiyun          * we do not, because a WM_DRAWCLIPBOARD message will closely
445*4882a593Smuzhiyun          * follow this message and reassert ownership of the X11
446*4882a593Smuzhiyun          * selections, handling the issue for us.
447*4882a593Smuzhiyun          */
448*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n");
449*4882a593Smuzhiyun         return 0;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun     case WM_RENDERALLFORMATS:
452*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_RENDERALLFORMATS - Hello.\n");
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun         /*
455*4882a593Smuzhiyun           WM_RENDERALLFORMATS is sent as we are shutting down, to render the
456*4882a593Smuzhiyun           clipboard so it's contents remains available to other applications.
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun           Unfortunately, this can't work without major changes. The server is
459*4882a593Smuzhiyun           already waiting for us to stop, so we can't ask for the rendering of
460*4882a593Smuzhiyun           clipboard text now.
461*4882a593Smuzhiyun         */
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun         return 0;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun     case WM_RENDERFORMAT:
466*4882a593Smuzhiyun     {
467*4882a593Smuzhiyun         int iReturn;
468*4882a593Smuzhiyun         Bool fConvertToUnicode;
469*4882a593Smuzhiyun         Bool pasted = FALSE;
470*4882a593Smuzhiyun         Atom selection;
471*4882a593Smuzhiyun         ClipboardConversionData data;
472*4882a593Smuzhiyun         int best_target = 0;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_RENDERFORMAT %d - Hello.\n",
475*4882a593Smuzhiyun                  (int)wParam);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun         /* Flag whether to convert to Unicode or not */
478*4882a593Smuzhiyun         fConvertToUnicode = (CF_UNICODETEXT == wParam);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun         selection = winClipboardGetLastOwnedSelectionAtom(atoms);
481*4882a593Smuzhiyun         if (selection == None) {
482*4882a593Smuzhiyun             ErrorF("winClipboardWindowProc - no monitored selection is owned\n");
483*4882a593Smuzhiyun             goto fake_paste;
484*4882a593Smuzhiyun         }
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - requesting targets for selection from owner\n");
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun         /* Request the selection's supported conversion targets */
489*4882a593Smuzhiyun         XConvertSelection(pDisplay,
490*4882a593Smuzhiyun                           selection,
491*4882a593Smuzhiyun                           atoms->atomTargets,
492*4882a593Smuzhiyun                           atoms->atomLocalProperty,
493*4882a593Smuzhiyun                           iWindow, CurrentTime);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun         /* Process X events */
496*4882a593Smuzhiyun         data.fUseUnicode = fConvertToUnicode;
497*4882a593Smuzhiyun         iReturn = winProcessXEventsTimeout(hwnd,
498*4882a593Smuzhiyun                                            iWindow,
499*4882a593Smuzhiyun                                            pDisplay,
500*4882a593Smuzhiyun                                            &data,
501*4882a593Smuzhiyun                                            atoms,
502*4882a593Smuzhiyun                                            WIN_POLL_TIMEOUT);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun         if (WIN_XEVENTS_NOTIFY_TARGETS != iReturn) {
505*4882a593Smuzhiyun             ErrorF
506*4882a593Smuzhiyun                 ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_TARGETS\n");
507*4882a593Smuzhiyun             goto fake_paste;
508*4882a593Smuzhiyun         }
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun         /* Choose the most preferred target */
511*4882a593Smuzhiyun         {
512*4882a593Smuzhiyun             struct target_priority
513*4882a593Smuzhiyun             {
514*4882a593Smuzhiyun                 Atom target;
515*4882a593Smuzhiyun                 unsigned int priority;
516*4882a593Smuzhiyun             };
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun             struct target_priority target_priority_table[] =
519*4882a593Smuzhiyun                 {
520*4882a593Smuzhiyun                     { atoms->atomCompoundText, 0 },
521*4882a593Smuzhiyun #ifdef X_HAVE_UTF8_STRING
522*4882a593Smuzhiyun                     { atoms->atomUTF8String,   1 },
523*4882a593Smuzhiyun #endif
524*4882a593Smuzhiyun                     { XA_STRING,               2 },
525*4882a593Smuzhiyun                 };
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun             int best_priority = INT_MAX;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun             int i,j;
530*4882a593Smuzhiyun             for (i = 0 ; data.targetList[i] != 0; i++)
531*4882a593Smuzhiyun                 {
532*4882a593Smuzhiyun                     for (j = 0; j < ARRAY_SIZE(target_priority_table); j ++)
533*4882a593Smuzhiyun                         {
534*4882a593Smuzhiyun                             if ((data.targetList[i] == target_priority_table[j].target) &&
535*4882a593Smuzhiyun                                 (target_priority_table[j].priority < best_priority))
536*4882a593Smuzhiyun                                 {
537*4882a593Smuzhiyun                                     best_target = target_priority_table[j].target;
538*4882a593Smuzhiyun                                     best_priority = target_priority_table[j].priority;
539*4882a593Smuzhiyun                                 }
540*4882a593Smuzhiyun                         }
541*4882a593Smuzhiyun                 }
542*4882a593Smuzhiyun         }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun         free(data.targetList);
545*4882a593Smuzhiyun         data.targetList = 0;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - best target is %d\n", best_target);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun         /* No useful targets found */
550*4882a593Smuzhiyun         if (best_target == 0)
551*4882a593Smuzhiyun           goto fake_paste;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - requesting selection from owner\n");
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun         /* Request the selection contents */
556*4882a593Smuzhiyun         XConvertSelection(pDisplay,
557*4882a593Smuzhiyun                           selection,
558*4882a593Smuzhiyun                           best_target,
559*4882a593Smuzhiyun                           atoms->atomLocalProperty,
560*4882a593Smuzhiyun                           iWindow, CurrentTime);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun         /* Process X events */
563*4882a593Smuzhiyun         iReturn = winProcessXEventsTimeout(hwnd,
564*4882a593Smuzhiyun                                            iWindow,
565*4882a593Smuzhiyun                                            pDisplay,
566*4882a593Smuzhiyun                                            &data,
567*4882a593Smuzhiyun                                            atoms,
568*4882a593Smuzhiyun                                            WIN_POLL_TIMEOUT);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun         /*
571*4882a593Smuzhiyun          * winProcessXEventsTimeout had better have seen a notify event,
572*4882a593Smuzhiyun          * or else we are dealing with a buggy or old X11 app.
573*4882a593Smuzhiyun          */
574*4882a593Smuzhiyun         if (WIN_XEVENTS_NOTIFY_DATA != iReturn) {
575*4882a593Smuzhiyun             ErrorF
576*4882a593Smuzhiyun                 ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_DATA\n");
577*4882a593Smuzhiyun         }
578*4882a593Smuzhiyun         else {
579*4882a593Smuzhiyun             pasted = TRUE;
580*4882a593Smuzhiyun         }
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun          /*
583*4882a593Smuzhiyun           * If we couldn't get the data from the X clipboard, we
584*4882a593Smuzhiyun           * have to paste some fake data to the Win32 clipboard to
585*4882a593Smuzhiyun           * satisfy the requirement that we write something to it.
586*4882a593Smuzhiyun           */
587*4882a593Smuzhiyun     fake_paste:
588*4882a593Smuzhiyun         if (!pasted)
589*4882a593Smuzhiyun           {
590*4882a593Smuzhiyun             /* Paste no data, to satisfy required call to SetClipboardData */
591*4882a593Smuzhiyun             SetClipboardData(CF_UNICODETEXT, NULL);
592*4882a593Smuzhiyun             SetClipboardData(CF_TEXT, NULL);
593*4882a593Smuzhiyun           }
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun         winDebug("winClipboardWindowProc - WM_RENDERFORMAT - Returning.\n");
596*4882a593Smuzhiyun         return 0;
597*4882a593Smuzhiyun     }
598*4882a593Smuzhiyun     }
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun     /* Let Windows perform default processing for unhandled messages */
601*4882a593Smuzhiyun     return DefWindowProc(hwnd, message, wParam, lParam);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun /*
605*4882a593Smuzhiyun  * Process any pending Windows messages
606*4882a593Smuzhiyun  */
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun Bool
winClipboardFlushWindowsMessageQueue(HWND hwnd)609*4882a593Smuzhiyun winClipboardFlushWindowsMessageQueue(HWND hwnd)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun     MSG msg;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun     /* Flush the messaging window queue */
614*4882a593Smuzhiyun     /* NOTE: Do not pass the hwnd of our messaging window to PeekMessage,
615*4882a593Smuzhiyun      * as this will filter out many non-window-specific messages that
616*4882a593Smuzhiyun      * are sent to our thread, such as WM_QUIT.
617*4882a593Smuzhiyun      */
618*4882a593Smuzhiyun     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
619*4882a593Smuzhiyun         /* Dispatch the message if not WM_QUIT */
620*4882a593Smuzhiyun         if (msg.message == WM_QUIT)
621*4882a593Smuzhiyun             return FALSE;
622*4882a593Smuzhiyun         else
623*4882a593Smuzhiyun             DispatchMessage(&msg);
624*4882a593Smuzhiyun     }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun     return TRUE;
627*4882a593Smuzhiyun }
628