diff options
Diffstat (limited to 'nx-X11/programs/Xserver')
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Clipboard.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c index f8d1a5d18..18bd44099 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -106,6 +106,19 @@ typedef struct _SelectionOwner static SelectionOwner *lastSelectionOwner = NULL; +/* + * cache for targets the current selection owner + * on the real X server has to offer. We are storing the targets + * after they have been converted from XlibAtom to Atom. +*/ +typedef struct _Targets +{ + Atom *targets; + int numTargets; +} Targets; + +static Targets *targetCache = NULL; + /* FIXME: can this also be stored per selection? */ static XlibAtom serverLastRequestedSelection = -1; @@ -378,6 +391,12 @@ static void printLastServerStat(int index) fprintf(stderr, " lastServer[].time (Time) [%u]\n", ls.time); } +static void printTargetCacheStat(int index) +{ + fprintf(stderr, " targetCache[].targets (Atom *) [%p]\n", (void *)targetCache[index].targets); + fprintf(stderr, " targetCache[].numTargets (int) [%d]\n", targetCache[index].numTargets); +} + void nxagentDumpClipboardStat(void) { fprintf(stderr, "/----- Clipboard internal status -----\n"); @@ -452,6 +471,7 @@ void nxagentDumpClipboardStat(void) printSelectionStat(index); printLastClientStat(index); printLastServerStat(index); + printTargetCacheStat(index); } fprintf(stderr, "\\------------------------------------------------------------------------------\n"); @@ -747,6 +767,41 @@ int nxagentFindCurrentSelectionIndex(Atom sel) return NumCurrentSelections; } +void cacheTargets(int index, Atom* targets, int numTargets) +{ + #ifdef DEBUG + fprintf(stderr, "%s: caching [%d] targets\n", __func__, numTargets); + #endif + + SAFE_free(targetCache[index].targets); + targetCache[index].targets = targets; + targetCache[index].numTargets = numTargets; +} + +/* this is called on init, reconnect and SelectionClear */ +void invalidateTargetCache(int index) +{ + #ifdef DEBUG + fprintf(stderr, "%s: invalidating target cache [%d]\n", __func__, index); + #endif + + SAFE_free(targetCache[index].targets); + targetCache[index].numTargets = 0; +} + +void invalidateTargetCaches(void) +{ + #ifdef DEBUG + fprintf(stderr, "%s: invalidating all target caches\n", __func__); + #endif + + for (int index = 0; index < nxagentMaxSelections; index++) + { + SAFE_free(targetCache[index].targets); + targetCache[index].numTargets = 0; + } +} + /* * This is called from Events.c dispatch loop on reception of a * SelectionClear event. We receive this event if someone on the real @@ -802,6 +857,8 @@ void nxagentHandleSelectionClearFromXServer(XEvent *X) clearSelectionOwnerData(index); setClientSelectionStage(SelectionStageNone, index); + + invalidateTargetCache(index); } } @@ -1543,6 +1600,8 @@ Bool nxagentCollectPropertyEventFromXServer(int resource) 32, PropModeReplace, ulReturnItems, (unsigned char*)targets, 1); + cacheTargets(index, targets, numTargets); + endTransfer(SELECTION_SUCCESS, index); } } @@ -1951,6 +2010,12 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data, } #endif + /* + * We do not know index here so for now let's invalidate the + * complete cache on every owner change regardless of the selection. + */ + invalidateTargetCaches(); + if (nxagentExternalClipboardEventTrap) { #ifdef DEBUG @@ -2063,6 +2128,13 @@ static void setSelectionOwnerOnXServer(Selection *pSelection) storeSelectionOwnerData(index, pSelection); setClientSelectionStage(SelectionStageNone, index); + + /* + * this will be repeated on reception of the SelectionOwner callback + * but we cannot be sure if there are any intermediate requests in the queue + * already so better do it here, too + */ + invalidateTargetCache(index); } /* FIXME: commented because index is invalid here! */ @@ -2254,6 +2326,42 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, else { /* + * Shortcut: Some applications tend to post multiple + * SelectionRequests. Further it can happen that multiple + * clients are interested in clipboard content. If we already + * know the answer and no intermediate SelectionOwner event + * occured we can answer with the cached list of targets. + */ + + if (targetCache[index].targets) + { + Atom *targets = targetCache[index].targets; + int numTargets = targetCache[index].numTargets; + + #ifdef DEBUG + fprintf(stderr, "%s: Sending %d cached targets:\n", __func__, numTargets); + for (int i = 0; i < numTargets; i++) + { + fprintf(stderr, "%s: %d %s\n", __func__, targets[i], NameForIntAtom(targets[i])); + } + #endif + + ChangeWindowProperty(pWin, + property, + MakeAtom("ATOM", 4, 1), + sizeof(Atom)*8, + PropModeReplace, + numTargets, + targets, + 1); + + sendSelectionNotifyEventToClient(client, time, requestor, selection, + target, property); + + return 1; + } + + /* * do nothing - TARGETS will be handled like any other target * and passed on to the owner on the remote side. */ @@ -2760,6 +2868,13 @@ Bool nxagentInitClipboard(WindowPtr pWin) { FatalError("nxagentInitClipboard: Failed to allocate memory for the remote selection Atoms array.\n"); } + + SAFE_free(targetCache); + targetCache = (Targets *) calloc(nxagentMaxSelections, sizeof(Targets)); + if (targetCache == NULL) + { + FatalError("nxagentInitClipboard: Failed to allocate memory for target cache.\n"); + } } /* @@ -2884,6 +2999,8 @@ Bool nxagentInitClipboard(WindowPtr pWin) * clients might still be waiting for answers. Should reply * with failure then */ + + invalidateTargetCache(index); } } } @@ -2896,6 +3013,7 @@ Bool nxagentInitClipboard(WindowPtr pWin) /* FIXME: required? move to setSelectionStage? */ lastClients[index].reqTime = GetTimeInMillis(); lastServers[index].requestor = None; + invalidateTargetCache(index); } clientCutProperty = MakeAtom(szAgentNX_CUT_BUFFER_CLIENT, |