Commit 56ab55d3 authored by Francis Beaudet's avatar Francis Beaudet Committed by Alexandre Julliard

Enabled the persistent clipboard server.

parent 7bf36ad3
......@@ -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");
......@@ -488,6 +489,13 @@ HRESULT WINAPI OleFlushClipboard()
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
*/
if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
......@@ -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 );
......
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
......@@ -206,6 +211,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
*
* Caches the list of data formats available from the current selection.
......@@ -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;
selectionWindow = None;
PrimarySelectionOwner = ClipboardSelectionOwner = 0;
/* We really lost CLIPBOARD but want to voluntarily lose PRIMARY */
if ( (selType == xaClipboard)
&& (selectionAcquired & S_PRIMARY) )
{
XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
}
/* Voluntarily give up the PRIMARY selection if we still own it */
if ( selectionAcquired & S_PRIMARY )
/* We really lost PRIMARY but want to voluntarily lose CLIPBOARD */
if ( (selType == XA_PRIMARY)
&& (selectionAcquired & S_CLIPBOARD) )
{
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 ) );
XSetSelectionOwner(display, xaClipboard, None, CurrentTime);
}
selectionWindow = None;
PrimarySelectionOwner = ClipboardSelectionOwner = 0;
/* 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
*
* TODO:
* 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) )
{
g_selectionAcquired &= ~S_PRIMARY; /* Clear the PRIMARY flag */
TRACE("Lost PRIMARY selection...\n");
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 == xaClipboard)
else if (event->selection == XA_PRIMARY)
{
g_selectionAcquired &= ~S_CLIPBOARD; /* Clear the CLIPBOARD flag */
TRACE("Lost CLIPBOARD selection...\n");
TRACE("Lost PRIMARY selection...\n");
g_selectionAcquired &= ~S_PRIMARY; /* Clear the PRIMARY flag */
}
/* 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;
}
......
......@@ -158,5 +158,9 @@ Startup=
;InitialColumns=80
;TerminalType=nxterm
[Clipboard]
ClearAllSelections=0
PersistentSelection=1
# </wineconf>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment