Enabled the persistent clipboard server.
diff --git a/windows/x11drv/clipboard.c b/windows/x11drv/clipboard.c
index 3db480b..fcdc4c9 100644
--- a/windows/x11drv/clipboard.c
+++ b/windows/x11drv/clipboard.c
@@ -49,13 +49,15 @@
#ifndef X_DISPLAY_MISSING
+#include <errno.h>
#include <X11/Xatom.h>
#include <string.h>
+#include <unistd.h>
+
#include "ts_xlib.h"
#include "wine/winuser16.h"
#include "clipboard.h"
-#include "debugtools.h"
#include "message.h"
#include "win.h"
#include "windef.h"
@@ -63,6 +65,8 @@
#include "bitmap.h"
#include "commctrl.h"
#include "heap.h"
+#include "options.h"
+#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(clipboard)
@@ -76,13 +80,14 @@
static char _CLIPBOARD[] = "CLIPBOARD"; /* CLIPBOARD atom name */
static char FMT_PREFIX[] = "<WCF>"; /* Prefix for windows specific formats */
-static int selectionAcquired = 0; /* Contains the current selection masks */
+static int selectionAcquired = 0; /* Contains the current selection masks */
static Window selectionWindow = None; /* The top level X window which owns the selection */
static Window selectionPrevWindow = None; /* The last X window that owned the selection */
static Window PrimarySelectionOwner = None; /* The window which owns the primary selection */
static Window ClipboardSelectionOwner = None; /* The window which owns the clipboard selection */
static unsigned long cSelectionTargets = 0; /* Number of target formats reported by TARGETS selection */
static Atom selectionCacheSrc = XA_PRIMARY; /* The selection source from which the clipboard cache was filled */
+static HANDLE selectionClearEvent = NULL; /* Synchronization object used to block until server is started */
/*
* Dynamic pointer arrays to manage destruction of Pixmap resources
@@ -206,6 +211,106 @@
/**************************************************************************
+ * X11DRV_CLIPBOARD_LaunchServer
+ * Launches the clipboard server. This is called from X11DRV_CLIPBOARD_ResetOwner
+ * when the selection can no longer be recyled to another top level window.
+ * In order to make the selection persist after Wine shuts down a server
+ * process is launched which services subsequent selection requests.
+ */
+BOOL X11DRV_CLIPBOARD_LaunchServer()
+{
+ int iWndsLocks;
+
+ /* If persistant selection has been disabled in the .winerc Clipboard section,
+ * don't launch the server
+ */
+ if ( !PROFILE_GetWineIniInt("Clipboard", "PersistentSelection", 1) )
+ return FALSE;
+
+ /* Start up persistant WINE X clipboard server process which will
+ * take ownership of the X selection and continue to service selection
+ * requests from other apps.
+ */
+ selectionWindow = selectionPrevWindow;
+ if ( !fork() )
+ {
+ /* NOTE: This code only executes in the context of the child process
+ * Do note make any Wine specific calls here.
+ */
+
+ int dbgClasses = 0;
+ char selMask[8], dbgClassMask[8], clearSelection[8];
+
+ sprintf(selMask, "%d", selectionAcquired);
+
+ /* Build the debug class mask to pass to the server, by inheriting
+ * the settings for the clipboard debug channel.
+ */
+ dbgClasses |= __GET_DEBUGGING(__DBCL_FIXME, dbch_clipboard) ? 1 : 0;
+ dbgClasses |= __GET_DEBUGGING(__DBCL_ERR, dbch_clipboard) ? 2 : 0;
+ dbgClasses |= __GET_DEBUGGING(__DBCL_WARN, dbch_clipboard) ? 4 : 0;
+ dbgClasses |= __GET_DEBUGGING(__DBCL_TRACE, dbch_clipboard) ? 8 : 0;
+ sprintf(dbgClassMask, "%d", dbgClasses);
+
+ /* Get the clear selection preference */
+ sprintf(clearSelection, "%d",
+ PROFILE_GetWineIniInt("Clipboard", "ClearAllSelections", 0));
+
+ /* Exec the clipboard server passing it the selection and debug class masks */
+ execl( BINDIR "/wineclipsvr", "wineclipsvr",
+ selMask, dbgClassMask, clearSelection, NULL );
+ execlp( "wineclipsvr", "wineclipsvr", selMask, dbgClassMask, clearSelection, NULL );
+ execl( "./windows/x11drv/wineclipsvr", "wineclipsvr",
+ selMask, dbgClassMask, clearSelection, NULL );
+
+ /* Exec Failed! */
+ perror("Could not start Wine clipboard server");
+ exit( 1 ); /* Exit the child process */
+ }
+
+ /* Wait until the clipboard server acquires the selection.
+ * We must release the windows lock to enable Wine to process
+ * selection messages in response to the servers requests.
+ */
+
+ iWndsLocks = WIN_SuspendWndsLock();
+
+ /* We must wait until the server finishes acquiring the selection,
+ * before proceeding, otherwise the window which owns the selection
+ * will be destroyed prematurely!
+ * Create a non-signalled, auto-reset event which will be set by
+ * X11DRV_CLIPBOARD_ReleaseSelection, and wait until this gets
+ * signalled before proceeding.
+ */
+
+ if ( !(selectionClearEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) )
+ ERR("Could not create wait object. Clipboard server won't start!\n");
+ else
+ {
+ /* Make the event object's handle global */
+ selectionClearEvent = ConvertToGlobalHandle(selectionClearEvent);
+
+ /* Wait until we lose the selection, timing out after a minute */
+
+ TRACE("Waiting for clipboard server to acquire selection\n");
+
+ if ( WaitForSingleObject( selectionClearEvent, 60000 ) != WAIT_OBJECT_0 )
+ TRACE("Server could not acquire selection, or a time out occured!\n");
+ else
+ TRACE("Server successfully acquired selection\n");
+
+ /* Release the event */
+ CloseHandle(selectionClearEvent);
+ selectionClearEvent = NULL;
+ }
+
+ WIN_RestoreWndsLock(iWndsLocks);
+
+ return TRUE;
+}
+
+
+/**************************************************************************
* X11DRV_CLIPBOARD_CacheDataFormats
*
* Caches the list of data formats available from the current selection.
@@ -567,14 +672,14 @@
* Release an XA_PRIMARY or XA_CLIPBOARD selection that we own, in response
* to a SelectionClear event.
* This can occur in response to another client grabbing the X selection.
- * If the XA_CLIPBOARD selection is lost we relinquish XA_PRIMARY as well.
+ * If the XA_CLIPBOARD selection is lost, we relinquish XA_PRIMARY as well.
*/
void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
{
Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
+ int clearAllSelections = PROFILE_GetWineIniInt("Clipboard", "ClearAllSelections", 0);
- /* w is the window that lost selection,
- *
+ /* w is the window that lost the selection
* selectionPrevWindow is nonzero if CheckSelection() was called.
*/
@@ -585,12 +690,15 @@
{
if( w == selectionWindow || selectionPrevWindow == None)
{
- /* alright, we really lost it */
-
- if ( selType == xaClipboard ) /* completely give up the selection */
+ /* If we're losing the CLIPBOARD selection, or if the preferences in .winerc
+ * dictate that *all* selections should be cleared on loss of a selection,
+ * we must give up all the selections we own.
+ */
+ if ( clearAllSelections || (selType == xaClipboard) )
{
- TRACE("Lost CLIPBOARD selection\n");
-
+ /* completely give up the selection */
+ TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
+
/* We are completely giving up the selection.
* Make sure we can open the windows clipboard first. */
@@ -607,24 +715,23 @@
return;
}
- selectionPrevWindow = selectionWindow;
+ /* We really lost CLIPBOARD but want to voluntarily lose PRIMARY */
+ if ( (selType == xaClipboard)
+ && (selectionAcquired & S_PRIMARY) )
+ {
+ XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
+ }
+
+ /* We really lost PRIMARY but want to voluntarily lose CLIPBOARD */
+ if ( (selType == XA_PRIMARY)
+ && (selectionAcquired & S_CLIPBOARD) )
+ {
+ XSetSelectionOwner(display, xaClipboard, None, CurrentTime);
+ }
+
selectionWindow = None;
PrimarySelectionOwner = ClipboardSelectionOwner = 0;
- /* Voluntarily give up the PRIMARY selection if we still own it */
- if ( selectionAcquired & S_PRIMARY )
- {
- XEvent xe;
- TRACE("Releasing XA_PRIMARY selection\n");
-
- TSXSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
-
- /* Wait until SelectionClear is processed */
- if( selectionPrevWindow )
- while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
- SelectionClear, &xe ) );
- }
-
/* Empty the windows clipboard.
* We should pretend that we still own the selection BEFORE calling
* EmptyClipboard() since otherwise this has the side effect of
@@ -633,12 +740,13 @@
*/
selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
EmptyClipboard();
- selectionAcquired = S_NOSELECTION;
-
CloseClipboard();
/* Give up ownership of the windows clipboard */
CLIPBOARD_ReleaseOwner();
+
+ /* Reset the selection flags now that we are done */
+ selectionAcquired = S_NOSELECTION;
}
else if ( selType == XA_PRIMARY ) /* Give up only PRIMARY selection */
{
@@ -664,6 +772,13 @@
}
}
+ /* Signal to a selectionClearEvent listener if the selection is completely lost */
+ if (selectionClearEvent && !selectionAcquired)
+ {
+ TRACE("Lost all selections, signalling to selectionClearEvent listener\n");
+ SetEvent(selectionClearEvent);
+ }
+
selectionPrevWindow = None;
}
@@ -996,21 +1111,6 @@
TRACE("clipboard owner = %04x, selection window = %08x\n",
hWndClipOwner, (unsigned)selectionWindow);
-#if(0)
- /* Check if all formats are already in the clipboard cache */
- if( !CLIPBOARD_IsCacheRendered() )
- {
- SendMessage16(hWndClipOwner,WM_RENDERALLFORMATS,0,0L);
-
- /* check if all formats were rendered */
- if ( !CLIPBOARD_IsCacheRendered() )
- {
- ERR("\tCould not render all formats\n");
- CLIPBOARD_ReleaseOwner();
- }
- }
-#endif
-
/* now try to salvage current selection from being destroyed by X */
TRACE("\tchecking %08x\n", (unsigned) XWnd);
@@ -1041,7 +1141,10 @@
TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
TSXSetSelectionOwner(display, xaClipboard, selectionWindow, CurrentTime);
-
+
+ /* Restore the selection masks */
+ selectionAcquired = saveSelectionState;
+
/* Lose the selection if something went wrong */
if ( ( (saveSelectionState & S_PRIMARY) &&
(TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow) )
@@ -1053,7 +1156,6 @@
else
{
/* Update selection state */
- selectionAcquired = saveSelectionState;
if (saveSelectionState & S_PRIMARY)
PrimarySelectionOwner = selectionWindow;
@@ -1069,26 +1171,33 @@
END:
if (bLostSelection)
{
- /* Empty the windows clipboard.
- * We should pretend that we still own the selection BEFORE calling
- * EmptyClipboard() since otherwise this has the side effect of
- * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
- * to be re-acquired by us!
- */
+ /* Launch the clipboard server if the selection can no longer be recyled
+ * to another top level window. */
+
+ if ( !X11DRV_CLIPBOARD_LaunchServer() )
+ {
+ /* Empty the windows clipboard if the server was not launched.
+ * We should pretend that we still own the selection BEFORE calling
+ * EmptyClipboard() since otherwise this has the side effect of
+ * triggering X11DRV_CLIPBOARD_Acquire() and causing the X selection
+ * to be re-acquired by us!
+ */
+
+ TRACE("\tLost the selection! Emptying the clipboard...\n");
+
+ OpenClipboard(NULL);
+ selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
+ EmptyClipboard();
+
+ CloseClipboard();
+
+ /* Give up ownership of the windows clipboard */
+ CLIPBOARD_ReleaseOwner();
+ }
- TRACE("\tLost the selection! Emptying the clipboard...\n");
-
- OpenClipboard(NULL);
- selectionAcquired = (S_PRIMARY | S_CLIPBOARD);
- EmptyClipboard();
- selectionAcquired = S_NOSELECTION;
-
- CloseClipboard();
-
- /* Give up ownership of the windows clipboard */
- CLIPBOARD_ReleaseOwner();
- ClipboardSelectionOwner = PrimarySelectionOwner = 0;
- selectionWindow = 0;
+ selectionAcquired = S_NOSELECTION;
+ ClipboardSelectionOwner = PrimarySelectionOwner = 0;
+ selectionWindow = 0;
}
}