2 * X11 clipboard windows driver
4 * Copyright 1994 Martin Ayotte
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * This file contains the X specific implementation for the windows
26 * Wine's internal clipboard is exposed to external apps via the X
27 * selection mechanism.
28 * Currently the driver asserts ownership via two selection atoms:
29 * 1. PRIMARY(XA_PRIMARY)
32 * In our implementation, the CLIPBOARD selection takes precedence over PRIMARY,
33 * i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
34 * When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
35 * While giving up selection ownership, if the CLIPBOARD selection is lost,
36 * it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
37 * However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
38 * (leaving the clipboard cache content unaffected).
40 * Every format exposed via a windows clipboard format is also exposed through
41 * a corresponding X selection target. A selection target atom is synthesized
42 * whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
43 * or when a built-in format is used for the first time.
44 * Windows native format are exposed by prefixing the format name with "<WCF>"
45 * This allows us to uniquely identify windows native formats exposed by other
48 * In order to allow external applications to query WINE for supported formats,
49 * we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
50 * for implementation) We use the same mechanism to query external clients for
51 * availability of a particular format, by caching the list of available targets
52 * by using the clipboard cache's "delayed render" mechanism. If a selection client
53 * does not support the "TARGETS" selection target, we actually attempt to retrieve
54 * the format requested as a fallback mechanism.
56 * Certain Windows native formats are automatically converted to X native formats
57 * and vice versa. If a native format is available in the selection, it takes
58 * precedence, in order to avoid unnecessary conversions.
72 #include "clipboard.h"
75 #include "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
81 #define S_NOSELECTION 0
85 /* X selection context info */
87 static char _CLIPBOARD[] = "CLIPBOARD"; /* CLIPBOARD atom name */
88 static char FMT_PREFIX[] = "<WCF>"; /* Prefix for windows specific formats */
89 static int selectionAcquired = 0; /* Contains the current selection masks */
90 static Window selectionWindow = None; /* The top level X window which owns the selection */
91 static Window selectionPrevWindow = None; /* The last X window that owned the selection */
92 static Window PrimarySelectionOwner = None; /* The window which owns the primary selection */
93 static Window ClipboardSelectionOwner = None; /* The window which owns the clipboard selection */
94 static unsigned long cSelectionTargets = 0; /* Number of target formats reported by TARGETS selection */
95 static Atom selectionCacheSrc = XA_PRIMARY; /* The selection source from which the clipboard cache was filled */
96 static HANDLE selectionClearEvent = 0;/* Synchronization object used to block until server is started */
98 typedef struct tagPROPERTY
100 struct tagPROPERTY *next;
105 static PROPERTY *prop_head;
108 /**************************************************************************
109 * X11DRV_CLIPBOARD_MapPropertyToFormat
111 * Map an X selection property type atom name to a windows clipboard format ID
113 UINT X11DRV_CLIPBOARD_MapPropertyToFormat(char *itemFmtName)
116 * If the property name starts with FMT_PREFIX strip this off and
117 * get the ID for a custom Windows registered format with this name.
118 * We can also understand STRING, PIXMAP and BITMAP.
120 if ( NULL == itemFmtName )
122 else if ( 0 == strncmp(itemFmtName, FMT_PREFIX, strlen(FMT_PREFIX)) )
123 return RegisterClipboardFormatA(itemFmtName + strlen(FMT_PREFIX));
124 else if ( 0 == strcmp(itemFmtName, "STRING") )
125 return CF_UNICODETEXT;
126 else if ( 0 == strcmp(itemFmtName, "PIXMAP")
127 || 0 == strcmp(itemFmtName, "BITMAP") )
130 * Return CF_DIB as first preference, if WINE is the selection owner
131 * and if CF_DIB exists in the cache.
132 * If wine dowsn't own the selection we always return CF_DIB
134 if ( !X11DRV_IsSelectionOwner() )
136 else if ( CLIPBOARD_IsPresent(CF_DIB) )
142 WARN("\tNo mapping to Windows clipboard format for property %s\n", itemFmtName);
146 /**************************************************************************
147 * X11DRV_CLIPBOARD_MapFormatToProperty
149 * Map a windows clipboard format ID to an X selection property atom
151 Atom X11DRV_CLIPBOARD_MapFormatToProperty(UINT wFormat)
157 /* We support only CF_UNICODETEXT, other formats are synthesized */
170 * Request a PIXMAP, only if WINE is NOT the selection owner,
171 * AND the requested format is not in the cache.
173 if ( !X11DRV_IsSelectionOwner() && !CLIPBOARD_IsPresent(wFormat) )
178 /* Fall through to the default case in order to use the native format */
184 * If an X atom is registered for this format, return that
185 * Otherwise register a new atom.
188 char *fmtName = CLIPBOARD_GetFormatName(wFormat);
189 strcpy(str, FMT_PREFIX);
193 strncat(str, fmtName, sizeof(str) - strlen(FMT_PREFIX));
194 prop = TSXInternAtom(thread_display(), str, False);
201 TRACE("\tNo mapping to X property for Windows clipboard format %d(%s)\n",
202 wFormat, CLIPBOARD_GetFormatName(wFormat));
207 /**************************************************************************
208 * X11DRV_CLIPBOARD_IsNativeProperty
210 * Checks if a property is a native Wine property type
212 BOOL X11DRV_CLIPBOARD_IsNativeProperty(Atom prop)
214 char *itemFmtName = TSXGetAtomName(thread_display(), prop);
217 if ( 0 == strncmp(itemFmtName, FMT_PREFIX, strlen(FMT_PREFIX)) )
220 TSXFree(itemFmtName);
225 /**************************************************************************
226 * X11DRV_CLIPBOARD_LaunchServer
227 * Launches the clipboard server. This is called from X11DRV_CLIPBOARD_ResetOwner
228 * when the selection can no longer be recyled to another top level window.
229 * In order to make the selection persist after Wine shuts down a server
230 * process is launched which services subsequent selection requests.
232 BOOL X11DRV_CLIPBOARD_LaunchServer()
235 char clearSelection[8] = "0";
236 int persistent_selection = 1;
240 /* If persistant selection has been disabled in the .winerc Clipboard section,
241 * don't launch the server
243 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Clipboard", &hkey))
246 DWORD type, count = sizeof(buffer);
247 if(!RegQueryValueExA(hkey, "PersistentSelection", 0, &type, buffer, &count))
248 persistent_selection = atoi(buffer);
250 /* Get the clear selection preference */
251 count = sizeof(clearSelection);
252 RegQueryValueExA(hkey, "ClearAllSelections", 0, &type, clearSelection, &count);
255 if ( !persistent_selection )
258 /* Start up persistant WINE X clipboard server process which will
259 * take ownership of the X selection and continue to service selection
260 * requests from other apps.
263 if(pipe(fd) == -1) return FALSE;
264 fcntl(fd[1], F_SETFD, 1); /* set close on exec */
266 selectionWindow = selectionPrevWindow;
269 /* NOTE: This code only executes in the context of the child process
270 * Do note make any Wine specific calls here.
273 char selMask[8], dbgClassMask[8];
276 sprintf(selMask, "%d", selectionAcquired);
278 /* Build the debug class mask to pass to the server, by inheriting
279 * the settings for the clipboard debug channel.
281 dbgClasses |= FIXME_ON(clipboard) ? 1 : 0;
282 dbgClasses |= ERR_ON(clipboard) ? 2 : 0;
283 dbgClasses |= WARN_ON(clipboard) ? 4 : 0;
284 dbgClasses |= TRACE_ON(clipboard) ? 8 : 0;
285 sprintf(dbgClassMask, "%d", dbgClasses);
287 /* Exec the clipboard server passing it the selection and debug class masks */
288 execl( BINDIR "/wineclipsrv", "wineclipsrv",
289 selMask, dbgClassMask, clearSelection, NULL );
290 execlp( "wineclipsrv", "wineclipsrv", selMask, dbgClassMask, clearSelection, NULL );
291 execl( "./windows/x11drv/wineclipsrv", "wineclipsrv",
292 selMask, dbgClassMask, clearSelection, NULL );
295 perror("Could not start Wine clipboard server");
296 write(fd[1], &err, sizeof(err));
297 _exit( 1 ); /* Exit the child process */
301 if(read(fd[0], &err, sizeof(err)) > 0) { /* exec failed */
307 /* Wait until the clipboard server acquires the selection.
308 * We must release the windows lock to enable Wine to process
309 * selection messages in response to the servers requests.
312 iWndsLocks = WIN_SuspendWndsLock();
314 /* We must wait until the server finishes acquiring the selection,
315 * before proceeding, otherwise the window which owns the selection
316 * will be destroyed prematurely!
317 * Create a non-signalled, auto-reset event which will be set by
318 * X11DRV_CLIPBOARD_ReleaseSelection, and wait until this gets
319 * signalled before proceeding.
322 if ( !(selectionClearEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) )
323 ERR("Could not create wait object. Clipboard server won't start!\n");
326 /* Wait until we lose the selection, timing out after a minute */
327 DWORD start_time, timeout, elapsed, ret;
329 TRACE("Waiting for clipboard server to acquire selection\n");
332 start_time = GetTickCount();
336 ret = MsgWaitForMultipleObjects( 1, &selectionClearEvent, FALSE, timeout - elapsed, QS_ALLINPUT );
337 if (ret != WAIT_OBJECT_0+1)
339 elapsed = GetTickCount() - start_time;
340 if (elapsed > timeout)
344 if ( ret != WAIT_OBJECT_0 )
345 TRACE("Server could not acquire selection, or a timeout occurred!\n");
347 TRACE("Server successfully acquired selection\n");
349 /* Release the event */
350 CloseHandle(selectionClearEvent);
351 selectionClearEvent = 0;
354 WIN_RestoreWndsLock(iWndsLocks);
360 /**************************************************************************
361 * X11DRV_CLIPBOARD_CacheDataFormats
363 * Caches the list of data formats available from the current selection.
364 * This queries the selection owner for the TARGETS property and saves all
365 * reported property types.
367 int X11DRV_CLIPBOARD_CacheDataFormats( Atom SelectionName )
369 Display *display = thread_display();
371 HWND hWndClipWindow = GetOpenClipboardWindow();
374 Atom atype=AnyPropertyType;
376 unsigned long remain;
377 Atom* targetList=NULL;
379 Window ownerSelection = 0;
383 * Empty the clipboard cache
385 CLIPBOARD_EmptyCache(TRUE);
387 cSelectionTargets = 0;
388 selectionCacheSrc = SelectionName;
390 hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
392 ownerSelection = TSXGetSelectionOwner(display, SelectionName);
393 if ( !hWnd || (ownerSelection == None) )
394 return cSelectionTargets;
397 * Query the selection owner for the TARGETS property
399 w = X11DRV_get_whole_window( GetAncestor(hWnd,GA_ROOT) );
401 aTargets = TSXInternAtom(display, "TARGETS", False);
403 TRACE("Requesting TARGETS selection for '%s' (owner=%08x)...\n",
404 TSXGetAtomName(display, selectionCacheSrc), (unsigned)ownerSelection );
406 XConvertSelection(display, selectionCacheSrc, aTargets,
407 TSXInternAtom(display, "SELECTION_DATA", False),
411 * Wait until SelectionNotify is received
415 if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
416 if( xe.xselection.selection == selectionCacheSrc )
421 /* Verify that the selection returned a valid TARGETS property */
422 if ( (xe.xselection.target != aTargets)
423 || (xe.xselection.property == None) )
425 TRACE("\tExit, could not retrieve TARGETS\n");
426 return cSelectionTargets;
429 /* Read the TARGETS property contents */
430 if(TSXGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
431 0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat,
432 &cSelectionTargets, &remain, (unsigned char**)&targetList) != Success)
433 TRACE("\tCouldn't read TARGETS property\n");
436 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
437 TSXGetAtomName(display,atype),aformat,cSelectionTargets, remain);
439 * The TARGETS property should have returned us a list of atoms
440 * corresponding to each selection target format supported.
442 if( (atype == XA_ATOM || atype == aTargets) && aformat == 32 )
445 LPWINE_CLIPFORMAT lpFormat;
447 /* Cache these formats in the clipboard cache */
449 for (i = 0; i < cSelectionTargets; i++)
451 char *itemFmtName = TSXGetAtomName(display, targetList[i]);
452 UINT wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
455 * If the clipboard format maps to a Windows format, simply store
456 * the atom identifier and record its availablity status
457 * in the clipboard cache.
461 lpFormat = CLIPBOARD_LookupFormat( wFormat );
463 /* Don't replace if the property already cached is a native format,
464 * or if a PIXMAP is being replaced by a BITMAP.
466 if (lpFormat->wDataPresent &&
467 ( X11DRV_CLIPBOARD_IsNativeProperty(lpFormat->drvData)
468 || (lpFormat->drvData == XA_PIXMAP && targetList[i] == XA_BITMAP) )
471 TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s (Skipped)\n",
472 i, itemFmtName, wFormat, lpFormat->Name);
476 lpFormat->wDataPresent = 1;
477 lpFormat->drvData = targetList[i];
478 TRACE("\tAtom# %d: '%s' --> FormatID(%d) %s\n",
479 i, itemFmtName, wFormat, lpFormat->Name);
483 TSXFree(itemFmtName);
487 /* Free the list of targets */
491 return cSelectionTargets;
494 /**************************************************************************
495 * X11DRV_CLIPBOARD_ReadSelection
496 * Reads the contents of the X selection property into the WINE clipboard cache
497 * converting the selection into a format compatible with the windows clipboard
499 * This method is invoked only to read the contents of a the selection owned
500 * by an external application. i.e. when we do not own the X selection.
502 static BOOL X11DRV_CLIPBOARD_ReadSelection(UINT wFormat, Window w, Atom prop, Atom reqType)
504 Display *display = thread_display();
505 Atom atype=AnyPropertyType;
507 unsigned long total,nitems,remain,itemSize,val_cnt;
508 long lRequestLength,bwc;
510 unsigned char* buffer;
511 LPWINE_CLIPFORMAT lpFormat;
513 HWND hWndClipWindow = GetOpenClipboardWindow();
519 TRACE("Reading X selection...\n");
521 TRACE("\tretrieving property %s from window %ld into %s\n",
522 TSXGetAtomName(display,reqType), (long)w, TSXGetAtomName(display,prop) );
525 * First request a zero length in order to figure out the request size.
527 if(TSXGetWindowProperty(display,w,prop,0,0,False, AnyPropertyType/*reqType*/,
528 &atype, &aformat, &nitems, &itemSize, &val) != Success)
530 WARN("\tcouldn't get property size\n");
534 /* Free zero length return data if any */
541 TRACE("\tretrieving %ld bytes...\n", itemSize * aformat/8);
542 lRequestLength = (itemSize * aformat/8)/4 + 1;
545 /* we want to read the property, but not it too large of chunks or
546 we could hang the cause problems. Lets go for 4k blocks */
548 if(TSXGetWindowProperty(display,w,prop,0,4096,False,
549 AnyPropertyType/*reqType*/,
550 &atype, &aformat, &nitems, &remain, &buffer)
553 WARN("\tcouldn't read property\n");
556 val = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
558 memcpy(val,buffer,nitems*bwc);
561 for (total = nitems*bwc,val_cnt=0; remain;)
563 val_cnt +=nitems*bwc;
564 TSXGetWindowProperty(display, w, prop,
565 (total / 4), 4096, False,
566 AnyPropertyType, &atype,
567 &aformat, &nitems, &remain,
571 HeapReAlloc(GetProcessHeap(),0,val, total);
572 memcpy(&val[val_cnt], buffer, nitems*(aformat/8));
578 * Translate the X property into the appropriate Windows clipboard
579 * format, if possible.
581 if ( (reqType == XA_STRING)
582 && (atype == XA_STRING) && (aformat == 8) )
583 /* convert Unix text to CF_UNICODETEXT */
588 for(i=0; i <= nitems; i++)
589 if( val[i] == '\n' ) inlcount++;
591 if( (lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nitems + inlcount + 1)) )
593 static UINT text_cp = (UINT)-1;
597 for(i=0,inlcount=0; i <= nitems; i++)
599 if( val[i] == '\n' ) lpstr[inlcount++]='\r';
600 lpstr[inlcount++]=val[i];
603 if(text_cp == (UINT)-1)
608 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
611 DWORD type, count = sizeof(buf);
612 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
618 count = MultiByteToWideChar(text_cp, 0, lpstr, -1, NULL, 0);
619 hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
622 WCHAR *textW = GlobalLock(hUnicodeText);
623 MultiByteToWideChar(text_cp, 0, lpstr, -1, textW, count);
624 GlobalUnlock(hUnicodeText);
625 if (!SetClipboardData(CF_UNICODETEXT, hUnicodeText))
627 ERR("Not SET! Need to free our own block\n");
628 GlobalFree(hUnicodeText);
632 HeapFree(GetProcessHeap(), 0, lpstr);
635 else if ( reqType == XA_PIXMAP || reqType == XA_BITMAP ) /* treat PIXMAP as CF_DIB or CF_BITMAP */
637 /* Get the first pixmap handle passed to us */
638 Pixmap *pPixmap = (Pixmap *)val;
639 HANDLE hTargetImage = 0; /* Handle to store the converted bitmap or DIB */
641 if (aformat != 32 || nitems < 1 || atype != XA_PIXMAP
642 || (wFormat != CF_BITMAP && wFormat != CF_DIB))
644 WARN("\tUnimplemented format conversion request\n");
648 if ( wFormat == CF_BITMAP )
650 /* For CF_BITMAP requests we must return an HBITMAP */
651 hTargetImage = X11DRV_BITMAP_CreateBitmapFromPixmap(*pPixmap, TRUE);
653 else if (wFormat == CF_DIB)
655 HWND hwnd = GetOpenClipboardWindow();
656 HDC hdc = GetDC(hwnd);
658 /* For CF_DIB requests we must return an HGLOBAL storing a packed DIB */
659 hTargetImage = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc, TRUE);
661 ReleaseDC(hwnd, hdc);
666 WARN("PIXMAP conversion failed!\n" );
670 /* Delete previous clipboard data */
671 lpFormat = CLIPBOARD_LookupFormat(wFormat);
672 if (lpFormat->wDataPresent && (lpFormat->hData16 || lpFormat->hData32))
673 CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
675 /* Update the clipboard record */
676 lpFormat->wDataPresent = 1;
677 lpFormat->hData32 = hTargetImage;
678 lpFormat->hData16 = 0;
683 /* For native properties simply copy the X data without conversion */
684 else if (X11DRV_CLIPBOARD_IsNativeProperty(reqType)) /* <WCF>* */
686 HANDLE hClipData = 0;
688 int cBytes = nitems * aformat/8;
692 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
693 hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cBytes );
694 if( (lpClipData = GlobalLock(hClipData)) )
696 memcpy(lpClipData, val, cBytes);
697 GlobalUnlock(hClipData);
705 /* delete previous clipboard record if any */
706 lpFormat = CLIPBOARD_LookupFormat(wFormat);
707 if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)
708 CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
710 /* Update the clipboard record */
711 lpFormat->wDataPresent = 1;
712 lpFormat->hData32 = hClipData;
713 lpFormat->hData16 = 0;
720 WARN("\tUnimplemented format conversion request\n");
725 /* Delete the property on the window now that we are done
726 * This will send a PropertyNotify event to the selection owner. */
727 TSXDeleteProperty(display,w,prop);
729 /* Free the retrieved property data */
730 HeapFree(GetProcessHeap(),0,val);
734 /**************************************************************************
735 * X11DRV_CLIPBOARD_ReleaseSelection
737 * Release an XA_PRIMARY or XA_CLIPBOARD selection that we own, in response
738 * to a SelectionClear event.
739 * This can occur in response to another client grabbing the X selection.
740 * If the XA_CLIPBOARD selection is lost, we relinquish XA_PRIMARY as well.
742 void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
744 Display *display = thread_display();
745 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
746 int clearAllSelections = 0;
749 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Clipboard", &hkey))
752 DWORD type, count = sizeof(buffer);
753 if(!RegQueryValueExA(hkey, "ClearAllSelections", 0, &type, buffer, &count))
754 clearAllSelections = atoi(buffer);
758 /* w is the window that lost the selection
759 * selectionPrevWindow is nonzero if CheckSelection() was called.
762 TRACE("\tevent->window = %08x (sw = %08x, spw=%08x)\n",
763 (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionPrevWindow );
765 if( selectionAcquired )
767 if( w == selectionWindow || selectionPrevWindow == None)
769 /* If we're losing the CLIPBOARD selection, or if the preferences in .winerc
770 * dictate that *all* selections should be cleared on loss of a selection,
771 * we must give up all the selections we own.
773 if ( clearAllSelections || (selType == xaClipboard) )
775 /* completely give up the selection */
776 TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
778 /* We are completely giving up the selection.
779 * Make sure we can open the windows clipboard first. */
781 if ( !OpenClipboard(hwnd) )
784 * We can't empty the clipboard if we cant open it so abandon.
785 * Wine will think that it still owns the selection but this is
786 * safer than losing the selection without properly emptying
787 * the clipboard. Perhaps we should forcibly re-assert ownership
788 * of the CLIPBOARD selection in this case...
790 ERR("\tClipboard is busy. Could not give up selection!\n");
794 /* We really lost CLIPBOARD but want to voluntarily lose PRIMARY */
795 if ( (selType == xaClipboard)
796 && (selectionAcquired & S_PRIMARY) )
798 XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
801 /* We really lost PRIMARY but want to voluntarily lose CLIPBOARD */
802 if ( (selType == XA_PRIMARY)
803 && (selectionAcquired & S_CLIPBOARD) )
805 XSetSelectionOwner(display, xaClipboard, None, CurrentTime);
808 selectionWindow = None;
809 PrimarySelectionOwner = ClipboardSelectionOwner = 0;
811 /* Empty the windows clipboard.
812 * We should pretend that we still own the selection BEFORE calling
813 * EmptyClipboard() since otherwise this has the side effect of
814 * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
815 * to be re-acquired by us!
817 selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
821 /* Give up ownership of the windows clipboard */
822 CLIPBOARD_ReleaseOwner();
824 /* Reset the selection flags now that we are done */
825 selectionAcquired = S_NOSELECTION;
827 else if ( selType == XA_PRIMARY ) /* Give up only PRIMARY selection */
829 TRACE("Lost PRIMARY selection\n");
830 PrimarySelectionOwner = 0;
831 selectionAcquired &= ~S_PRIMARY; /* clear S_PRIMARY mask */
834 cSelectionTargets = 0;
836 /* but we'll keep existing data for internal use */
837 else if( w == selectionPrevWindow )
839 Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
841 w = TSXGetSelectionOwner(display, XA_PRIMARY);
843 TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
845 w = TSXGetSelectionOwner(display, xaClipboard);
847 TSXSetSelectionOwner(display, xaClipboard, selectionWindow, CurrentTime);
851 /* Signal to a selectionClearEvent listener if the selection is completely lost */
852 if (selectionClearEvent && !selectionAcquired)
854 TRACE("Lost all selections, signalling to selectionClearEvent listener\n");
855 SetEvent(selectionClearEvent);
858 selectionPrevWindow = None;
861 /**************************************************************************
862 * ReleaseClipboard (X11DRV.@)
863 * Voluntarily release all currently owned X selections
865 void X11DRV_ReleaseClipboard(void)
867 Display *display = thread_display();
868 if( selectionAcquired )
871 Window savePrevWindow = selectionWindow;
872 Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
873 BOOL bHasPrimarySelection = selectionAcquired & S_PRIMARY;
875 selectionAcquired = S_NOSELECTION;
876 selectionPrevWindow = selectionWindow;
877 selectionWindow = None;
879 TRACE("\tgiving up selection (spw = %08x)\n",
880 (unsigned)selectionPrevWindow);
884 TRACE("Releasing CLIPBOARD selection\n");
885 XSetSelectionOwner(display, xaClipboard, None, CurrentTime);
886 if( selectionPrevWindow )
887 while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
888 SelectionClear, &xe ) );
890 if ( bHasPrimarySelection )
892 TRACE("Releasing XA_PRIMARY selection\n");
893 selectionPrevWindow = savePrevWindow; /* May be cleared in X11DRV_CLIPBOARD_ReleaseSelection */
894 XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
896 if( selectionPrevWindow )
897 while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
898 SelectionClear, &xe ) );
903 /* Get rid of any Pixmap resources we may still have */
906 PROPERTY *prop = prop_head;
907 prop_head = prop->next;
908 XFreePixmap( gdi_display, prop->pixmap );
909 HeapFree( GetProcessHeap(), 0, prop );
913 /**************************************************************************
914 * AcquireClipboard (X11DRV.@)
916 void X11DRV_AcquireClipboard(void)
918 Display *display = thread_display();
920 HWND hWndClipWindow = GetOpenClipboardWindow();
923 * Acquire X selection if we don't already own it.
924 * Note that we only acquire the selection if it hasn't been already
925 * acquired by us, and ignore the fact that another X window may be
926 * asserting ownership. The reason for this is we need *any* top level
927 * X window to hold selection ownership. The actual clipboard data requests
928 * are made via GetClipboardData from EVENT_SelectionRequest and this
929 * ensures that the real HWND owner services the request.
930 * If the owning X window gets destroyed the selection ownership is
931 * re-cycled to another top level X window in X11DRV_CLIPBOARD_ResetOwner.
935 if ( !(selectionAcquired == (S_PRIMARY | S_CLIPBOARD)) )
937 Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
938 owner = X11DRV_get_whole_window( GetAncestor( hWndClipWindow ? hWndClipWindow : AnyPopup(),
941 /* Grab PRIMARY selection if not owned */
942 if ( !(selectionAcquired & S_PRIMARY) )
943 TSXSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
945 /* Grab CLIPBOARD selection if not owned */
946 if ( !(selectionAcquired & S_CLIPBOARD) )
947 TSXSetSelectionOwner(display, xaClipboard, owner, CurrentTime);
949 if( TSXGetSelectionOwner(display,XA_PRIMARY) == owner )
950 selectionAcquired |= S_PRIMARY;
952 if( TSXGetSelectionOwner(display,xaClipboard) == owner)
953 selectionAcquired |= S_CLIPBOARD;
955 if (selectionAcquired)
957 selectionWindow = owner;
958 TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
963 /**************************************************************************
964 * IsClipboardFormatAvailable (X11DRV.@)
966 * Checks if the specified format is available in the current selection
967 * Only invoked when WINE is not the selection owner
969 BOOL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
971 Display *display = thread_display();
972 Atom xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
973 Window ownerPrimary = TSXGetSelectionOwner(display,XA_PRIMARY);
974 Window ownerClipboard = TSXGetSelectionOwner(display,xaClipboard);
976 TRACE("enter for %d\n", wFormat);
979 * If the selection has not been previously cached, or the selection has changed,
980 * try and cache the list of available selection targets from the current selection.
982 if ( !cSelectionTargets || (PrimarySelectionOwner != ownerPrimary)
983 || (ClipboardSelectionOwner != ownerClipboard) )
986 * First try caching the CLIPBOARD selection.
987 * If unavailable try PRIMARY.
989 if ( X11DRV_CLIPBOARD_CacheDataFormats(xaClipboard) == 0 )
991 X11DRV_CLIPBOARD_CacheDataFormats(XA_PRIMARY);
994 ClipboardSelectionOwner = ownerClipboard;
995 PrimarySelectionOwner = ownerPrimary;
998 /* Exit if there is no selection */
999 if ( !ownerClipboard && !ownerPrimary )
1001 TRACE("There is no selection owner\n");
1005 /* Check if the format is available in the clipboard cache */
1006 if ( CLIPBOARD_IsPresent(wFormat) )
1010 * Many X client apps (such as XTerminal) don't support being queried
1011 * for the "TARGETS" target atom. To handle such clients we must actually
1012 * try to convert the selection to the requested type.
1014 if ( !cSelectionTargets )
1015 return X11DRV_GetClipboardData( wFormat );
1017 TRACE("There is no selection\n");
1021 /**************************************************************************
1022 * RegisterClipboardFormat (X11DRV.@)
1024 * Registers a custom X clipboard format
1025 * Returns: TRUE - success, FALSE - failure
1027 BOOL X11DRV_RegisterClipboardFormat( LPCSTR FormatName )
1029 Display *display = thread_display();
1034 * If an X atom is registered for this format, return that
1035 * Otherwise register a new atom.
1039 /* Add a WINE specific prefix to the format */
1040 strcpy(str, FMT_PREFIX);
1041 strncat(str, FormatName, sizeof(str) - strlen(FMT_PREFIX));
1042 prop = TSXInternAtom(display, str, False);
1045 return (prop) ? TRUE : FALSE;
1048 /**************************************************************************
1049 * IsSelectionOwner (X11DRV.@)
1051 * Returns: TRUE - We(WINE) own the selection, FALSE - Selection not owned by us
1053 BOOL X11DRV_IsSelectionOwner(void)
1055 return selectionAcquired;
1058 /**************************************************************************
1059 * SetClipboardData (X11DRV.@)
1061 * We don't need to do anything special here since the clipboard code
1062 * maintains the cache.
1065 void X11DRV_SetClipboardData(UINT wFormat)
1067 /* Make sure we have acquired the X selection */
1068 X11DRV_AcquireClipboard();
1071 /**************************************************************************
1072 * GetClipboardData (X11DRV.@)
1074 * This method is invoked only when we DO NOT own the X selection
1076 * NOTE: Clipboard driver get requests only for CF_UNICODETEXT data.
1077 * We always get the data from the selection client each time,
1078 * since we have no way of determining if the data in our cache is stale.
1080 BOOL X11DRV_GetClipboardData(UINT wFormat)
1082 Display *display = thread_display();
1083 BOOL bRet = selectionAcquired;
1084 HWND hWndClipWindow = GetOpenClipboardWindow();
1085 HWND hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
1086 LPWINE_CLIPFORMAT lpFormat;
1088 TRACE("%d\n", wFormat);
1090 if (!selectionAcquired)
1094 Window w = X11DRV_get_whole_window( GetAncestor( hWnd, GA_ROOT ));
1097 FIXME("No parent win found %x %x\n", hWnd, hWndClipWindow);
1101 /* Map the format ID requested to an X selection property.
1102 * If the format is in the cache, use the atom associated
1106 lpFormat = CLIPBOARD_LookupFormat( wFormat );
1107 if (lpFormat && lpFormat->wDataPresent && lpFormat->drvData)
1108 propRequest = (Atom)lpFormat->drvData;
1110 propRequest = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat);
1114 TRACE("Requesting %s selection from %s...\n",
1115 TSXGetAtomName(display, propRequest),
1116 TSXGetAtomName(display, selectionCacheSrc) );
1118 XConvertSelection(display, selectionCacheSrc, propRequest,
1119 TSXInternAtom(display, "SELECTION_DATA", False),
1122 /* wait until SelectionNotify is received */
1126 if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
1127 if( xe.xselection.selection == selectionCacheSrc )
1130 wine_tsx11_unlock();
1133 * Read the contents of the X selection property into WINE's
1134 * clipboard cache converting the selection to be compatible if possible.
1136 bRet = X11DRV_CLIPBOARD_ReadSelection( wFormat,
1137 xe.xselection.requestor,
1138 xe.xselection.property,
1139 xe.xselection.target);
1144 TRACE("\tpresent %s = %i\n", CLIPBOARD_GetFormatName(wFormat), bRet );
1147 TRACE("Returning %d\n", bRet);
1152 /**************************************************************************
1153 * ResetSelectionOwner (X11DRV.@)
1155 * Called from DestroyWindow() to prevent X selection from being lost when
1156 * a top level window is destroyed, by switching ownership to another top
1158 * Any top level window can own the selection. See X11DRV_CLIPBOARD_Acquire
1159 * for a more detailed description of this.
1161 void X11DRV_ResetSelectionOwner(HWND hwnd, BOOL bFooBar)
1163 Display *display = thread_display();
1164 HWND hWndClipOwner = 0;
1166 Window XWnd = X11DRV_get_whole_window(hwnd);
1168 BOOL bLostSelection = FALSE;
1170 /* There is nothing to do if we don't own the selection,
1171 * or if the X window which currently owns the selecion is different
1172 * from the one passed in.
1174 if ( !selectionAcquired || XWnd != selectionWindow
1175 || selectionWindow == None )
1178 if ( (bFooBar && XWnd) || (!bFooBar && !XWnd) )
1181 hWndClipOwner = GetClipboardOwner();
1182 xaClipboard = TSXInternAtom(display, _CLIPBOARD, False);
1184 TRACE("clipboard owner = %04x, selection window = %08x\n",
1185 hWndClipOwner, (unsigned)selectionWindow);
1187 /* now try to salvage current selection from being destroyed by X */
1189 TRACE("\tchecking %08x\n", (unsigned) XWnd);
1191 selectionPrevWindow = selectionWindow;
1192 selectionWindow = None;
1194 if (!(tmp = GetWindow( hwnd, GW_HWNDNEXT ))) tmp = GetWindow( hwnd, GW_HWNDFIRST );
1195 if (tmp && tmp != hwnd) selectionWindow = X11DRV_get_whole_window(tmp);
1197 if( selectionWindow != None )
1199 /* We must pretend that we don't own the selection while making the switch
1200 * since a SelectionClear event will be sent to the last owner.
1201 * If there is no owner X11DRV_CLIPBOARD_ReleaseSelection will do nothing.
1203 int saveSelectionState = selectionAcquired;
1204 selectionAcquired = False;
1206 TRACE("\tswitching selection from %08x to %08x\n",
1207 (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
1209 /* Assume ownership for the PRIMARY and CLIPBOARD selection */
1210 if ( saveSelectionState & S_PRIMARY )
1211 TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
1213 TSXSetSelectionOwner(display, xaClipboard, selectionWindow, CurrentTime);
1215 /* Restore the selection masks */
1216 selectionAcquired = saveSelectionState;
1218 /* Lose the selection if something went wrong */
1219 if ( ( (saveSelectionState & S_PRIMARY) &&
1220 (TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow) )
1221 || (TSXGetSelectionOwner(display, xaClipboard) != selectionWindow) )
1223 bLostSelection = TRUE;
1228 /* Update selection state */
1229 if (saveSelectionState & S_PRIMARY)
1230 PrimarySelectionOwner = selectionWindow;
1232 ClipboardSelectionOwner = selectionWindow;
1237 bLostSelection = TRUE;
1244 /* Launch the clipboard server if the selection can no longer be recyled
1245 * to another top level window. */
1247 if ( !X11DRV_CLIPBOARD_LaunchServer() )
1249 /* Empty the windows clipboard if the server was not launched.
1250 * We should pretend that we still own the selection BEFORE calling
1251 * EmptyClipboard() since otherwise this has the side effect of
1252 * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
1253 * to be re-acquired by us!
1256 TRACE("\tLost the selection! Emptying the clipboard...\n");
1259 selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
1264 /* Give up ownership of the windows clipboard */
1265 CLIPBOARD_ReleaseOwner();
1268 selectionAcquired = S_NOSELECTION;
1269 ClipboardSelectionOwner = PrimarySelectionOwner = 0;
1270 selectionWindow = 0;
1274 /**************************************************************************
1275 * X11DRV_CLIPBOARD_RegisterPixmapResource
1276 * Registers a Pixmap resource which is to be associated with a property Atom.
1277 * When the property is destroyed we also destroy the Pixmap through the
1278 * PropertyNotify event.
1280 BOOL X11DRV_CLIPBOARD_RegisterPixmapResource( Atom property, Pixmap pixmap )
1282 PROPERTY *prop = HeapAlloc( GetProcessHeap(), 0, sizeof(*prop) );
1283 if (!prop) return FALSE;
1284 prop->atom = property;
1285 prop->pixmap = pixmap;
1286 prop->next = prop_head;
1291 /**************************************************************************
1292 * X11DRV_CLIPBOARD_FreeResources
1294 * Called from EVENT_PropertyNotify() to give us a chance to destroy
1295 * any resources associated with this property.
1297 void X11DRV_CLIPBOARD_FreeResources( Atom property )
1299 /* Do a simple linear search to see if we have a Pixmap resource
1300 * associated with this property and release it.
1302 PROPERTY **prop = &prop_head;
1306 if ((*prop)->atom == property)
1308 PROPERTY *next = (*prop)->next;
1309 XFreePixmap( gdi_display, (*prop)->pixmap );
1310 HeapFree( GetProcessHeap(), 0, *prop );
1313 else prop = &(*prop)->next;