From 51dae621fcfd6e6453657591205e673f16c2df04 Mon Sep 17 00:00:00 2001 From: Ulrich Sibiller Date: Wed, 2 Dec 2020 23:43:53 +0100 Subject: Clipboard.c: extend target caching for the other direction This may seem unneccessary at first sight because we are only talking to our own clients which generally is quick. But if you are using nested nx sessions or clients from remote machines (e.g. via ssh X forwarding) this still can save some lenghty communication. Plus: it helps in debugging because there are fewer messages being sent around. --- nx-X11/programs/Xserver/hw/nxagent/Clipboard.c | 93 +++++++++++++++++++++----- 1 file changed, 76 insertions(+), 17 deletions(-) (limited to 'nx-X11/programs/Xserver/hw/nxagent') diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c index 682dfbab0..f88d7588b 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -108,15 +108,21 @@ 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. + * has to offer. We are storing the targets + * after they have been converted */ typedef struct _Targets { - Atom *targets; - int numTargets; + Bool type; /* EMPTY, FORINT, FORREM */ + unsigned int numTargets; + Atom *forInt; /* Atoms converted for internal -> type Atom, not XlibAtom */ + XlibAtom *forRem; /* Atoms converted for remote -> type XlibAtom, not Atom */ } Targets; +#define EMPTY 0 +#define FORREM 1 +#define FORINT 2 + static Targets *targetCache = NULL; /* FIXME: can this also be stored per selection? */ @@ -394,7 +400,9 @@ static void printLastServerStat(int index) static void printTargetCacheStat(int index) { - fprintf(stderr, " targetCache[].targets (Atom *) [%p]\n", (void *)targetCache[index].targets); + fprintf(stderr, " targetCache[].type (int) [%d]\n", targetCache[index].type); + fprintf(stderr, " targetCache[].forInt (Atom *) [%p]\n", (void *)targetCache[index].forInt); + fprintf(stderr, " targetCache[].forRem (XlibAtom *) [%p]\n", (void *)targetCache[index].forRem); fprintf(stderr, " targetCache[].numTargets (int) [%d]\n", targetCache[index].numTargets); } @@ -768,14 +776,29 @@ int nxagentFindCurrentSelectionIndex(Atom sel) return NumCurrentSelections; } -void cacheTargets(int index, Atom* targets, int numTargets) +void cacheTargetsForInt(int index, Atom* targets, int numTargets) +{ + #ifdef DEBUG + fprintf(stderr, "%s: caching [%d] targets for internal requests\n", __func__, numTargets); + #endif + + SAFE_free(targetCache[index].forInt); + SAFE_free(targetCache[index].forRem); + targetCache[index].type = FORINT; + targetCache[index].forInt = targets; + targetCache[index].numTargets = numTargets; +} + +void cacheTargetsForRem(int index, XlibAtom* targets, int numTargets) { #ifdef DEBUG - fprintf(stderr, "%s: caching [%d] targets\n", __func__, numTargets); + fprintf(stderr, "%s: caching [%d] targets for remote requests\n", __func__, numTargets); #endif - SAFE_free(targetCache[index].targets); - targetCache[index].targets = targets; + SAFE_free(targetCache[index].forInt); + SAFE_free(targetCache[index].forRem); + targetCache[index].type = FORREM; + targetCache[index].forRem = targets; targetCache[index].numTargets = numTargets; } @@ -786,7 +809,9 @@ void invalidateTargetCache(int index) fprintf(stderr, "%s: invalidating target cache [%d]\n", __func__, index); #endif - SAFE_free(targetCache[index].targets); + SAFE_free(targetCache[index].forInt); + SAFE_free(targetCache[index].forRem); + targetCache[index].type = EMPTY; targetCache[index].numTargets = 0; } @@ -798,7 +823,9 @@ void invalidateTargetCaches(void) for (int index = 0; index < nxagentMaxSelections; index++) { - SAFE_free(targetCache[index].targets); + SAFE_free(targetCache[index].forInt); + SAFE_free(targetCache[index].forRem); + targetCache[index].type = EMPTY; targetCache[index].numTargets = 0; } } @@ -1006,7 +1033,39 @@ void nxagentHandleSelectionRequestFromXServer(XEvent *X) } else { - /* do nothing, let TARGETS be passed on to the owner later */ + /* + * 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].type == FORREM && targetCache[index].forRem) + { + XlibAtom *targets = targetCache[index].forRem; + unsigned int numTargets = targetCache[index].numTargets; + + #ifdef DEBUG + fprintf(stderr, "%s: Sending %d cached targets to remote requestor:\n", __func__, numTargets); + for (int i = 0; i < numTargets; i++) + { + fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], NameForRemAtom(targets[i])); + } + #endif + + XChangeProperty(nxagentDisplay, + X->xselectionrequest.requestor, + X->xselectionrequest.property, + XInternAtom(nxagentDisplay, "ATOM", 0), + 32, + PropModeReplace, + (unsigned char *)targets, + numTargets); + + replyRequestSelectionToXServer(X, True); + return; + } } } else if (X->xselectionrequest.target == serverTIMESTAMP) @@ -1601,7 +1660,7 @@ Bool nxagentCollectPropertyEventFromXServer(int resource) 32, PropModeReplace, ulReturnItems, (unsigned char*)targets, 1); - cacheTargets(index, targets, numTargets); + cacheTargetsForInt(index, targets, numTargets); endTransfer(SELECTION_SUCCESS, index); } @@ -1852,7 +1911,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) (unsigned char*)targets, numTargets); - SAFE_free(targets); + cacheTargetsForRem(index, targets, numTargets); } } else @@ -2358,13 +2417,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, * occured we can answer with the cached list of targets. */ - if (targetCache[index].targets) + if (targetCache[index].type == FORINT && targetCache[index].forInt) { - Atom *targets = targetCache[index].targets; + Atom *targets = targetCache[index].forInt; int numTargets = targetCache[index].numTargets; #ifdef DEBUG - fprintf(stderr, "%s: Sending %d cached targets:\n", __func__, numTargets); + fprintf(stderr, "%s: Sending %d cached targets to internal client:\n", __func__, numTargets); for (int i = 0; i < numTargets; i++) { fprintf(stderr, "%s: %d %s\n", __func__, targets[i], NameForIntAtom(targets[i])); -- cgit v1.2.3