mirror of
git://source.winehq.org/git/wine.git
synced 2024-08-31 05:35:41 +00:00
Enabled the persistent clipboard server.
This commit is contained in:
parent
7bf36ad35d
commit
56ab55d374
|
@ -146,7 +146,7 @@ static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
|
|||
static HWND OLEClipbrd_CreateWindow();
|
||||
static void OLEClipbrd_DestroyWindow(HWND hwnd);
|
||||
LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
static HRESULT OLEClipbrd_RenderFormat(LPFORMATETC pFormatetc);
|
||||
static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc );
|
||||
static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );
|
||||
|
||||
/*
|
||||
|
@ -473,6 +473,7 @@ HRESULT WINAPI OleFlushClipboard()
|
|||
FORMATETC rgelt;
|
||||
HRESULT hr = S_OK;
|
||||
BOOL bClipboardOpen = FALSE;
|
||||
IDataObject* pIDataObjectSrc = NULL;
|
||||
|
||||
TRACE("()\n");
|
||||
|
||||
|
@ -487,6 +488,13 @@ HRESULT WINAPI OleFlushClipboard()
|
|||
if (!theOleClipboard->pIDataObjectSrc)
|
||||
return S_OK;
|
||||
|
||||
/*
|
||||
* Addref and save the source data object we are holding on to temporarily,
|
||||
* since it will be released when we empty the clipboard.
|
||||
*/
|
||||
pIDataObjectSrc = theOleClipboard->pIDataObjectSrc;
|
||||
IDataObject_AddRef(pIDataObjectSrc);
|
||||
|
||||
/*
|
||||
* Open the Windows clipboard
|
||||
*/
|
||||
|
@ -503,7 +511,7 @@ HRESULT WINAPI OleFlushClipboard()
|
|||
* Render all HGLOBAL formats supported by the source into
|
||||
* the windows clipboard.
|
||||
*/
|
||||
if ( FAILED( hr = IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
|
||||
if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc,
|
||||
DATADIR_GET,
|
||||
&penumFormatetc) ))
|
||||
{
|
||||
|
@ -522,7 +530,7 @@ HRESULT WINAPI OleFlushClipboard()
|
|||
/*
|
||||
* Render the clipboard data
|
||||
*/
|
||||
if ( FAILED(OLEClipbrd_RenderFormat( &rgelt )) )
|
||||
if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -530,13 +538,9 @@ HRESULT WINAPI OleFlushClipboard()
|
|||
IEnumFORMATETC_Release(penumFormatetc);
|
||||
|
||||
/*
|
||||
* Release the data object we are holding on to
|
||||
* Release the source data object we are holding on to
|
||||
*/
|
||||
if ( theOleClipboard->pIDataObjectSrc )
|
||||
{
|
||||
IDataObject_Release(theOleClipboard->pIDataObjectSrc);
|
||||
theOleClipboard->pIDataObjectSrc = NULL;
|
||||
}
|
||||
IDataObject_Release(pIDataObjectSrc);
|
||||
|
||||
CLEANUP:
|
||||
|
||||
|
@ -795,7 +799,7 @@ LRESULT CALLBACK OLEClipbrd_WndProc
|
|||
* Render the clipboard data.
|
||||
* (We must have a source data object or we wouldn't be in this WndProc)
|
||||
*/
|
||||
OLEClipbrd_RenderFormat( &rgelt );
|
||||
OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt );
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -835,7 +839,7 @@ LRESULT CALLBACK OLEClipbrd_WndProc
|
|||
/*
|
||||
* Render the clipboard data.
|
||||
*/
|
||||
if ( FAILED(OLEClipbrd_RenderFormat( &rgelt )) )
|
||||
if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) )
|
||||
continue;
|
||||
|
||||
TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);
|
||||
|
@ -891,14 +895,13 @@ LRESULT CALLBACK OLEClipbrd_WndProc
|
|||
* source data object.
|
||||
* Note: This function assumes it is passed an HGLOBAL format to render.
|
||||
*/
|
||||
static HRESULT OLEClipbrd_RenderFormat(LPFORMATETC pFormatetc)
|
||||
static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc)
|
||||
{
|
||||
STGMEDIUM medium;
|
||||
HGLOBAL hDup;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( FAILED(hr = IDataObject_GetData((IDataObject*)&(theOleClipboard->lpvtbl1),
|
||||
pFormatetc, &medium)) )
|
||||
if ( FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &medium)) )
|
||||
{
|
||||
WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr);
|
||||
return hr;
|
||||
|
|
|
@ -488,7 +488,7 @@ static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
|
|||
TRACE("\tconverting from '%s' to '%s', %i chars\n",
|
||||
lpSource->Name, lpTarget->Name, size);
|
||||
|
||||
lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT, size);
|
||||
lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, size);
|
||||
lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
|
||||
|
||||
if( lpstrT )
|
||||
|
@ -791,7 +791,8 @@ HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
|
|||
}
|
||||
|
||||
/* Convert between 32 -> 16 bit data, if necessary */
|
||||
if( lpRender->hData32 && !lpRender->hData16 )
|
||||
if( lpRender->hData32 && !lpRender->hData16
|
||||
&& CLIPBOARD_IsMemoryObject(wFormat) )
|
||||
{
|
||||
int size;
|
||||
if( lpRender->wFormatID == CF_METAFILEPICT )
|
||||
|
@ -857,7 +858,8 @@ HANDLE WINAPI GetClipboardData( UINT wFormat )
|
|||
}
|
||||
|
||||
/* Convert between 16 -> 32 bit data, if necessary */
|
||||
if( lpRender->hData16 && !lpRender->hData32 )
|
||||
if( lpRender->hData16 && !lpRender->hData32
|
||||
&& CLIPBOARD_IsMemoryObject(wFormat) )
|
||||
{
|
||||
int size;
|
||||
if( lpRender->wFormatID == CF_METAFILEPICT )
|
||||
|
|
|
@ -171,11 +171,6 @@ static void USER_AppExit( HINSTANCE16 hInstance )
|
|||
* but does nothing);
|
||||
*/
|
||||
|
||||
/* TODO: 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.
|
||||
*/
|
||||
|
||||
/* ModuleUnload() in "Internals" */
|
||||
|
||||
hInstance = GetExePtr( hInstance );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEFS = @DLLFLAGS@ -D__WINE__
|
||||
DEFS = @DLLFLAGS@ -D__WINE__ -DBINDIR="\"$(bindir)\""
|
||||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
|
@ -23,8 +23,6 @@ all: $(MODULE).o $(PROGRAMS)
|
|||
wineclipsrv: wineclipsrv.c
|
||||
$(CC) $(ALLCFLAGS) -o wineclipsrv $(SRCDIR)/wineclipsrv.c $(X_LIBS) $(XLIB) $(LIBS)
|
||||
|
||||
all: $(MODULE).o
|
||||
|
||||
@MAKE_RULES@
|
||||
|
||||
### Dependencies:
|
||||
|
|
|
@ -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 @@ DEFAULT_DEBUG_CHANNEL(clipboard)
|
|||
|
||||
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
|
||||
|
@ -205,6 +210,106 @@ BOOL X11DRV_CLIPBOARD_IsNativeProperty(Atom prop)
|
|||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* 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
|
||||
*
|
||||
|
@ -567,14 +672,14 @@ END:
|
|||
* 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 @@ void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
|
|||
{
|
||||
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 @@ void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
|
|||
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 @@ void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
|
|||
*/
|
||||
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 @@ void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 @@ void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
|
|||
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 @@ void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
|
|||
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 @@ void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
|
|||
else
|
||||
{
|
||||
/* Update selection state */
|
||||
selectionAcquired = saveSelectionState;
|
||||
if (saveSelectionState & S_PRIMARY)
|
||||
PrimarySelectionOwner = selectionWindow;
|
||||
|
||||
|
@ -1069,26 +1171,33 @@ void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,50 +3,123 @@
|
|||
*
|
||||
* Copyright 1999 Noel Borthwick
|
||||
*
|
||||
* USAGE:
|
||||
* wineclipsrv [selection_mask] [debugClass_mask] [clearAllSelections]
|
||||
*
|
||||
* The optional selection-mask argument is a bit mask of the selection
|
||||
* types to be acquired. Currently two selections are supported:
|
||||
* 1. PRIMARY (mask value 1)
|
||||
* 2. CLIPBOARD (mask value 2).
|
||||
*
|
||||
* debugClass_mask is a bit mask of all debugging classes for which messages
|
||||
* are to be output. The standard Wine debug class set FIXME(1), ERR(2),
|
||||
* WARN(4) and TRACE(8) are supported.
|
||||
*
|
||||
* If clearAllSelections == 1 *all* selections are lost whenever a SelectionClear
|
||||
* event is received.
|
||||
*
|
||||
* If no arguments are supplied the server aquires all selections. (mask value 3)
|
||||
* and defaults to output of only FIXME(1) and ERR(2) messages. The default for
|
||||
* clearAllSelections is 0.
|
||||
*
|
||||
* NOTES:
|
||||
* This file contains the implementation for the Clipboard server
|
||||
*
|
||||
* The Wine Clipboard Server is a standalone XLib application whose
|
||||
* purpose is to manage the X selection when Wine exits.
|
||||
* The server itself is started automatically with the appropriate
|
||||
* selection masks, whenever Wine exits after acquiring the PRIMARY and/or
|
||||
* CLIPBOARD selection. (See X11DRV_CLIPBOARD_ResetOwner)
|
||||
* When the server starts, it first proceeds to capture the selection data from
|
||||
* Wine and then takes over the selection ownership. It does this by querying
|
||||
* the current selection owner(of the specified selections) for the TARGETS
|
||||
* selection target. It then proceeds to cache all the formats exposed by
|
||||
* TARGETS. If the selection does not support the TARGETS target, or if no
|
||||
* target formats are exposed, the server simply exits.
|
||||
* Once the cache has been filled, the server then actually acquires ownership
|
||||
* of the respective selection and begins fielding selection requests.
|
||||
* Selection requests are serviced from the cache. If a selection is lost the
|
||||
* server flushes its internal cache, destroying all data previously saved.
|
||||
* Once ALL selections have been lost the server terminates.
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Lightweight debug definitions */
|
||||
/*
|
||||
* Lightweight debug definitions for Wine Clipboard Server.
|
||||
* The standard FIXME, ERR, WARN & TRACE classes are supported
|
||||
* without debug channels.
|
||||
* The standard defines NO_TRACE_MSGS and NO_DEBUG_MSGS will compile out
|
||||
* TRACE, WARN and ERR and FIXME message displays.
|
||||
*/
|
||||
|
||||
/* Internal definitions (do not use these directly) */
|
||||
|
||||
enum __DEBUG_CLASS { __DBCL_FIXME, __DBCL_ERR, __DBCL_WARN, __DBCL_TRACE, __DBCL_COUNT };
|
||||
|
||||
extern char __debug_msg_enabled[__DBCL_COUNT];
|
||||
|
||||
extern const char * const debug_cl_name[__DBCL_COUNT];
|
||||
|
||||
#define DEBUG_CLASS_COUNT __DBCL_COUNT
|
||||
|
||||
#define __GET_DEBUGGING(dbcl) (__debug_msg_enabled[(dbcl)])
|
||||
#define __SET_DEBUGGING(dbcl,on) (__debug_msg_enabled[(dbcl)] = (on))
|
||||
|
||||
|
||||
#define __DPRINTF(dbcl) \
|
||||
(!__GET_DEBUGGING(dbcl) || \
|
||||
(printf("%s:%s:%s ", debug_cl_name[(dbcl)], progname, __FUNCTION__),0)) \
|
||||
? 0 : printf
|
||||
|
||||
#define __DPRINTF(dbname) (printf("%s:%s:%s ", dbname, progname, __FUNCTION__),0) ? 0 : printf
|
||||
#define __DUMMY_DPRINTF 1 ? (void)0 : (void)((int (*)(char *, ...)) NULL)
|
||||
|
||||
/* use configure to allow user to compile out debugging messages */
|
||||
#ifndef NO_TRACE_MSGS
|
||||
#define TRACE __DPRINTF("TRACE")
|
||||
#define TRACE __DPRINTF(__DBCL_TRACE)
|
||||
#else
|
||||
#define TRACE __DUMMY_DPRINTF
|
||||
#endif /* NO_TRACE_MSGS */
|
||||
|
||||
#ifndef NO_DEBUG_MSGS
|
||||
#define WARN __DPRINTF("WARN")
|
||||
#define FIXME __DPRINTF("FIXME")
|
||||
#define WARN __DPRINTF(__DBCL_WARN)
|
||||
#define FIXME __DPRINTF(__DBCL_FIXME)
|
||||
#else
|
||||
#define WARN __DUMMY_DPRINTF
|
||||
#define FIXME __DUMMY_DPRINTF
|
||||
#endif /* NO_DEBUG_MSGS */
|
||||
|
||||
#define ERR __DPRINTF("ERROR")
|
||||
/* define error macro regardless of what is configured */
|
||||
#define ERR __DPRINTF(__DBCL_ERR)
|
||||
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
typedef int BOOL;
|
||||
|
||||
/* Internal definitions for debugging messages(do not use these directly) */
|
||||
const char * const debug_cl_name[] = { "fixme", "err", "warn", "trace" };
|
||||
char __debug_msg_enabled[DEBUG_CLASS_COUNT] = {1, 1, 0, 0};
|
||||
|
||||
|
||||
/* Selection masks */
|
||||
|
||||
#define S_NOSELECTION 0
|
||||
#define S_PRIMARY 1
|
||||
#define S_CLIPBOARD 2
|
||||
|
||||
/* Debugging class masks */
|
||||
|
||||
#define C_FIXME 1
|
||||
#define C_ERR 2
|
||||
#define C_WARN 4
|
||||
#define C_TRACE 8
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
|
@ -62,10 +135,10 @@ static char *g_szOutOfMemory = "Insufficient memory!\n";
|
|||
|
||||
/* X selection context info */
|
||||
static char _CLIPBOARD[] = "CLIPBOARD"; /* CLIPBOARD atom name */
|
||||
static char FMT_PREFIX[] = "<WCF>"; /* Prefix for windows specific formats */
|
||||
static int g_selectionToAcquire = 0; /* Masks for the selection to be acquired */
|
||||
static int g_selectionAcquired = 0; /* Contains the current selection masks */
|
||||
|
||||
static int g_clearAllSelections = 0; /* If TRUE *all* selections are lost on SelectionClear */
|
||||
|
||||
/* Selection cache */
|
||||
typedef struct tag_CACHEENTRY
|
||||
{
|
||||
|
@ -119,7 +192,6 @@ void getGC(Window win, GC *gc);
|
|||
void main(int argc, char **argv)
|
||||
{
|
||||
XEvent event;
|
||||
unsigned int width, height; /* window size */
|
||||
|
||||
if ( !Init(argc, argv) )
|
||||
exit(0);
|
||||
|
@ -130,6 +202,8 @@ void main(int argc, char **argv)
|
|||
*/
|
||||
if ( AcquireSelection() == S_NOSELECTION )
|
||||
TerminateServer(0);
|
||||
|
||||
TRACE("Clipboard server running...\n");
|
||||
|
||||
/* Start an X event loop */
|
||||
while (1)
|
||||
|
@ -243,8 +317,23 @@ BOOL Init(int argc, char **argv)
|
|||
g_selectionToAcquire = atoi(argv[1]);
|
||||
else
|
||||
g_selectionToAcquire = S_PRIMARY | S_CLIPBOARD;
|
||||
|
||||
/* Set the debugging class state from the command line argument */
|
||||
if (argc > 2)
|
||||
{
|
||||
int dbgClasses = atoi(argv[2]);
|
||||
|
||||
TRACE("Clipboard server running...\n");
|
||||
__SET_DEBUGGING(__DBCL_FIXME, dbgClasses & C_FIXME);
|
||||
__SET_DEBUGGING(__DBCL_ERR, dbgClasses & C_ERR);
|
||||
__SET_DEBUGGING(__DBCL_WARN, dbgClasses & C_WARN);
|
||||
__SET_DEBUGGING(__DBCL_TRACE, dbgClasses & C_TRACE);
|
||||
}
|
||||
|
||||
/* Set the "ClearSelections" state from the command line argument */
|
||||
if (argc > 3)
|
||||
g_clearAllSelections = atoi(argv[3]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -287,27 +376,39 @@ int AcquireSelection()
|
|||
{
|
||||
TRACE("Acquiring PRIMARY selection...\n");
|
||||
g_cPrimaryTargets = CacheDataFormats( XA_PRIMARY, &g_pPrimaryCache );
|
||||
if (g_cPrimaryTargets)
|
||||
XSetSelectionOwner(g_display, XA_PRIMARY, g_win, CurrentTime);
|
||||
else
|
||||
TRACE("No PRIMARY targets - ownership not acquired.\n");
|
||||
TRACE("Cached %ld formats...\n", g_cPrimaryTargets);
|
||||
}
|
||||
if (g_selectionToAcquire & S_CLIPBOARD)
|
||||
{
|
||||
TRACE("Acquiring CLIPBOARD selection...\n");
|
||||
g_cClipboardTargets = CacheDataFormats( xaClipboard, &g_pClipboardCache );
|
||||
|
||||
if (g_cClipboardTargets)
|
||||
XSetSelectionOwner(g_display, xaClipboard, g_win, CurrentTime);
|
||||
else
|
||||
TRACE("No CLIPBOARD targets - ownership not acquired.\n");
|
||||
TRACE("Cached %ld formats...\n", g_cClipboardTargets);
|
||||
}
|
||||
|
||||
/* Remember the acquired selections */
|
||||
if( XGetSelectionOwner(g_display,XA_PRIMARY) == g_win )
|
||||
/*
|
||||
* Now that we have cached the data, we proceed to acquire the selections
|
||||
*/
|
||||
if (g_cPrimaryTargets)
|
||||
{
|
||||
/* Acquire the PRIMARY selection */
|
||||
while (XGetSelectionOwner(g_display,XA_PRIMARY) != g_win)
|
||||
XSetSelectionOwner(g_display, XA_PRIMARY, g_win, CurrentTime);
|
||||
|
||||
g_selectionAcquired |= S_PRIMARY;
|
||||
if( XGetSelectionOwner(g_display,xaClipboard) == g_win )
|
||||
}
|
||||
else
|
||||
TRACE("No PRIMARY targets - ownership not acquired.\n");
|
||||
|
||||
if (g_cClipboardTargets)
|
||||
{
|
||||
/* Acquire the CLIPBOARD selection */
|
||||
while (XGetSelectionOwner(g_display,xaClipboard) != g_win)
|
||||
XSetSelectionOwner(g_display, xaClipboard, g_win, CurrentTime);
|
||||
|
||||
g_selectionAcquired |= S_CLIPBOARD;
|
||||
}
|
||||
else
|
||||
TRACE("No CLIPBOARD targets - ownership not acquired.\n");
|
||||
|
||||
return g_selectionAcquired;
|
||||
}
|
||||
|
@ -398,7 +499,7 @@ int CacheDataFormats( Atom SelectionSrc, PCACHEENTRY *ppCache )
|
|||
|
||||
/* Populate the cache entry */
|
||||
if (!FillCacheEntry( SelectionSrc, targetList[i], &((*ppCache)[i])))
|
||||
ERR("Failed to fill cache entry!");
|
||||
ERR("Failed to fill cache entry!\n");
|
||||
|
||||
XFree(itemFmtName);
|
||||
}
|
||||
|
@ -453,8 +554,11 @@ BOOL FillCacheEntry( Atom SelectionSrc, Atom target, PCACHEENTRY pCacheEntry )
|
|||
reqType = xe.xselection.target;
|
||||
|
||||
if(prop == None)
|
||||
{
|
||||
TRACE("\tOwner failed to convert selection!\n");
|
||||
return bRet;
|
||||
|
||||
}
|
||||
|
||||
TRACE("\tretrieving property %s from window %ld into %s\n",
|
||||
XGetAtomName(g_display,reqType), (long)w, XGetAtomName(g_display,prop) );
|
||||
|
||||
|
@ -600,7 +704,7 @@ void EmptyCache(PCACHEENTRY pCache, int nItems)
|
|||
}
|
||||
else
|
||||
{
|
||||
TRACE("Freeing %s (0x%x)...\n",
|
||||
TRACE("Freeing %s (%p)...\n",
|
||||
XGetAtomName(g_display, pCache[i].target), pCache[i].pData);
|
||||
|
||||
/* Free the cached data item (allocated by X) */
|
||||
|
@ -621,8 +725,10 @@ void EmptyCache(PCACHEENTRY pCache, int nItems)
|
|||
*/
|
||||
void EVENT_ProcessEvent( XEvent *event )
|
||||
{
|
||||
// TRACE(" event %s for Window %08lx\n", event_names[event->type], event->xany.window );
|
||||
|
||||
/*
|
||||
TRACE(" event %s for Window %08lx\n", event_names[event->type], event->xany.window );
|
||||
*/
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case Expose:
|
||||
|
@ -652,7 +758,7 @@ void EVENT_ProcessEvent( XEvent *event )
|
|||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
EVENT_PropertyNotify( (XPropertyEvent *)event );
|
||||
// EVENT_PropertyNotify( (XPropertyEvent *)event );
|
||||
break;
|
||||
|
||||
default: /* ignore all other events */
|
||||
|
@ -771,7 +877,6 @@ void EVENT_SelectionRequest( XSelectionRequestEvent *event, BOOL bIsMultiple )
|
|||
XSelectionEvent result;
|
||||
Atom rprop = None;
|
||||
Window request = event->requestor;
|
||||
BOOL couldOpen = FALSE;
|
||||
Atom xaMultiple = XInternAtom(g_display, "MULTIPLE", False);
|
||||
PCACHEENTRY pCacheEntry = NULL;
|
||||
void *pData = NULL;
|
||||
|
@ -803,7 +908,7 @@ void EVENT_SelectionRequest( XSelectionRequestEvent *event, BOOL bIsMultiple )
|
|||
}
|
||||
|
||||
/* Update the X property */
|
||||
TRACE("\tUpdating property %s...", XGetAtomName(g_display, rprop));
|
||||
TRACE("\tUpdating property %s...\n", XGetAtomName(g_display, rprop));
|
||||
|
||||
/* If we have a request for a pixmap, return a duplicate */
|
||||
|
||||
|
@ -853,17 +958,36 @@ void EVENT_SelectionClear( XSelectionClearEvent *event )
|
|||
|
||||
TRACE("()\n");
|
||||
|
||||
if (event->selection == XA_PRIMARY)
|
||||
/* 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 ( g_clearAllSelections || (event->selection == xaClipboard) )
|
||||
{
|
||||
TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
|
||||
|
||||
/* We really lost CLIPBOARD but want to voluntarily lose PRIMARY */
|
||||
if ( (event->selection == xaClipboard)
|
||||
&& (g_selectionAcquired & S_PRIMARY) )
|
||||
{
|
||||
XSetSelectionOwner(g_display, XA_PRIMARY, None, CurrentTime);
|
||||
}
|
||||
|
||||
/* We really lost PRIMARY but want to voluntarily lose CLIPBOARD */
|
||||
if ( (event->selection == XA_PRIMARY)
|
||||
&& (g_selectionAcquired & S_CLIPBOARD) )
|
||||
{
|
||||
XSetSelectionOwner(g_display, xaClipboard, None, CurrentTime);
|
||||
}
|
||||
|
||||
g_selectionAcquired = S_NOSELECTION; /* Clear the selection masks */
|
||||
}
|
||||
else if (event->selection == XA_PRIMARY)
|
||||
{
|
||||
g_selectionAcquired &= ~S_PRIMARY; /* Clear the PRIMARY flag */
|
||||
TRACE("Lost PRIMARY selection...\n");
|
||||
g_selectionAcquired &= ~S_PRIMARY; /* Clear the PRIMARY flag */
|
||||
}
|
||||
else if (event->selection == xaClipboard)
|
||||
{
|
||||
g_selectionAcquired &= ~S_CLIPBOARD; /* Clear the CLIPBOARD flag */
|
||||
TRACE("Lost CLIPBOARD selection...\n");
|
||||
}
|
||||
|
||||
|
||||
/* Once we lose all our selections we have nothing more to do */
|
||||
if (g_selectionAcquired == S_NOSELECTION)
|
||||
TerminateServer(1);
|
||||
|
@ -915,7 +1039,7 @@ Pixmap DuplicatePixmap(Pixmap pixmap)
|
|||
unsigned border_width; /* Unused */
|
||||
unsigned int depth, width, height;
|
||||
|
||||
TRACE("\t() Pixmap=%ul\n", pixmap);
|
||||
TRACE("\t() Pixmap=%ld\n", (long)pixmap);
|
||||
|
||||
/* Get the Pixmap dimensions and bit depth */
|
||||
if ( 0 == XGetGeometry(g_display, pixmap, &root, &x, &y, &width, &height,
|
||||
|
@ -933,7 +1057,7 @@ Pixmap DuplicatePixmap(Pixmap pixmap)
|
|||
|
||||
XDestroyImage(xi);
|
||||
|
||||
TRACE("\t() New Pixmap=%ul\n", newPixmap);
|
||||
TRACE("\t() New Pixmap=%ld\n", (long)newPixmap);
|
||||
return newPixmap;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue