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 #else
36*4882a593Smuzhiyun #define HAS_WINSOCK 1
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun * Including any server header might define the macro _XSERVER64 on 64 bit machines.
41*4882a593Smuzhiyun * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
42*4882a593Smuzhiyun * So let's undef that macro if necessary.
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun #ifdef _XSERVER64
45*4882a593Smuzhiyun #undef _XSERVER64
46*4882a593Smuzhiyun #endif
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #include <assert.h>
49*4882a593Smuzhiyun #include <unistd.h>
50*4882a593Smuzhiyun #include <fcntl.h>
51*4882a593Smuzhiyun #include <setjmp.h>
52*4882a593Smuzhiyun #include <pthread.h>
53*4882a593Smuzhiyun #include <sys/param.h> // for MAX() macro
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #ifdef HAS_WINSOCK
56*4882a593Smuzhiyun #include <X11/Xwinsock.h>
57*4882a593Smuzhiyun #else
58*4882a593Smuzhiyun #include <errno.h>
59*4882a593Smuzhiyun #endif
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun #include <X11/Xatom.h>
62*4882a593Smuzhiyun #include <X11/extensions/Xfixes.h>
63*4882a593Smuzhiyun #include "winclipboard.h"
64*4882a593Smuzhiyun #include "internal.h"
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define WIN_CONNECT_RETRIES 40
67*4882a593Smuzhiyun #define WIN_CONNECT_DELAY 4
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun #define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip"
70*4882a593Smuzhiyun #define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip"
71*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
72*4882a593Smuzhiyun #define WIN_MSG_QUEUE_FNAME "/dev/windows"
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun * Global variables
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static HWND g_hwndClipboard = NULL;
80*4882a593Smuzhiyun static jmp_buf g_jmpEntry;
81*4882a593Smuzhiyun static XIOErrorHandler g_winClipboardOldIOErrorHandler;
82*4882a593Smuzhiyun static pthread_t g_winClipboardProcThread;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun int xfixes_event_base;
85*4882a593Smuzhiyun int xfixes_error_base;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun Bool g_fHasModernClipboardApi = FALSE;
88*4882a593Smuzhiyun ADDCLIPBOARDFORMATLISTENERPROC g_fpAddClipboardFormatListener;
89*4882a593Smuzhiyun REMOVECLIPBOARDFORMATLISTENERPROC g_fpRemoveClipboardFormatListener;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /*
92*4882a593Smuzhiyun * Local function prototypes
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun static HWND
96*4882a593Smuzhiyun winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun static int
99*4882a593Smuzhiyun winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun static int
102*4882a593Smuzhiyun winClipboardIOErrorHandler(Display * pDisplay);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun * Create X11 and Win32 messaging windows, and run message processing loop
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * returns TRUE if shutdown was signalled to loop, FALSE if some error occurred
108*4882a593Smuzhiyun */
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun Bool
winClipboardProc(Bool fUseUnicode,char * szDisplay)111*4882a593Smuzhiyun winClipboardProc(Bool fUseUnicode, char *szDisplay)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun ClipboardAtoms atoms;
114*4882a593Smuzhiyun int iReturn;
115*4882a593Smuzhiyun HWND hwnd = NULL;
116*4882a593Smuzhiyun int iConnectionNumber = 0;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
119*4882a593Smuzhiyun int fdMessageQueue = 0;
120*4882a593Smuzhiyun #else
121*4882a593Smuzhiyun struct timeval tvTimeout;
122*4882a593Smuzhiyun #endif
123*4882a593Smuzhiyun fd_set fdsRead;
124*4882a593Smuzhiyun int iMaxDescriptor;
125*4882a593Smuzhiyun Display *pDisplay = NULL;
126*4882a593Smuzhiyun Window iWindow = None;
127*4882a593Smuzhiyun int iSelectError;
128*4882a593Smuzhiyun Bool fShutdown = FALSE;
129*4882a593Smuzhiyun static Bool fErrorHandlerSet = FALSE;
130*4882a593Smuzhiyun ClipboardConversionData data;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun winDebug("winClipboardProc - Hello\n");
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Allow multiple threads to access Xlib */
135*4882a593Smuzhiyun if (XInitThreads() == 0) {
136*4882a593Smuzhiyun ErrorF("winClipboardProc - XInitThreads failed.\n");
137*4882a593Smuzhiyun goto winClipboardProc_Exit;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* See if X supports the current locale */
141*4882a593Smuzhiyun if (XSupportsLocale() == False) {
142*4882a593Smuzhiyun ErrorF("winClipboardProc - Warning: Locale not supported by X.\n");
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun g_fpAddClipboardFormatListener = (ADDCLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"AddClipboardFormatListener");
146*4882a593Smuzhiyun g_fpRemoveClipboardFormatListener = (REMOVECLIPBOARDFORMATLISTENERPROC)GetProcAddress(GetModuleHandle("user32"),"RemoveClipboardFormatListener");
147*4882a593Smuzhiyun g_fHasModernClipboardApi = g_fpAddClipboardFormatListener && g_fpRemoveClipboardFormatListener;
148*4882a593Smuzhiyun ErrorF("OS maintains clipboard viewer chain: %s\n", g_fHasModernClipboardApi ? "yes" : "no");
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun g_winClipboardProcThread = pthread_self();
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* Set error handler */
153*4882a593Smuzhiyun if (!fErrorHandlerSet) {
154*4882a593Smuzhiyun XSetErrorHandler(winClipboardErrorHandler);
155*4882a593Smuzhiyun g_winClipboardOldIOErrorHandler =
156*4882a593Smuzhiyun XSetIOErrorHandler(winClipboardIOErrorHandler);
157*4882a593Smuzhiyun fErrorHandlerSet = TRUE;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Set jump point for Error exits */
161*4882a593Smuzhiyun if (setjmp(g_jmpEntry)) {
162*4882a593Smuzhiyun ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n");
163*4882a593Smuzhiyun goto winClipboardProc_Done;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* Make sure that the display opened */
167*4882a593Smuzhiyun pDisplay = XOpenDisplay(szDisplay);
168*4882a593Smuzhiyun if (pDisplay == NULL) {
169*4882a593Smuzhiyun ErrorF("winClipboardProc - Failed opening the display, giving up\n");
170*4882a593Smuzhiyun goto winClipboardProc_Done;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun ErrorF("winClipboardProc - XOpenDisplay () returned and "
174*4882a593Smuzhiyun "successfully opened the display.\n");
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* Get our connection number */
177*4882a593Smuzhiyun iConnectionNumber = ConnectionNumber(pDisplay);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
180*4882a593Smuzhiyun /* Open a file descriptor for the windows message queue */
181*4882a593Smuzhiyun fdMessageQueue = open(WIN_MSG_QUEUE_FNAME, O_RDONLY);
182*4882a593Smuzhiyun if (fdMessageQueue == -1) {
183*4882a593Smuzhiyun ErrorF("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME);
184*4882a593Smuzhiyun goto winClipboardProc_Done;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* Find max of our file descriptors */
188*4882a593Smuzhiyun iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1;
189*4882a593Smuzhiyun #else
190*4882a593Smuzhiyun iMaxDescriptor = iConnectionNumber + 1;
191*4882a593Smuzhiyun #endif
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base))
194*4882a593Smuzhiyun ErrorF ("winClipboardProc - XFixes extension not present\n");
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* Create atoms */
197*4882a593Smuzhiyun atoms.atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False);
198*4882a593Smuzhiyun atoms.atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False);
199*4882a593Smuzhiyun atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False);
200*4882a593Smuzhiyun atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False);
201*4882a593Smuzhiyun atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* Create a messaging window */
204*4882a593Smuzhiyun iWindow = XCreateSimpleWindow(pDisplay,
205*4882a593Smuzhiyun DefaultRootWindow(pDisplay),
206*4882a593Smuzhiyun 1, 1,
207*4882a593Smuzhiyun 500, 500,
208*4882a593Smuzhiyun 0,
209*4882a593Smuzhiyun BlackPixel(pDisplay, 0),
210*4882a593Smuzhiyun BlackPixel(pDisplay, 0));
211*4882a593Smuzhiyun if (iWindow == 0) {
212*4882a593Smuzhiyun ErrorF("winClipboardProc - Could not create an X window.\n");
213*4882a593Smuzhiyun goto winClipboardProc_Done;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun XStoreName(pDisplay, iWindow, "xwinclip");
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* Select event types to watch */
219*4882a593Smuzhiyun if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow)
220*4882a593Smuzhiyun ErrorF("winClipboardProc - XSelectInput generated BadWindow "
221*4882a593Smuzhiyun "on messaging window\n");
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun XFixesSelectSelectionInput (pDisplay,
224*4882a593Smuzhiyun iWindow,
225*4882a593Smuzhiyun XA_PRIMARY,
226*4882a593Smuzhiyun XFixesSetSelectionOwnerNotifyMask |
227*4882a593Smuzhiyun XFixesSelectionWindowDestroyNotifyMask |
228*4882a593Smuzhiyun XFixesSelectionClientCloseNotifyMask);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun XFixesSelectSelectionInput (pDisplay,
231*4882a593Smuzhiyun iWindow,
232*4882a593Smuzhiyun atoms.atomClipboard,
233*4882a593Smuzhiyun XFixesSetSelectionOwnerNotifyMask |
234*4882a593Smuzhiyun XFixesSelectionWindowDestroyNotifyMask |
235*4882a593Smuzhiyun XFixesSelectionClientCloseNotifyMask);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /* Initialize monitored selection state */
239*4882a593Smuzhiyun winClipboardInitMonitoredSelections();
240*4882a593Smuzhiyun /* Create Windows messaging window */
241*4882a593Smuzhiyun hwnd = winClipboardCreateMessagingWindow(pDisplay, iWindow, &atoms);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* Save copy of HWND */
244*4882a593Smuzhiyun g_hwndClipboard = hwnd;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* Assert ownership of selections if Win32 clipboard is owned */
247*4882a593Smuzhiyun if (NULL != GetClipboardOwner()) {
248*4882a593Smuzhiyun /* PRIMARY */
249*4882a593Smuzhiyun iReturn = XSetSelectionOwner(pDisplay, XA_PRIMARY,
250*4882a593Smuzhiyun iWindow, CurrentTime);
251*4882a593Smuzhiyun if (iReturn == BadAtom || iReturn == BadWindow ||
252*4882a593Smuzhiyun XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
253*4882a593Smuzhiyun ErrorF("winClipboardProc - Could not set PRIMARY owner\n");
254*4882a593Smuzhiyun goto winClipboardProc_Done;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* CLIPBOARD */
258*4882a593Smuzhiyun iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard,
259*4882a593Smuzhiyun iWindow, CurrentTime);
260*4882a593Smuzhiyun if (iReturn == BadAtom || iReturn == BadWindow ||
261*4882a593Smuzhiyun XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) {
262*4882a593Smuzhiyun ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
263*4882a593Smuzhiyun goto winClipboardProc_Done;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun data.fUseUnicode = fUseUnicode;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Loop for events */
270*4882a593Smuzhiyun while (1) {
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* Process X events */
273*4882a593Smuzhiyun winClipboardFlushXEvents(hwnd,
274*4882a593Smuzhiyun iWindow, pDisplay, &data, &atoms);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Process Windows messages */
277*4882a593Smuzhiyun if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
278*4882a593Smuzhiyun ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue trapped "
279*4882a593Smuzhiyun "WM_QUIT message, exiting main loop.\n");
280*4882a593Smuzhiyun break;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* We need to ensure that all pending requests are sent */
284*4882a593Smuzhiyun XFlush(pDisplay);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Setup the file descriptor set */
287*4882a593Smuzhiyun /*
288*4882a593Smuzhiyun * NOTE: You have to do this before every call to select
289*4882a593Smuzhiyun * because select modifies the mask to indicate
290*4882a593Smuzhiyun * which descriptors are ready.
291*4882a593Smuzhiyun */
292*4882a593Smuzhiyun FD_ZERO(&fdsRead);
293*4882a593Smuzhiyun FD_SET(iConnectionNumber, &fdsRead);
294*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
295*4882a593Smuzhiyun FD_SET(fdMessageQueue, &fdsRead);
296*4882a593Smuzhiyun #else
297*4882a593Smuzhiyun tvTimeout.tv_sec = 0;
298*4882a593Smuzhiyun tvTimeout.tv_usec = 100;
299*4882a593Smuzhiyun #endif
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* Wait for a Windows event or an X event */
302*4882a593Smuzhiyun iReturn = select(iMaxDescriptor, /* Highest fds number */
303*4882a593Smuzhiyun &fdsRead, /* Read mask */
304*4882a593Smuzhiyun NULL, /* No write mask */
305*4882a593Smuzhiyun NULL, /* No exception mask */
306*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
307*4882a593Smuzhiyun NULL /* No timeout */
308*4882a593Smuzhiyun #else
309*4882a593Smuzhiyun &tvTimeout /* Set timeout */
310*4882a593Smuzhiyun #endif
311*4882a593Smuzhiyun );
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun #ifndef HAS_WINSOCK
314*4882a593Smuzhiyun iSelectError = errno;
315*4882a593Smuzhiyun #else
316*4882a593Smuzhiyun iSelectError = WSAGetLastError();
317*4882a593Smuzhiyun #endif
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (iReturn < 0) {
320*4882a593Smuzhiyun #ifndef HAS_WINSOCK
321*4882a593Smuzhiyun if (iSelectError == EINTR)
322*4882a593Smuzhiyun #else
323*4882a593Smuzhiyun if (iSelectError == WSAEINTR)
324*4882a593Smuzhiyun #endif
325*4882a593Smuzhiyun continue;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun ErrorF("winClipboardProc - Call to select () failed: %d. "
328*4882a593Smuzhiyun "Bailing.\n", iReturn);
329*4882a593Smuzhiyun break;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (FD_ISSET(iConnectionNumber, &fdsRead)) {
333*4882a593Smuzhiyun winDebug
334*4882a593Smuzhiyun ("winClipboardProc - X connection ready, pumping X event queue\n");
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
338*4882a593Smuzhiyun /* Check for Windows event ready */
339*4882a593Smuzhiyun if (FD_ISSET(fdMessageQueue, &fdsRead))
340*4882a593Smuzhiyun #else
341*4882a593Smuzhiyun if (1)
342*4882a593Smuzhiyun #endif
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun winDebug
345*4882a593Smuzhiyun ("winClipboardProc - /dev/windows ready, pumping Windows message queue\n");
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
349*4882a593Smuzhiyun if (!(FD_ISSET(iConnectionNumber, &fdsRead)) &&
350*4882a593Smuzhiyun !(FD_ISSET(fdMessageQueue, &fdsRead))) {
351*4882a593Smuzhiyun winDebug("winClipboardProc - Spurious wake, select() returned %d\n", iReturn);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun winClipboardProc_Exit:
357*4882a593Smuzhiyun /* broke out of while loop on a shutdown message */
358*4882a593Smuzhiyun fShutdown = TRUE;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun winClipboardProc_Done:
361*4882a593Smuzhiyun /* Close our Windows window */
362*4882a593Smuzhiyun if (g_hwndClipboard) {
363*4882a593Smuzhiyun DestroyWindow(g_hwndClipboard);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* Close our X window */
367*4882a593Smuzhiyun if (pDisplay && iWindow) {
368*4882a593Smuzhiyun iReturn = XDestroyWindow(pDisplay, iWindow);
369*4882a593Smuzhiyun if (iReturn == BadWindow)
370*4882a593Smuzhiyun ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n");
371*4882a593Smuzhiyun else
372*4882a593Smuzhiyun ErrorF("winClipboardProc - XDestroyWindow succeeded.\n");
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
376*4882a593Smuzhiyun /* Close our Win32 message handle */
377*4882a593Smuzhiyun if (fdMessageQueue)
378*4882a593Smuzhiyun close(fdMessageQueue);
379*4882a593Smuzhiyun #endif
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun #if 0
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun * FIXME: XCloseDisplay hangs if we call it
384*4882a593Smuzhiyun *
385*4882a593Smuzhiyun * XCloseDisplay() calls XSync(), so any outstanding errors are reported.
386*4882a593Smuzhiyun * If we are built into the server, this can deadlock if the server is
387*4882a593Smuzhiyun * in the process of exiting and waiting for this thread to exit.
388*4882a593Smuzhiyun */
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* Discard any remaining events */
391*4882a593Smuzhiyun XSync(pDisplay, TRUE);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /* Select event types to watch */
394*4882a593Smuzhiyun XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /* Close our X display */
397*4882a593Smuzhiyun if (pDisplay) {
398*4882a593Smuzhiyun XCloseDisplay(pDisplay);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun #endif
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun /* global clipboard variable reset */
403*4882a593Smuzhiyun g_hwndClipboard = NULL;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun return fShutdown;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /*
409*4882a593Smuzhiyun * Create the Windows window that we use to receive Windows messages
410*4882a593Smuzhiyun */
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun static HWND
winClipboardCreateMessagingWindow(Display * pDisplay,Window iWindow,ClipboardAtoms * atoms)413*4882a593Smuzhiyun winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun WNDCLASSEX wc;
416*4882a593Smuzhiyun ClipboardWindowCreationParams cwcp;
417*4882a593Smuzhiyun HWND hwnd;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /* Setup our window class */
420*4882a593Smuzhiyun wc.cbSize = sizeof(WNDCLASSEX);
421*4882a593Smuzhiyun wc.style = CS_HREDRAW | CS_VREDRAW;
422*4882a593Smuzhiyun wc.lpfnWndProc = winClipboardWindowProc;
423*4882a593Smuzhiyun wc.cbClsExtra = 0;
424*4882a593Smuzhiyun wc.cbWndExtra = 0;
425*4882a593Smuzhiyun wc.hInstance = GetModuleHandle(NULL);
426*4882a593Smuzhiyun wc.hIcon = 0;
427*4882a593Smuzhiyun wc.hCursor = 0;
428*4882a593Smuzhiyun wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
429*4882a593Smuzhiyun wc.lpszMenuName = NULL;
430*4882a593Smuzhiyun wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS;
431*4882a593Smuzhiyun wc.hIconSm = 0;
432*4882a593Smuzhiyun RegisterClassEx(&wc);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Information to be passed to WM_CREATE */
435*4882a593Smuzhiyun cwcp.pClipboardDisplay = pDisplay;
436*4882a593Smuzhiyun cwcp.iClipboardWindow = iWindow;
437*4882a593Smuzhiyun cwcp.atoms = atoms;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /* Create the window */
440*4882a593Smuzhiyun hwnd = CreateWindowExA(0, /* Extended styles */
441*4882a593Smuzhiyun WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */
442*4882a593Smuzhiyun WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */
443*4882a593Smuzhiyun WS_OVERLAPPED, /* Not visible anyway */
444*4882a593Smuzhiyun CW_USEDEFAULT, /* Horizontal position */
445*4882a593Smuzhiyun CW_USEDEFAULT, /* Vertical position */
446*4882a593Smuzhiyun CW_USEDEFAULT, /* Right edge */
447*4882a593Smuzhiyun CW_USEDEFAULT, /* Bottom edge */
448*4882a593Smuzhiyun (HWND) NULL, /* No parent or owner window */
449*4882a593Smuzhiyun (HMENU) NULL, /* No menu */
450*4882a593Smuzhiyun GetModuleHandle(NULL), /* Instance handle */
451*4882a593Smuzhiyun &cwcp); /* Creation data */
452*4882a593Smuzhiyun assert(hwnd != NULL);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* I'm not sure, but we may need to call this to start message processing */
455*4882a593Smuzhiyun ShowWindow(hwnd, SW_HIDE);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* Similarly, we may need a call to this even though we don't paint */
458*4882a593Smuzhiyun UpdateWindow(hwnd);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return hwnd;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /*
464*4882a593Smuzhiyun * winClipboardErrorHandler - Our application specific error handler
465*4882a593Smuzhiyun */
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun static int
winClipboardErrorHandler(Display * pDisplay,XErrorEvent * pErr)468*4882a593Smuzhiyun winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun char pszErrorMsg[100];
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
473*4882a593Smuzhiyun ErrorF("winClipboardErrorHandler - ERROR: \n\t%s\n"
474*4882a593Smuzhiyun "\tSerial: %lu, Request Code: %d, Minor Code: %d\n",
475*4882a593Smuzhiyun pszErrorMsg, pErr->serial, pErr->request_code, pErr->minor_code);
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /*
480*4882a593Smuzhiyun * winClipboardIOErrorHandler - Our application specific IO error handler
481*4882a593Smuzhiyun */
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun static int
winClipboardIOErrorHandler(Display * pDisplay)484*4882a593Smuzhiyun winClipboardIOErrorHandler(Display * pDisplay)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun ErrorF("winClipboardIOErrorHandler!\n");
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun if (pthread_equal(pthread_self(), g_winClipboardProcThread)) {
489*4882a593Smuzhiyun /* Restart at the main entry point */
490*4882a593Smuzhiyun longjmp(g_jmpEntry, 2);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (g_winClipboardOldIOErrorHandler)
494*4882a593Smuzhiyun g_winClipboardOldIOErrorHandler(pDisplay);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun return 0;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun void
winClipboardWindowDestroy(void)500*4882a593Smuzhiyun winClipboardWindowDestroy(void)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun if (g_hwndClipboard) {
503*4882a593Smuzhiyun SendMessage(g_hwndClipboard, WM_WM_QUIT, 0, 0);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun void
winFixClipboardChain(void)508*4882a593Smuzhiyun winFixClipboardChain(void)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun if (g_hwndClipboard) {
511*4882a593Smuzhiyun PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun }
514