From 56ab55d374ed2532ca9782eb9ec70836bc9980d7 Mon Sep 17 00:00:00 2001 From: Francis Beaudet Date: Sun, 24 Oct 1999 20:22:24 +0000 Subject: [PATCH] Enabled the persistent clipboard server. --- dlls/ole32/clipboard.c | 31 ++--- windows/clipboard.c | 8 +- windows/user.c | 5 - windows/x11drv/Makefile.in | 4 +- windows/x11drv/clipboard.c | 235 +++++++++++++++++++++++++---------- windows/x11drv/wineclipsrv.c | 210 ++++++++++++++++++++++++------- wine.ini | 4 + 7 files changed, 366 insertions(+), 131 deletions(-) diff --git a/dlls/ole32/clipboard.c b/dlls/ole32/clipboard.c index 3d4ed262bae..952bb88e2b1 100644 --- a/dlls/ole32/clipboard.c +++ b/dlls/ole32/clipboard.c @@ -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; diff --git a/windows/clipboard.c b/windows/clipboard.c index 7122167b9bc..27fe04bb622 100644 --- a/windows/clipboard.c +++ b/windows/clipboard.c @@ -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 ) diff --git a/windows/user.c b/windows/user.c index ff920b2e99d..672783b2747 100644 --- a/windows/user.c +++ b/windows/user.c @@ -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 ); diff --git a/windows/x11drv/Makefile.in b/windows/x11drv/Makefile.in index afc90d3c114..8d54cf047d9 100644 --- a/windows/x11drv/Makefile.in +++ b/windows/x11drv/Makefile.in @@ -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: diff --git a/windows/x11drv/clipboard.c b/windows/x11drv/clipboard.c index 3db480b2226..fcdc4c976c8 100644 --- a/windows/x11drv/clipboard.c +++ b/windows/x11drv/clipboard.c @@ -49,13 +49,15 @@ #ifndef X_DISPLAY_MISSING +#include #include #include +#include + #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[] = ""; /* 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; } } diff --git a/windows/x11drv/wineclipsrv.c b/windows/x11drv/wineclipsrv.c index 63276f7d307..97ff7a71b59 100644 --- a/windows/x11drv/wineclipsrv.c +++ b/windows/x11drv/wineclipsrv.c @@ -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 +#include #include #include #include #include -#include -/* 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[] = ""; /* 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; } diff --git a/wine.ini b/wine.ini index a995dc8a8a8..731b1d59955 100644 --- a/wine.ini +++ b/wine.ini @@ -158,5 +158,9 @@ Startup= ;InitialColumns=80 ;TerminalType=nxterm +[Clipboard] +ClearAllSelections=0 +PersistentSelection=1 + #