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