diff --git a/configure.ac b/configure.ac index cba7d24ea..8dc719852 100644 --- a/configure.ac +++ b/configure.ac @@ -2143,7 +2143,7 @@ if test "x$XWIN" = xyes; then AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) AC_CHECK_TOOL(WINDRES, windres) - PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau]) + PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfixes]) if test "x$WINDOWSWM" = xauto; then PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no]) diff --git a/hw/xwin/InitInput.c b/hw/xwin/InitInput.c index 38203c906..3e9ee41e6 100644 --- a/hw/xwin/InitInput.c +++ b/hw/xwin/InitInput.c @@ -39,7 +39,6 @@ #ifdef XWIN_CLIPBOARD int winProcEstablishConnection(ClientPtr /* client */ ); -int winProcSetSelectionOwner(ClientPtr /* client */ ); #endif /* diff --git a/hw/xwin/winclipboard.h b/hw/xwin/winclipboard.h index 63dce733d..503d6acfe 100644 --- a/hw/xwin/winclipboard.h +++ b/hw/xwin/winclipboard.h @@ -116,7 +116,14 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); */ int - winClipboardFlushXEvents(HWND hwnd, int iWindow, Display * pDisplay, Bool fUnicodeSupport); + + +Atom +winClipboardGetLastOwnedSelectionAtom(void); + +void +winClipboardInitMonitoredSelections(void); + #endif diff --git a/hw/xwin/winclipboardinit.c b/hw/xwin/winclipboardinit.c index 4912b2e7d..e74e2b23d 100644 --- a/hw/xwin/winclipboardinit.c +++ b/hw/xwin/winclipboardinit.c @@ -35,25 +35,16 @@ #include #include -#include "dixstruct.h" +#include "os.h" #include "winclipboard.h" #define WIN_CLIPBOARD_RETRIES 40 #define WIN_CLIPBOARD_DELAY 1 -/* - * Local typedefs - */ - -typedef int (*winDispatchProcPtr) (ClientPtr); - -int winProcSetSelectionOwner(ClientPtr /* client */ ); - /* * References to external symbols */ -extern winDispatchProcPtr winProcSetSelectionOwnerOrig; extern Bool g_fClipboard; extern HWND g_hwndClipboard; extern Bool g_fClipboardStarted; @@ -108,12 +99,6 @@ winInitClipboard(void) { winDebug("winInitClipboard ()\n"); - /* Wrap some internal server functions */ - if (ProcVector[X_SetSelectionOwner] != winProcSetSelectionOwner) { - winProcSetSelectionOwnerOrig = ProcVector[X_SetSelectionOwner]; - ProcVector[X_SetSelectionOwner] = winProcSetSelectionOwner; - } - /* Spawn a thread for the Clipboard module */ if (pthread_create(&g_ptClipboardProc, NULL, winClipboardThreadProc, NULL)) { /* Bail if thread creation failed */ diff --git a/hw/xwin/winclipboardthread.c b/hw/xwin/winclipboardthread.c index 2ef73bde9..04ab24f7f 100644 --- a/hw/xwin/winclipboardthread.c +++ b/hw/xwin/winclipboardthread.c @@ -43,6 +43,7 @@ #include #endif #include "misc.h" +#include #define WIN_CONNECT_RETRIES 40 #define WIN_CONNECT_DELAY 4 @@ -66,6 +67,8 @@ static XIOErrorHandler g_winClipboardOldIOErrorHandler; static pthread_t g_winClipboardProcThread; Bool g_fUseUnicode = FALSE; +int xfixes_event_base; +int xfixes_error_base; /* * Local function prototypes @@ -206,6 +209,9 @@ winClipboardProc(void *pvNotUsed) iMaxDescriptor = iConnectionNumber + 1; #endif + if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base)) + ErrorF ("winClipboardProc - XFixes extension not present\n"); + /* Create atom */ atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); @@ -229,9 +235,26 @@ winClipboardProc(void *pvNotUsed) ErrorF("winClipboardProc - XSelectInput generated BadWindow " "on messaging window\n"); + XFixesSelectSelectionInput (pDisplay, + iWindow, + XA_PRIMARY, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + + XFixesSelectSelectionInput (pDisplay, + iWindow, + XInternAtom (pDisplay, "CLIPBOARD", False), + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + /* Save the window in the screen privates */ g_iClipboardWindow = iWindow; + /* Initialize monitored selection state */ + winClipboardInitMonitoredSelections(); + /* Create Windows messaging window */ hwnd = winClipboardCreateMessagingWindow(); diff --git a/hw/xwin/winclipboardwndproc.c b/hw/xwin/winclipboardwndproc.c index 90dc9e0bb..d73c2db40 100644 --- a/hw/xwin/winclipboardwndproc.c +++ b/hw/xwin/winclipboardwndproc.c @@ -50,7 +50,6 @@ extern void *g_pClipboardDisplay; extern Window g_iClipboardWindow; -extern Atom g_atomLastOwnedSelection; /* * Process X events up to specified timeout @@ -423,7 +422,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Request the selection contents */ iReturn = XConvertSelection(pDisplay, - g_atomLastOwnedSelection, + winClipboardGetLastOwnedSelectionAtom(), XInternAtom(pDisplay, "COMPOUND_TEXT", False), XInternAtom(pDisplay, diff --git a/hw/xwin/winclipboardwrappers.c b/hw/xwin/winclipboardwrappers.c index 99dfc5b47..2679f4f98 100644 --- a/hw/xwin/winclipboardwrappers.c +++ b/hw/xwin/winclipboardwrappers.c @@ -33,35 +33,21 @@ #ifdef HAVE_XWIN_CONFIG_H #include #endif + #include "win.h" #include "dixstruct.h" -#include - -/* - * Constants - */ - -#define CLIP_NUM_SELECTIONS 2 -#define CLIP_OWN_PRIMARY 0 -#define CLIP_OWN_CLIPBOARD 1 /* * Local function prototypes */ DISPATCH_PROC(winProcEstablishConnection); -DISPATCH_PROC(winProcSetSelectionOwner); /* * References to external symbols */ -extern Bool g_fClipboardStarted; extern Bool g_fClipboard; -extern Window g_iClipboardWindow; -extern Atom g_atomLastOwnedSelection; -extern HWND g_hwndClipboard; - /* * Wrapper for internal EstablishConnection function. @@ -157,202 +143,3 @@ winProcEstablishConnection(ClientPtr client) return iReturn; } - -/* - * Wrapper for internal SetSelectionOwner function. - * Grabs ownership of Windows clipboard when X11 clipboard owner changes. - */ - -int -winProcSetSelectionOwner(ClientPtr client) -{ - int i; - DrawablePtr pDrawable; - WindowPtr pWindow = None; - Bool fOwnedToNotOwned = FALSE; - static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None }; - static unsigned long s_ulServerGeneration = 0; - - REQUEST(xSetSelectionOwnerReq); - - REQUEST_SIZE_MATCH(xSetSelectionOwnerReq); - - winDebug("winProcSetSelectionOwner - Hello.\n"); - - /* Watch for server reset */ - if (s_ulServerGeneration != serverGeneration) { - /* Save new generation number */ - s_ulServerGeneration = serverGeneration; - - /* Initialize static variables */ - for (i = 0; i < CLIP_NUM_SELECTIONS; ++i) - s_iOwners[i] = None; - } - - /* Abort if clipboard not completely initialized yet */ - if (!g_fClipboardStarted) { - /* ErrorF ("winProcSetSelectionOwner - Clipboard not yet started, " - "aborting.\n"); */ - goto winProcSetSelectionOwner_Done; - } - - /* Grab window if we have one */ - if (None != stuff->window) { - /* Grab the Window from the request */ - int rc = - dixLookupWindow(&pWindow, stuff->window, client, DixReadAccess); - if (rc != Success) { - ErrorF("winProcSetSelectionOwner - Found BadWindow, aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - } - - /* Now we either have a valid window or None */ - - /* Save selection owners for monitored selections, ignore other selections */ - if (XA_PRIMARY == stuff->selection) { - /* Look for owned -> not owned transition */ - if (None == stuff->window && None != s_iOwners[CLIP_OWN_PRIMARY]) { - fOwnedToNotOwned = TRUE; - - winDebug("winProcSetSelectionOwner - PRIMARY - Going from " - "owned to not owned.\n"); - - /* Adjust last owned selection */ - if (None != s_iOwners[CLIP_OWN_CLIPBOARD]) - g_atomLastOwnedSelection = MakeAtom("CLIPBOARD", 9, TRUE); - else - g_atomLastOwnedSelection = None; - } - - /* Save new selection owner or None */ - s_iOwners[CLIP_OWN_PRIMARY] = stuff->window; - - winDebug("winProcSetSelectionOwner - PRIMARY - Now owned by: %d\n", - stuff->window); - } - else if (MakeAtom("CLIPBOARD", 9, TRUE) == stuff->selection) { - /* Look for owned -> not owned transition */ - if (None == stuff->window && None != s_iOwners[CLIP_OWN_CLIPBOARD]) { - fOwnedToNotOwned = TRUE; - - winDebug("winProcSetSelectionOwner - CLIPBOARD - Going from " - "owned to not owned.\n"); - - /* Adjust last owned selection */ - if (None != s_iOwners[CLIP_OWN_PRIMARY]) - g_atomLastOwnedSelection = XA_PRIMARY; - else - g_atomLastOwnedSelection = None; - } - - /* Save new selection owner or None */ - s_iOwners[CLIP_OWN_CLIPBOARD] = stuff->window; - - winDebug("winProcSetSelectionOwner - CLIPBOARD - Now owned by: %d\n", - stuff->window); - - } - else - goto winProcSetSelectionOwner_Done; - - /* - * At this point, if one of the selections is still owned by the - * clipboard manager then it should be marked as unowned since - * we will be taking ownership of the Win32 clipboard. - */ - if (g_iClipboardWindow == s_iOwners[CLIP_OWN_PRIMARY]) - s_iOwners[CLIP_OWN_PRIMARY] = None; - if (g_iClipboardWindow == s_iOwners[CLIP_OWN_CLIPBOARD]) - s_iOwners[CLIP_OWN_CLIPBOARD] = None; - - /* - * Handle case when selection is being disowned, - * WM_DRAWCLIPBOARD did not do the disowning, - * both monitored selections are no longer owned, - * an owned to not owned transition was detected, - * and we currently own the Win32 clipboard. - */ - if (stuff->window == None - && s_iOwners[CLIP_OWN_PRIMARY] == None - && s_iOwners[CLIP_OWN_CLIPBOARD] == None - && fOwnedToNotOwned - && g_hwndClipboard != NULL && g_hwndClipboard == GetClipboardOwner()) { - winDebug("winProcSetSelectionOwner - We currently own the " - "clipboard and neither the PRIMARY nor the CLIPBOARD " - "selections are owned, releasing ownership of Win32 " - "clipboard.\n"); - - /* Release ownership of the Windows clipboard */ - OpenClipboard(NULL); - EmptyClipboard(); - CloseClipboard(); - - goto winProcSetSelectionOwner_Done; - } - - /* Abort if no window at this point */ - if (None == stuff->window) { - winDebug("winProcSetSelectionOwner - No window, returning.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Abort if invalid selection */ - if (!ValidAtom(stuff->selection)) { - ErrorF("winProcSetSelectionOwner - Found BadAtom, aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Cast Window to Drawable */ - pDrawable = (DrawablePtr) pWindow; - - /* Abort if clipboard manager is owning the selection */ - if (pDrawable->id == g_iClipboardWindow) { - winDebug("winProcSetSelectionOwner - We changed ownership, " - "aborting.\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Abort if root window is taking ownership */ - if (pDrawable->id == 0) { - ErrorF("winProcSetSelectionOwner - Root window taking ownership, " - "aborting\n"); - goto winProcSetSelectionOwner_Done; - } - - /* Close clipboard if we have it open already */ - if (GetOpenClipboardWindow() == g_hwndClipboard) { - CloseClipboard(); - } - - /* Access the Windows clipboard */ - if (!OpenClipboard(g_hwndClipboard)) { - ErrorF("winProcSetSelectionOwner - OpenClipboard () failed: %08x\n", - (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - /* Take ownership of the Windows clipboard */ - if (!EmptyClipboard()) { - ErrorF("winProcSetSelectionOwner - EmptyClipboard () failed: %08x\n", - (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - /* Advertise regular text and unicode */ - SetClipboardData(CF_UNICODETEXT, NULL); - SetClipboardData(CF_TEXT, NULL); - - /* Save handle to last owned selection */ - g_atomLastOwnedSelection = stuff->selection; - - /* Release the clipboard */ - if (!CloseClipboard()) { - ErrorF("winProcSetSelectionOwner - CloseClipboard () failed: " - "%08x\n", (int) GetLastError()); - goto winProcSetSelectionOwner_Done; - } - - winProcSetSelectionOwner_Done: - return (*winProcSetSelectionOwnerOrig) (client); -} diff --git a/hw/xwin/winclipboardxevents.c b/hw/xwin/winclipboardxevents.c index 7d3c30e85..a792467f0 100644 --- a/hw/xwin/winclipboardxevents.c +++ b/hw/xwin/winclipboardxevents.c @@ -33,8 +33,95 @@ #ifdef HAVE_XWIN_CONFIG_H #include #endif + #include "winclipboard.h" #include "misc.h" +#include + +/* + * Constants + */ + +#define CLIP_NUM_SELECTIONS 2 +#define CLIP_OWN_NONE -1 +#define CLIP_OWN_PRIMARY 0 +#define CLIP_OWN_CLIPBOARD 1 + +/* + * Global variables + */ + +extern int xfixes_event_base; + +/* + * Local variables + */ + +static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None }; +static const char *szSelectionNames[CLIP_NUM_SELECTIONS] = + { "PRIMARY", "CLIPBOARD" }; + +static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; +static Atom atomClipboard = None; + +static void +MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i) +{ + /* Look for owned -> not owned transition */ + if (None == e->owner && None != s_iOwners[i]) { + unsigned int other_index; + + winDebug("MonitorSelection - %s - Going from owned to not owned.\n", + szSelectionNames[i]); + + /* If this selection is not owned, the other monitored selection must be the most + recently owned, if it is owned at all */ + if (i == CLIP_OWN_PRIMARY) + other_index = CLIP_OWN_CLIPBOARD; + if (i == CLIP_OWN_CLIPBOARD) + other_index = CLIP_OWN_PRIMARY; + if (None != s_iOwners[other_index]) + lastOwnedSelectionIndex = other_index; + else + lastOwnedSelectionIndex = CLIP_OWN_NONE; + } + + /* Save last owned selection */ + if (None != e->owner) { + lastOwnedSelectionIndex = i; + } + + /* Save new selection owner or None */ + s_iOwners[i] = e->owner; + winDebug("MonitorSelection - %s - Now owned by XID %x\n", + szSelectionNames[i], e->owner); +} + +Atom +winClipboardGetLastOwnedSelectionAtom(void) +{ + if (lastOwnedSelectionIndex == CLIP_OWN_NONE) + return None; + + if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) + return XA_PRIMARY; + + if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) + return atomClipboard; + + return None; +} + + +void +winClipboardInitMonitoredSelections(void) +{ + /* Initialize static variables */ + for (int i = 0; i < CLIP_NUM_SELECTIONS; ++i) + s_iOwners[i] = None; + + lastOwnedSelectionIndex = CLIP_OWN_NONE; +} /* * Process any pending X events @@ -52,6 +139,7 @@ winClipboardFlushXEvents(HWND hwnd, if (generation != serverGeneration) { generation = serverGeneration; + atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); atomLocalProperty = XInternAtom(pDisplay, WIN_LOCAL_PROPERTY, False); atomUTF8String = XInternAtom(pDisplay, "UTF8_STRING", False); atomCompoundText = XInternAtom(pDisplay, "COMPOUND_TEXT", False); @@ -77,7 +165,6 @@ winClipboardFlushXEvents(HWND hwnd, wchar_t *pwszUnicodeStr = NULL; int iUnicodeLen = 0; int iReturnDataLen = 0; - int i; Bool fAbort = FALSE; Bool fCloseClipboard = FALSE; Bool fSetClipboardData = TRUE; @@ -525,6 +612,8 @@ winClipboardFlushXEvents(HWND hwnd, if (iReturn == Success || iReturn > 0) { /* Conversion succeeded or some unconvertible characters */ if (ppszTextList != NULL) { + int i; + iReturnDataLen = 0; for (i = 0; i < iCount; i++) { iReturnDataLen += strlen(ppszTextList[i]); @@ -693,8 +782,78 @@ winClipboardFlushXEvents(HWND hwnd, break; default: - ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", - event.type); + if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { + XFixesSelectionNotifyEvent *e = + (XFixesSelectionNotifyEvent *) & event; + + winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); + + /* Save selection owners for monitored selections, ignore other selections */ + if (e->selection == XA_PRIMARY) { + MonitorSelection(e, CLIP_OWN_PRIMARY); + } + else if (e->selection == atomClipboard) { + MonitorSelection(e, CLIP_OWN_CLIPBOARD); + } + else + break; + + /* Selection is being disowned */ + if (e->owner == None) { + winDebug + ("winClipboardFlushXEvents - No window, returning.\n"); + break; + } + + /* + XXX: there are all kinds of wacky edge cases we might need here: + - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? + - root window is taking ownership? + */ + + /* If we are the owner of the most recently owned selection, don't go all recursive :) */ + if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && + (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { + winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); + break; + } + + /* Close clipboard if we have it open already (possible? correct??) */ + if (GetOpenClipboardWindow() == hwnd) { + CloseClipboard(); + } + + /* Access the Windows clipboard */ + if (!OpenClipboard(hwnd)) { + ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + + /* Take ownership of the Windows clipboard */ + if (!EmptyClipboard()) { + ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + + /* Advertise regular text and unicode */ + SetClipboardData(CF_UNICODETEXT, NULL); + SetClipboardData(CF_TEXT, NULL); + + /* Release the clipboard */ + if (!CloseClipboard()) { + ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", + (int) GetLastError()); + break; + } + } + /* XFixesSelectionWindowDestroyNotifyMask */ + /* XFixesSelectionClientCloseNotifyMask */ + else { + ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", + event.type); + } break; } } diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c index 095ecff67..b3f18ae4b 100644 --- a/hw/xwin/winglobals.c +++ b/hw/xwin/winglobals.c @@ -86,7 +86,6 @@ pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER; * Wrapped DIX functions */ winDispatchProcPtr winProcEstablishConnectionOrig = NULL; -winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL; /* * Clipboard variables @@ -98,7 +97,6 @@ Bool g_fClipboardStarted = FALSE; HWND g_hwndClipboard = NULL; void *g_pClipboardDisplay = NULL; Window g_iClipboardWindow = None; -Atom g_atomLastOwnedSelection = None; #endif /* @@ -113,7 +111,6 @@ winInitializeGlobals(void) #ifdef XWIN_CLIPBOARD g_iClipboardWindow = None; g_pClipboardDisplay = NULL; - g_atomLastOwnedSelection = None; g_hwndClipboard = NULL; #endif } diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h index 60c00da42..5d8e7a075 100644 --- a/hw/xwin/winglobals.h +++ b/hw/xwin/winglobals.h @@ -72,7 +72,6 @@ typedef int (*winDispatchProcPtr) (ClientPtr); * Wrapped DIX functions */ extern winDispatchProcPtr winProcEstablishConnectionOrig; -extern winDispatchProcPtr winProcSetSelectionOwnerOrig; #endif /* The global X default icons */