aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Sibiller <uli42@gmx.de>2022-01-29 20:36:22 +0100
committerGitHub <noreply@github.com>2022-01-29 20:36:22 +0100
commit8129c1f6bea9eac2e7af067414ebcf47c9e2fe51 (patch)
treeb6ef222c026749cec2e8e48b0686dd0539f0ed19
parent106d6c8d4bbda5e6c5eadf8dec7d8094f026e346 (diff)
parenta8d7b0c8c68d95e465fc05a1f49cfff4e969a0f5 (diff)
downloadnx-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.c114
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Events.c2
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c6
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;