diff options
author | Ulrich Sibiller <uli42@gmx.de> | 2022-01-29 20:36:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-29 20:36:22 +0100 |
commit | 8129c1f6bea9eac2e7af067414ebcf47c9e2fe51 (patch) | |
tree | b6ef222c026749cec2e8e48b0686dd0539f0ed19 | |
parent | 106d6c8d4bbda5e6c5eadf8dec7d8094f026e346 (diff) | |
parent | a8d7b0c8c68d95e465fc05a1f49cfff4e969a0f5 (diff) | |
download | nx-libs-8129c1f6bea9eac2e7af067414ebcf47c9e2fe51.tar.gz nx-libs-8129c1f6bea9eac2e7af067414ebcf47c9e2fe51.tar.bz2 nx-libs-8129c1f6bea9eac2e7af067414ebcf47c9e2fe51.zip |
Merge pull request #1028 from uli42/pr/fix_clipboard_callbacks
Pr/fix clipboard callbacks
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Clipboard.c | 114 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Events.c | 2 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c | 6 |
3 files changed, 80 insertions, 42 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c index f0cef595c..a45cab01e 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -95,7 +95,7 @@ const int nxagentMaxSelections = 2; /* store the remote atom for all selections */ static XlibAtom *remoteSelectionAtoms = NULL; -static Atom *localSelelectionAtoms = NULL; +static Atom *localSelectionAtoms = NULL; /* * The real owner window (inside nxagent) is stored in @@ -109,7 +109,7 @@ typedef struct _SelectionOwner ClientPtr client; /* local client */ Window window; /* local window id */ WindowPtr windowPtr; /* local window struct */ - Time lastTimeChanged; /* local time (server time) */ + TimeStamp lastTimeChanged; /* local time (server time) */ } SelectionOwner; /* @@ -364,7 +364,7 @@ static void printSelectionStat(int index) fprintf(stderr, "selection [%d]:\n", index); fprintf(stderr, " selection Atom local [%d][%s] remote [%ld][%s]\n", - localSelelectionAtoms[index], NameForLocalAtom(localSelelectionAtoms[index]), + localSelectionAtoms[index], NameForLocalAtom(localSelectionAtoms[index]), remoteSelectionAtoms[index], NameForRemoteAtom(remoteSelectionAtoms[index])); fprintf(stderr, " owner side %s\n", IS_LOCAL_OWNER(index) ? "nxagent" : "real X server/none"); fprintf(stderr, " lastSelectionOwner[].client %s\n", nxagentClientInfoString(lOwner.client)); @@ -373,10 +373,15 @@ static void printSelectionStat(int index) fprintf(stderr, " lastSelectionOwner[].windowPtr [%p] (-> [0x%x])\n", (void *)lOwner.windowPtr, WINDOWID(lOwner.windowPtr)); else fprintf(stderr, " lastSelectionOwner[].windowPtr -\n"); - fprintf(stderr, " lastSelectionOwner[].lastTimeChanged [%u]\n", lOwner.lastTimeChanged); + fprintf(stderr, " lastSelectionOwner[].lastTimeChanged [%u]\n", lOwner.lastTimeChanged.milliseconds); fprintf(stderr, " CurrentSelections[].client %s\n", nxagentClientInfoString(curSel.client)); fprintf(stderr, " CurrentSelections[].window [0x%x]\n", curSel.window); + if (curSel.pWin) + fprintf(stderr, " CurrentSelections[].pWin [%p] (-> [0x%x])\n", (void *)curSel.pWin, WINDOWID(curSel.pWin)); + else + fprintf(stderr, " CurrentSelections[].pWin -\n"); + fprintf(stderr, " CurrentSelections[].lastTimeChanged [%u]\n", curSel.lastTimeChanged.milliseconds); return; } @@ -692,7 +697,7 @@ static void initSelectionOwnerData(int index) lastSelectionOwner[index].client = NullClient; lastSelectionOwner[index].window = screenInfo.screens[0]->root->drawable.id; lastSelectionOwner[index].windowPtr = NULL; - lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis(); + lastSelectionOwner[index].lastTimeChanged = ClientTimeToServerTime(CurrentTime); } /* there's no owner on nxagent side anymore */ @@ -701,7 +706,7 @@ static void clearSelectionOwnerData(int index) lastSelectionOwner[index].client = NullClient; lastSelectionOwner[index].window = None; lastSelectionOwner[index].windowPtr = NULL; - lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis(); + lastSelectionOwner[index].lastTimeChanged = ClientTimeToServerTime(CurrentTime); } static void storeSelectionOwnerData(int index, Selection *sel) @@ -709,7 +714,7 @@ static void storeSelectionOwnerData(int index, Selection *sel) lastSelectionOwner[index].client = sel->client; lastSelectionOwner[index].window = sel->window; lastSelectionOwner[index].windowPtr = sel->pWin; - lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis(); + lastSelectionOwner[index].lastTimeChanged = ClientTimeToServerTime(CurrentTime); } static Bool matchSelectionOwner(int index, ClientPtr pClient, WindowPtr pWindow) @@ -872,8 +877,9 @@ void invalidateTargetCaches(void) /* * This is called from Events.c dispatch loop on reception of a - * SelectionClear event. We receive this event if someone on the real - * X server claims the selection ownership we have/had. + * SelectionClear or XFixes selection event from the real X + * server. We receive this event if someone on the real X server + * claims the selection ownership we have/had. * Three versions of this routine with different parameter types. */ void nxagentHandleSelectionClearFromXServerByIndex(int index) @@ -906,12 +912,15 @@ void nxagentHandleSelectionClearFromXServerByIndex(int index) return; } + UpdateCurrentTime(); + TimeStamp time = ClientTimeToServerTime(CurrentTime); + if (IS_LOCAL_OWNER(index)) { /* Send a SelectionClear event to (our) previous owner. */ xEvent x = {0}; x.u.u.type = SelectionClear; - x.u.selectionClear.time = GetTimeInMillis(); + x.u.selectionClear.time = time.milliseconds; x.u.selectionClear.window = lastSelectionOwner[index].window; x.u.selectionClear.atom = CurrentSelections[index].selection; @@ -921,8 +930,11 @@ void nxagentHandleSelectionClearFromXServerByIndex(int index) * Set the root window with the NullClient as selection owner. Our * clients asking for the owner via XGetSelectionOwner() will get * this for an answer. + * Set the CurrentSelection data just as ProcSetSelectionOwner does. */ + CurrentSelections[index].lastTimeChanged = time; CurrentSelections[index].window = screenInfo.screens[0]->root->drawable.id; + CurrentSelections[index].pWin = NULL; CurrentSelections[index].client = NullClient; clearSelectionOwnerData(index); @@ -930,6 +942,22 @@ void nxagentHandleSelectionClearFromXServerByIndex(int index) setClientSelectionStage(index, SelectionStageNone); invalidateTargetCache(index); + + /* + * Now call the callbacks. This is important, especially for + * XFixes events to work properly. Keep in mind that this will + * also call our own callback so we must be prepared there to not + * communicate back to the real X server about this SelectionClear + * event. It already knows about that... + */ + if (SelectionCallback) + { + SelectionInfoRec info = {0}; + + info.selection = &CurrentSelections[index]; + info.kind = SelectionSetOwner; + CallCallbacks(&SelectionCallback, &info); + } } else { @@ -1117,7 +1145,7 @@ void nxagentHandleSelectionRequestFromXServer(XEvent *X) * 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. + * occurred we can answer with the cached list of targets. */ if (targetCache[index].type == FOR_REMOTE && targetCache[index].forRemote) @@ -1438,7 +1466,7 @@ static void endTransfer(int index, Bool success) sendSelectionNotifyEventToClient(lastClients[index].clientPtr, lastClients[index].time, lastClients[index].requestor, - localSelelectionAtoms[index], + localSelectionAtoms[index], lastClients[index].target, success == SELECTION_SUCCESS ? lastClients[index].property : None); } @@ -2268,20 +2296,34 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data, return; } + #ifdef DEBUG + printSelectionStat(index); + #endif + + if (CurrentSelections[index].client == NullClient && + CurrentSelections[index].pWin == (WindowPtr)None && + CurrentSelections[index].window == screenInfo.screens[0]->root->drawable.id && + lastSelectionOwner[index].client == NullClient && + lastSelectionOwner[index].window == None && + lastSelectionOwner[index].windowPtr == NULL) + { + /* + * No need to propagate anything to the real X server because this + * callback was triggered by a SelectionClear from the real X + * server. See nxagentHandleSelectionClearFromXServer + */ + #ifdef DEBUG + fprintf(stderr, "%s: aborting callback because it was triggered by nxagent\n", __func__); + #endif + return; + } + /* * Always invalidate the target cache for the relevant selection. * This ensures not having invalid data in the cache. */ invalidateTargetCache(index); - #ifdef DEBUG - fprintf(stderr, "%s: pCurSel->window [0x%x]\n", __func__, pCurSel->window); - fprintf(stderr, "%s: pCurSel->pWin [0x%x]\n", __func__, WINDOWID(pCurSel->pWin)); - fprintf(stderr, "%s: pCurSel->selection [%s]\n", __func__, NameForLocalAtom(pCurSel->selection)); - fprintf(stderr, "%s: pCurSel->lastTimeChanged [%u]\n", __func__, pCurSel->lastTimeChanged.milliseconds); - fprintf(stderr, "%s: pCurSel->client [%s]\n", __func__, nxagentClientInfoString(pCurSel->client)); - #endif - if (nxagentOption(Clipboard) != ClipboardNone) /* FIXME: shouldn't we also check for != ClipboardClient? */ { Selection *pSel = NULL; @@ -2313,6 +2355,9 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data, } else { + #ifdef WARNING + fprintf(stderr, "%s: WARNING: unknown kind [%d] - data corruption?\n", __func__, info->kind); + #endif } if (pSel) @@ -2350,16 +2395,7 @@ static void setSelectionOwnerOnXServer(Selection *pSelection) } #ifdef DEBUG - fprintf(stderr, "%s: lastSelectionOwner.client %s -> %s\n", __func__, - nxagentClientInfoString(lastSelectionOwner[index].client), - nxagentClientInfoString(pSelection->client)); - fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__, - lastSelectionOwner[index].window, pSelection->window); - fprintf(stderr, "%s: lastSelectionOwner.windowPtr [%p] -> [%p] [0x%x] (serverWindow: [0x%lx])\n", __func__, - (void *)lastSelectionOwner[index].windowPtr, (void *)pSelection->pWin, - pSelection->pWin ? nxagentWindow(pSelection->pWin) : 0, serverWindow); - fprintf(stderr, "%s: lastSelectionOwner.lastTimeChanged [%u]\n", __func__, - lastSelectionOwner[index].lastTimeChanged); + printSelectionStat(index); #endif @@ -2513,7 +2549,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, #endif #ifdef DEBUG - fprintf(stderr, "%s: localSelelectionAtoms[%d] [%d] - selection [%d]\n", __func__, index, localSelelectionAtoms[index], selection); + fprintf(stderr, "%s: localSelectionAtoms[%d] [%d] - selection [%d]\n", __func__, index, localSelectionAtoms[index], selection); #endif if ((GetTimeInMillis() - lastClients[index].reqTime) >= CONVERSION_TIMEOUT) @@ -2607,7 +2643,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, * 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. + * occurred we can answer with the cached list of targets. */ if (targetCache[index].type == FOR_LOCAL && targetCache[index].forLocal) @@ -2920,7 +2956,7 @@ XlibAtom translateLocalToRemoteSelection(Atom local) for (int index = 0; index < nxagentMaxSelections; index++) { - if (local == localSelelectionAtoms[index]) + if (local == localSelectionAtoms[index]) { remote = remoteSelectionAtoms[index]; break; @@ -3122,7 +3158,7 @@ WindowPtr nxagentGetClipboardWindow(Atom property) { #ifdef DEBUG fprintf(stderr, "%s: Returning last [%d] selection owner window [%p] (0x%x).\n", __func__, - localSelelectionAtoms[index], + localSelectionAtoms[index], (void *)lastSelectionOwner[index].windowPtr, WINDOWID(lastSelectionOwner[index].windowPtr)); #endif @@ -3200,14 +3236,14 @@ Bool nxagentInitClipboard(WindowPtr pWin) FatalError("nxagentInitClipboard: Failed to allocate memory for the last servers array.\n"); } - SAFE_free(localSelelectionAtoms); - localSelelectionAtoms = (Atom *) calloc(nxagentMaxSelections, sizeof(Atom)); - if (localSelelectionAtoms == NULL) + SAFE_free(localSelectionAtoms); + localSelectionAtoms = (Atom *) calloc(nxagentMaxSelections, sizeof(Atom)); + if (localSelectionAtoms == NULL) { FatalError("nxagentInitClipboard: Failed to allocate memory for the local selection Atoms array.\n"); } - localSelelectionAtoms[nxagentPrimarySelection] = XA_PRIMARY; - localSelelectionAtoms[nxagentClipboardSelection] = MakeAtom(szAgentCLIPBOARD, strlen(szAgentCLIPBOARD), True); + localSelectionAtoms[nxagentPrimarySelection] = XA_PRIMARY; + localSelectionAtoms[nxagentClipboardSelection] = MakeAtom(szAgentCLIPBOARD, strlen(szAgentCLIPBOARD), True); SAFE_free(remoteSelectionAtoms); remoteSelectionAtoms = (XlibAtom *) calloc(nxagentMaxSelections, sizeof(XlibAtom)); diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c index 0340e0b57..7cadb987b 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Events.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c @@ -2893,7 +2893,7 @@ int nxagentHandleXFixesSelectionNotify(XEvent *X) /* * Reception of an owner change on the real X server is - for nxagent - the same as * receiving a SelectionClear event. We just need to tell a (possible) internal - * owner that is no longer owning the selection. + * owner that it is no longer owning the selection. */ nxagentHandleSelectionClearFromXServerByAtom(xfixesEvent -> xfixesselection.selection); } diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c b/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c index 5df008bbb..cd57182a1 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c +++ b/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c @@ -215,14 +215,16 @@ InitSelections(void) NumCurrentSelections += nxagentMaxSelections; CurrentSelections = newsels; + /* Note: these are the same values that will be set on a SelectionClear event */ + CurrentSelections[nxagentPrimarySelection].selection = XA_PRIMARY; - CurrentSelections[nxagentPrimarySelection].lastTimeChanged = ClientTimeToServerTime(0); + CurrentSelections[nxagentPrimarySelection].lastTimeChanged = ClientTimeToServerTime(CurrentTime); CurrentSelections[nxagentPrimarySelection].window = screenInfo.screens[0]->root->drawable.id; CurrentSelections[nxagentPrimarySelection].pWin = NULL; CurrentSelections[nxagentPrimarySelection].client = NullClient; CurrentSelections[nxagentClipboardSelection].selection = MakeAtom("CLIPBOARD", 9, 1); - CurrentSelections[nxagentClipboardSelection].lastTimeChanged = ClientTimeToServerTime(0); + CurrentSelections[nxagentClipboardSelection].lastTimeChanged = ClientTimeToServerTime(CurrentTime); CurrentSelections[nxagentClipboardSelection].window = screenInfo.screens[0]->root->drawable.id; CurrentSelections[nxagentClipboardSelection].pWin = NULL; CurrentSelections[nxagentClipboardSelection].client = NullClient; |