aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2020-01-05 23:50:21 +0100
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2020-01-05 23:50:21 +0100
commite89fb895a25004496b7dde4aec5fd7574baf6f25 (patch)
tree9f7decd9b6ebc4d922648ae4bb8633398b57d256
parent057ce728fcb43e6b91a54f98f6f6d9ed8fe680a6 (diff)
parent30fb45b2a65aa8cf1a544339b1288119319de455 (diff)
downloadnx-libs-e89fb895a25004496b7dde4aec5fd7574baf6f25.tar.gz
nx-libs-e89fb895a25004496b7dde4aec5fd7574baf6f25.tar.bz2
nx-libs-e89fb895a25004496b7dde4aec5fd7574baf6f25.zip
Merge branch 'uli42-pr/more_clipboard_improvements' into 3.6.x
Attributes GH PR #877: https://github.com/ArcticaProject/nx-libs/pull/877
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Atoms.c6
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Atoms.h2
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Clipboard.c666
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Clipboard.h5
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/NXproperty.c4
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Options.h18
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Splash.c4
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Window.c4
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Windows.h2
9 files changed, 429 insertions, 282 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Atoms.c b/nx-X11/programs/Xserver/hw/nxagent/Atoms.c
index 6bd945de7..4e9b7fb1f 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Atoms.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Atoms.c
@@ -81,6 +81,9 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] =
"WM_NX_READY", /* 3 */
"MCOPGLOBALS", /* 4 */
"NX_CUT_BUFFER_SERVER", /* 5 */
+ /* Unfortunately we cannot rename this to NX_SELTRANS_TO_AGENT
+ because nomachine's nxclient is depending on this
+ selection */
"TARGETS", /* 6 */
"TEXT", /* 7 */
"NX_AGENT_SIGNATURE", /* 8 */
@@ -90,7 +93,8 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] =
"UTF8_STRING", /* 12 */
"_NET_WM_STATE", /* 13 */
"_NET_WM_STATE_FULLSCREEN", /* 14 */
- "NX_CUT_BUFFER_CLIENT", /* 15 */
+ "NX_SELTRANS_FROM_AGENT", /* 15 */
+ "COMPOUND_TEXT", /* 16 */
NULL,
NULL
};
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Atoms.h b/nx-X11/programs/Xserver/hw/nxagent/Atoms.h
index f770c7e66..d04874f25 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Atoms.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Atoms.h
@@ -30,7 +30,7 @@
#include "../../include/window.h"
#include "screenint.h"
-#define NXAGENT_NUMBER_OF_ATOMS 17
+#define NXAGENT_NUMBER_OF_ATOMS 18
extern Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS];
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c
index b42396731..47eaa946d 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c
@@ -67,12 +67,12 @@ extern Selection *CurrentSelections;
int nxagentLastClipboardClient = -1;
-static int agentClipboardStatus;
+static int agentClipboardInitialized = False;
#ifdef DEBUG
static int clientAccum;
#endif
-XlibAtom serverCutProperty;
+XlibAtom serverTransToAgentProperty;
Atom clientCutProperty;
static Window serverWindow;
@@ -98,6 +98,8 @@ typedef struct _SelectionOwner
static SelectionOwner *lastSelectionOwner;
static XlibAtom nxagentLastRequestedSelection;
+#define IS_INTERNAL_OWNER(lsoindex) (lastSelectionOwner[lsoindex].client != NULL)
+
/*
* Needed to handle the notify selection event to
* be sent to client once the selection property
@@ -133,18 +135,34 @@ static Time lastServerTime;
static XlibAtom serverTARGETS;
static XlibAtom serverTIMESTAMP;
static XlibAtom serverTEXT;
+static XlibAtom serverCOMPOUND_TEXT;
static XlibAtom serverUTF8_STRING;
-static XlibAtom serverClientCutProperty;
+static XlibAtom serverTransFromAgentProperty;
static Atom clientTARGETS;
+static Atom clientTIMESTAMP;
static Atom clientTEXT;
static Atom clientCOMPOUND_TEXT;
static Atom clientUTF8_STRING;
+static Atom clientCLIPBOARD;
static char szAgentTARGETS[] = "TARGETS";
static char szAgentTEXT[] = "TEXT";
+static char szAgentTIMESTAMP[] = "TIMESTAMP";
static char szAgentCOMPOUND_TEXT[] = "COMPOUND_TEXT";
static char szAgentUTF8_STRING[] = "UTF8_STRING";
static char szAgentNX_CUT_BUFFER_CLIENT[] = "NX_CUT_BUFFER_CLIENT";
+static char szAgentCLIPBOARD[] = "CLIPBOARD";
+
+/* number of milliseconds to wait for a conversion from the real X server. */
+#define CONVERSION_TIMEOUT 5000
+
+#ifdef DEBUG
+/*
+ * Time window (milliseconds) within to detect multiple conversion
+ * calls of the same client.
+ */
+#define ACCUM_TIME 5000
+#endif
/*
* some helpers for debugging output
@@ -170,10 +188,12 @@ const char * GetClientSelectionStageString(int stage)
#else
#define SetClientSelectionStage(stage) do {lastClientStage = SelectionStage##stage;} while (0)
#define PrintClientSelectionStage()
-#endif
/*
* see also nx-X11/lib/src/ErrDes.c
+ *
+ * We use our own version to avoid Xlib doing expensive calls.
+ * FIXME: Must check if XGetErrorText() is really causing traffic over the wire.
*/
const char * GetXErrorString(int code)
{
@@ -200,6 +220,7 @@ const char * GetXErrorString(int code)
default: return("UNKNOWN!"); break;;
}
}
+#endif
/*
* Save the values queried from X server.
@@ -223,6 +244,10 @@ int nxagentSendNotify(xEvent *event);
void nxagentPrintClipboardStat(char *);
+#ifdef NXAGENT_TIMESTAMP
+extern unsigned long startTime;
+#endif
+
#ifdef DEBUG
void nxagentPrintSelectionStat(int sel)
{
@@ -280,19 +305,19 @@ void nxagentPrintSelectionStat(int sel)
void nxagentPrintClipboardStat(char *header)
{
#ifdef DEBUG
- char *s =NULL;
+ char *s = NULL;
fprintf(stderr, "/----- Clipboard internal status - %s -----\n", header);
fprintf(stderr, " current time (Time) [%u]\n", GetTimeInMillis());
- fprintf(stderr, " agentClipboardStatus (int) [%d]\n", agentClipboardStatus);
+ fprintf(stderr, " agentClipboardInitialized (Bool) [%s]\n", agentClipboardInitialized ? "True" : "False");
fprintf(stderr, " clientAccum (int) [%d]\n", clientAccum);
fprintf(stderr, " nxagentMaxSelections (int) [%d]\n", nxagentMaxSelections);
fprintf(stderr, " NumCurrentSelections (int) [%d]\n", NumCurrentSelections);
fprintf(stderr, " serverWindow (Window) [0x%x]\n", serverWindow);
fprintf(stderr, " nxagentLastClipboardClient (int) [%d]\n", nxagentLastClipboardClient);
- fprintf(stderr, " ClipboardMode ");
+ fprintf(stderr, " Clipboard mode ");
switch(nxagentOption(Clipboard))
{
case ClipboardBoth: fprintf(stderr, "[Both]"); break;;
@@ -301,7 +326,7 @@ void nxagentPrintClipboardStat(char *header)
case ClipboardNone: fprintf(stderr, "[None]"); break;;
default: fprintf(stderr, "[UNKNOWN] (FAIL!)"); break;;
}
- fprintf(stderr,"\n");
+ fprintf(stderr, "\n");
fprintf(stderr, "lastServer\n");
fprintf(stderr, " lastServerRequestor (Window) [0x%x]\n", lastServerRequestor);
@@ -336,21 +361,25 @@ void nxagentPrintClipboardStat(char *header)
fprintf(stderr, " serverTARGETS [% 4d][%s]\n", serverTARGETS, validateString(s));
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTEXT);
fprintf(stderr, " serverTEXT [% d][%s]\n", serverTEXT, s);
+ SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverCOMPOUND_TEXT);
+ fprintf(stderr, " serverCOMPOUND_TEXT [% d][%s]\n", serverCOMPOUND_TEXT, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverUTF8_STRING);
fprintf(stderr, " serverUTF8_STRING [% 4d][%s]\n", serverUTF8_STRING, s);
- SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverCutProperty);
- fprintf(stderr, " serverCutProperty [% 4d][%s]\n", serverCutProperty, s);
- SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverClientCutProperty);
- fprintf(stderr, " serverClientCutProperty [% 4d][%s]\n", serverClientCutProperty, s);
+ SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTransToAgentProperty);
+ fprintf(stderr, " serverTransToAgentProperty [% 4d][%s]\n", serverTransFromAgentProperty, s);
+ SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTransFromAgentProperty);
+ fprintf(stderr, " serverTransFromAgentProperty [% 4d][%s]\n", serverTransToAgentProperty, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTIMESTAMP);
fprintf(stderr, " serverTIMESTAMP [% 4d][%s]\n", serverTIMESTAMP, s);
fprintf(stderr, "Atoms (inside nxagent)\n");
fprintf(stderr, " clientTARGETS [% 4d][%s]\n", clientTARGETS, NameForAtom(clientTARGETS));
+ fprintf(stderr, " clientTIMESTAMP [% 4d][%s]\n", clientTIMESTAMP, NameForAtom(clientTIMESTAMP));
fprintf(stderr, " clientTEXT [% 4d][%s]\n", clientTEXT, NameForAtom(clientTEXT));
fprintf(stderr, " clientCOMPOUND_TEXT [% 4d][%s]\n", clientCOMPOUND_TEXT, NameForAtom(clientCOMPOUND_TEXT));
fprintf(stderr, " clientUTF8_STRING [% 4d][%s]\n", clientUTF8_STRING, NameForAtom(clientUTF8_STRING));
+ fprintf(stderr, " clientCLIPBOARD [% 4d][%s]\n", clientCLIPBOARD, NameForAtom(clientCLIPBOARD));
fprintf(stderr, " clientCutProperty [% 4d][%s]\n", clientCutProperty, NameForAtom(clientCutProperty));
fprintf(stderr, " nxagentLastRequestedSelection [% 4d][%s]\n", nxagentLastRequestedSelection, NameForAtom(nxagentLastRequestedSelection));
@@ -406,7 +435,7 @@ Status SendSelectionNotifyEventToServer(XSelectionEvent *event_to_send)
}
#endif
- //NXFlushDisplay(nxagentDisplay, NXFlushLink);
+ NXFlushDisplay(nxagentDisplay, NXFlushLink);
return result;
}
@@ -472,6 +501,13 @@ Bool nxagentValidServerTargets(XlibAtom target)
#endif
return True;
}
+ else if (target == serverCOMPOUND_TEXT)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: valid target [COMPOUND_TEXT].\n", __func__);
+ #endif
+ return True;
+ }
else if (target == serverTARGETS)
{
#ifdef DEBUG
@@ -493,21 +529,36 @@ Bool nxagentValidServerTargets(XlibAtom target)
return False;
}
-void nxagentClearSelectionOwner(SelectionOwner *owner)
+void nxagentInitSelectionOwner(int index, Atom selection)
+{
+ lastSelectionOwner[index].selection = selection;
+ lastSelectionOwner[index].client = NullClient;
+ lastSelectionOwner[index].window = screenInfo.screens[0]->root->drawable.id;
+ lastSelectionOwner[index].windowPtr = NULL;
+ lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis();
+}
+
+/* there's no owner on nxagent side anymore */
+void nxagentClearSelectionOwner(int index)
{
- /* there's no owner on nxagent side anymore */
- owner->client = NULL;
- owner->window = None;
- owner->lastTimeChanged = GetTimeInMillis();
- /* FIXME: why is windowPtr not cleared in the function? */
+ lastSelectionOwner[index].client = NULL;
+ lastSelectionOwner[index].window = None;
+ lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis();
+ /* FIXME: why is windowPtr not cleared in the function? */
}
-void nxagentStoreSelectionOwner(SelectionOwner *owner, Selection *sel)
+void nxagentStoreSelectionOwner(int index, Selection *sel)
{
- owner->client = sel->client;
- owner->window = sel->window;
- owner->windowPtr = sel->pWin;
- owner->lastTimeChanged = GetTimeInMillis();
+ lastSelectionOwner[index].client = sel->client;
+ lastSelectionOwner[index].window = sel->window;
+ lastSelectionOwner[index].windowPtr = sel->pWin;
+ lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis();
+}
+
+Bool nxagentMatchSelectionOwner(int index, ClientPtr pClient, WindowPtr pWindow)
+{
+ return ((pClient && lastSelectionOwner[index].client == pClient) ||
+ (pWindow && lastSelectionOwner[index].windowPtr == pWindow));
}
void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
@@ -525,8 +576,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
for (int i = 0; i < nxagentMaxSelections; i++)
{
- if ((pClient != NULL && lastSelectionOwner[i].client == pClient) ||
- (pWindow != NULL && lastSelectionOwner[i].windowPtr == pWindow))
+ if (nxagentMatchSelectionOwner(i, pClient, pWindow))
{
#ifdef TEST
fprintf(stderr, "%s: Resetting state with client [%p] window [%p].\n", __func__,
@@ -534,7 +584,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
#endif
/* FIXME: why is windowPtr not cleared in the function? */
- nxagentClearSelectionOwner(&lastSelectionOwner[i]);
+ nxagentClearSelectionOwner(i);
lastSelectionOwner[i].windowPtr = NULL;
lastClientWindowPtr = NULL;
@@ -544,7 +594,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
}
}
- if (pWindow == lastClientWindowPtr)
+ if (pWindow && pWindow == lastClientWindowPtr)
{
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
@@ -553,22 +603,30 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
nxagentPrintClipboardStat("after nxagentClearClipboard");
}
+/*
+ * Find the index of the lastSelectionOwner with the selection
+ * sel. sel is an atom on the real X server.
+ */
int nxagentFindLastSelectionOwnerIndex(XlibAtom sel)
{
int i = 0;
- while ((i < nxagentMaxSelections) &&
- (lastSelectionOwner[i].selection != sel))
+ while (i < nxagentMaxSelections &&
+ lastSelectionOwner[i].selection != sel)
{
i++;
}
return i;
}
+/*
+ * Find the index of CurrentSelection with the selection
+ * sel. sel is an internal atom.
+ */
int nxagentFindCurrentSelectionIndex(Atom sel)
{
int i = 0;
- while ((i < NumCurrentSelections) &&
- (CurrentSelections[i].selection != sel))
+ while (i < NumCurrentSelections &&
+ CurrentSelections[i].selection != sel)
{
i++;
}
@@ -588,17 +646,26 @@ void nxagentClearSelection(XEvent *X)
nxagentPrintClipboardStat("before nxagentClearSelection");
- if (agentClipboardStatus != 1 ||
- nxagentOption(Clipboard) == ClipboardServer)
+ if (!agentClipboardInitialized)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
+ #endif
return;
}
- int i = nxagentFindLastSelectionOwnerIndex(X->xselectionclear.selection);
+ if (nxagentOption(Clipboard) == ClipboardServer)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard mode 'server' - doing nothing.\n", __func__);
+ #endif
+ return;
+ }
+ int i = nxagentFindLastSelectionOwnerIndex(X->xselectionclear.selection);
if (i < nxagentMaxSelections)
{
- if (lastSelectionOwner[i].client != NULL)
+ if (IS_INTERNAL_OWNER(i))
{
/* send a SelectionClear event to (our) previous owner */
xEvent x = {0};
@@ -618,7 +685,7 @@ void nxagentClearSelection(XEvent *X)
CurrentSelections[i].window = screenInfo.screens[0]->root->drawable.id;
CurrentSelections[i].client = NullClient;
- nxagentClearSelectionOwner(&lastSelectionOwner[i]);
+ nxagentClearSelectionOwner(i);
}
lastClientWindowPtr = NULL;
@@ -629,9 +696,8 @@ void nxagentClearSelection(XEvent *X)
/*
* Send a SelectionNotify event as reply to the RequestSelection
* event X. If success is True take the property from the event, else
- * take None (which reports "failed/denied" to the requestor.
+ * take None (which reports "failed/denied" to the requestor).
*/
-
void nxagentReplyRequestSelection(XEvent *X, Bool success)
{
XSelectionEvent eventSelection = {
@@ -651,8 +717,6 @@ void nxagentReplyRequestSelection(XEvent *X, Bool success)
}
SendSelectionNotifyEventToServer(&eventSelection);
-
- NXFlushDisplay(nxagentDisplay, NXFlushLink);
}
/*
@@ -687,56 +751,71 @@ void nxagentRequestSelection(XEvent *X)
nxagentPrintClipboardStat("before nxagentRequestSelection");
- if (agentClipboardStatus != 1)
+ if (!agentClipboardInitialized)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
+ #endif
return;
}
- /*
- * check if this request needs special treatment by checking
- * if any of the following is true:
- * - this is a special request like TARGETS or TIMESTAMP
- * - lastServerRequestor in non-NULL (= we are currenty in the transfer phase)
- * - the selection in this request is none we own.
- * In all cases we'll send back a SelectionNotify event with an
- * appropriate answer
- */
- if (!nxagentValidServerTargets(X->xselectionrequest.target) ||
- (lastServerRequestor != None) ||
- ((X->xselectionrequest.selection != lastSelectionOwner[nxagentPrimarySelection].selection) &&
- (X->xselectionrequest.selection != lastSelectionOwner[nxagentClipboardSelection].selection)))
+ /* lastServerRequestor in non-NULL (= we are currently in the transfer phase) */
+ if (lastServerRequestor != None)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: denying additional request during transfer phase.\n", __func__);
+ #endif
+
+ nxagentReplyRequestSelection(X, False);
+ return;
+ }
+
+ /* the selection in this request is none we own. */
+ {
+ int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
+ if (i == nxagentMaxSelections)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: not owning selection [%ld] - denying request.\n", __func__, X->xselectionrequest.selection);
+ #endif
+
+ nxagentReplyRequestSelection(X, False);
+ return;
+ }
+ }
+
+ /* this is a special request like TARGETS or TIMESTAMP */
+ if (!nxagentValidServerTargets(X->xselectionrequest.target))
{
if (X->xselectionrequest.target == serverTARGETS)
{
/*
* the selection request target is TARGETS. The requestor is
- * asking for a list of supported data formats. Currently
- * there's only one format we support: XA_STRING
+ * asking for a list of supported data formats.
*
* The selection does not matter here, we will return this for
* PRIMARY and CLIPBOARD.
*
- * FIXME: I am wondering if we should align this with
- * nxagentConvertSelection, where we report more formats.
+ * The list is aligned with the one in nxagentConvertSelection.
+ *
* FIXME: the perfect solution should not just answer with
* XA_STRING but ask the real owner what format it supports. The
* should then be sent to the original requestor.
- * FIXME: add serverCOMPOUND_TEXT?
*/
- long targets[] = {XA_STRING, serverUTF8_STRING, serverTEXT, serverTARGETS, serverTIMESTAMP};
+ long targets[] = {XA_STRING, serverUTF8_STRING, serverTEXT, serverCOMPOUND_TEXT, serverTARGETS, serverTIMESTAMP};
int numTargets = sizeof(targets) / sizeof(targets[0]);
#ifdef DEBUG
{
- fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets);
- for (int i = 0; i < numTargets; i++)
- {
- char *s = XGetAtomName(nxagentDisplay, targets[i]);
- fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], s);
- SAFE_XFree(s);
- }
- fprintf(stderr, "\n");
+ fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets);
+ for (int i = 0; i < numTargets; i++)
+ {
+ char *s = XGetAtomName(nxagentDisplay, targets[i]);
+ fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], s);
+ SAFE_XFree(s);
+ }
+ fprintf(stderr, "\n");
}
#endif
@@ -768,6 +847,7 @@ void nxagentRequestSelection(XEvent *X)
* used to obtain the selection.
*
* FIXME: ensure we are reporting an _external_ timestamp
+ * FIXME: for a 32 bit property list we need to pass a "long" array, not "char"!
*/
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
@@ -786,15 +866,21 @@ void nxagentRequestSelection(XEvent *X)
}
else
{
- /* deny the request */
+ /*
+ * unknown special request - probably bug! Check if this code handles all cases
+ * that are handled in nxagentValidServerTargets!
+ */
+ #ifdef DEBUG
+ fprintf(stderr, "%s: unknown special target [%ld] - denying request.\n", __func__, X->xselectionrequest.target);
+ #endif
nxagentReplyRequestSelection(X, False);
}
return;
}
/*
- * reaching this means the request is neither a special request nor
- * invalid. We can process it now.
+ * reaching this means the request is a normal, valid request. We
+ * can process it now.
*/
/*
@@ -806,15 +892,15 @@ void nxagentRequestSelection(XEvent *X)
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
if (i < nxagentMaxSelections)
{
- if ((lastClientWindowPtr != NULL) && (lastSelectionOwner[i].client != NULL))
+ if (lastClientWindowPtr != NULL && IS_INTERNAL_OWNER(i))
{
/*
* Request the real X server to transfer the selection content
- * to the NX_CUT_BUFFER_CLIENT property of the serverWindow.
+ * to the NX_CUT_BUFFER_SERVER property of the serverWindow.
* FIXME: document how we can end up here
*/
XConvertSelection(nxagentDisplay, CurrentSelections[i].selection,
- X->xselectionrequest.target, serverCutProperty,
+ X->xselectionrequest.target, serverTransToAgentProperty,
serverWindow, lastClientTime);
#ifdef DEBUG
@@ -826,14 +912,16 @@ void nxagentRequestSelection(XEvent *X)
/*
* if one of our clients owns the selection we ask it to copy
* the selection to the clientCutProperty on nxagent's root
- * window
+ * window in the first step. We then later push that property's
+ * content to the real X server.
*/
- if (lastSelectionOwner[i].client != NULL &&
- nxagentOption(Clipboard) != ClipboardClient)
+ if (IS_INTERNAL_OWNER(i) &&
+ (nxagentOption(Clipboard) == ClipboardServer ||
+ nxagentOption(Clipboard) == ClipboardBoth))
{
/*
* store who on the real X server requested the data and how
- * and where it wants to have it
+ * and where it wants to have it
*/
lastServerProperty = X->xselectionrequest.property;
lastServerRequestor = X->xselectionrequest.requestor;
@@ -871,16 +959,16 @@ void nxagentRequestSelection(XEvent *X)
#ifdef DEBUG
fprintf(stderr, "%s: sent SelectionRequest event to client [%d] property [%d][%s]" \
- "target [%d][%s] requestor [0x%x].\n", __func__,
- CLINDEX(lastSelectionOwner[i].client),
- x.u.selectionRequest.property, NameForAtom(x.u.selectionRequest.property),
- x.u.selectionRequest.target, NameForAtom(x.u.selectionRequest.target),
- x.u.selectionRequest.requestor);
+ "target [%d][%s] requestor [0x%x].\n", __func__,
+ CLINDEX(lastSelectionOwner[i].client),
+ x.u.selectionRequest.property, NameForAtom(x.u.selectionRequest.property),
+ x.u.selectionRequest.target, NameForAtom(x.u.selectionRequest.target),
+ x.u.selectionRequest.requestor);
#endif
}
else
{
- /* deny the request */
+ /* deny the request */
nxagentReplyRequestSelection(X, False);
}
}
@@ -908,10 +996,10 @@ static void endTransfer(Bool success)
#ifdef DEBUG
if (success == SELECTION_SUCCESS)
fprintf(stderr, "%s: sending notification to client [%d], property [%d][%s]\n", __func__,
- CLINDEX(lastClientClientPtr), lastClientProperty, NameForAtom(lastClientProperty));
+ CLINDEX(lastClientClientPtr), lastClientProperty, NameForAtom(lastClientProperty));
else
fprintf(stderr, "%s: sending negative notification to client [%d]\n", __func__,
- CLINDEX(lastClientClientPtr));
+ CLINDEX(lastClientClientPtr));
#endif
SendSelectionNotifyEventToClient(lastClientClientPtr,
@@ -949,10 +1037,10 @@ void nxagentTransferSelection(int resource)
int result;
PrintClientSelectionStage();
+
/*
- * Don't get data yet, just get size. We skip
- * this stage in current implementation and
- * go straight to the data.
+ * Don't get data yet, just get size. We skip this stage in
+ * current implementation and go straight to the data.
*/
nxagentLastClipboardClient = NXGetCollectPropertyResource(nxagentDisplay);
@@ -970,7 +1058,7 @@ void nxagentTransferSelection(int resource)
result = NXCollectProperty(nxagentDisplay,
nxagentLastClipboardClient,
serverWindow,
- serverCutProperty,
+ serverTransToAgentProperty,
0,
0,
False,
@@ -1024,7 +1112,7 @@ void nxagentTransferSelection(int resource)
result = NXCollectProperty(nxagentDisplay,
nxagentLastClipboardClient,
serverWindow,
- serverCutProperty,
+ serverTransToAgentProperty,
0,
lastClientPropertySize,
False,
@@ -1046,7 +1134,7 @@ void nxagentTransferSelection(int resource)
SetClientSelectionStage(WaitData);
/* we've seen situations where you had to move the mouse or press a
- key to let the transfer complete. Flushing here fixed it */
+ key to let the transfer complete. Flushing here fixed it */
NXFlushDisplay(nxagentDisplay, NXFlushLink);
break;
@@ -1206,8 +1294,11 @@ void nxagentCollectPropertyEvent(int resource)
*/
void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
{
- if (agentClipboardStatus != 1)
+ if (!agentClipboardInitialized)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
+ #endif
return;
}
@@ -1233,11 +1324,12 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
* We reach here after a paste inside the nxagent, triggered by
* the XConvertSelection call in nxagentConvertSelection(). This
* means that data we need has been transferred to the
- * serverCutProperty of the serverWindow (our window on the real X
- * server). We now need to transfer it to the original requestor,
- * which is stored in the lastClient* variables.
+ * serverTransToAgentProperty of the serverWindow (our window on
+ * the real X server). We now need to transfer it to the original
+ * requestor, which is stored in the lastClient* variables.
*/
- if ((lastClientStage == SelectionStageNone) && (X->xselection.property == serverCutProperty))
+ if (lastClientStage == SelectionStageNone &&
+ X->xselection.property == serverTransToAgentProperty)
{
#ifdef DEBUG
fprintf(stderr, "%s: Starting selection transferral for client [%d].\n", __func__,
@@ -1275,10 +1367,13 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
int i = nxagentFindLastSelectionOwnerIndex(X->xselection.selection);
if (i < nxagentMaxSelections)
{
- /* if the last owner was an internal one */
- if ((lastSelectionOwner[i].client != NULL) &&
- (lastSelectionOwner[i].windowPtr != NULL) &&
- (X->xselection.property == serverClientCutProperty))
+ /* if the last owner was an internal one, read the
+ * clientCutProperty and push the contents to the
+ * lastServerRequestor on the real X server.
+ */
+ if (IS_INTERNAL_OWNER(i) &&
+ lastSelectionOwner[i].windowPtr != NULL &&
+ X->xselection.property == serverTransFromAgentProperty)
{
Atom atomReturnType;
int resultFormat;
@@ -1293,7 +1388,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
#ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__,
- lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
+ lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
#endif
if (result == BadAlloc || result == BadAtom ||
result == BadWindow || result == BadValue)
@@ -1309,7 +1404,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
&pszReturnData);
#ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__,
- lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
+ lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
#endif
if (result == BadAlloc || result == BadAtom ||
@@ -1373,7 +1468,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
};
#ifdef DEBUG
fprintf(stderr, "%s: Sending SelectionNotify event to requestor [%p].\n", __func__,
- (void *)eventSelection.requestor);
+ (void *)eventSelection.requestor);
#endif
SendSelectionNotifyEventToServer(&eventSelection);
@@ -1418,7 +1513,7 @@ void nxagentResetSelectionOwner(void)
fprintf(stderr, "%s: Reset selection state for selection [%d].\n", __func__, i);
#endif
- nxagentClearSelectionOwner(&lastSelectionOwner[i]);
+ nxagentClearSelectionOwner(i);
lastSelectionOwner[i].windowPtr = NULL;
}
@@ -1474,10 +1569,10 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
fprintf(stderr, "%s: pCurSel->selection [%s]\n", __func__, NameForAtom(pCurSel->selection));
#endif
- if ((pCurSel->pWin != NULL) &&
- (nxagentOption(Clipboard) != ClipboardNone) &&
- ((pCurSel->selection == XA_PRIMARY) ||
- (pCurSel->selection == MakeAtom("CLIPBOARD", 9, 0))))
+ if (pCurSel->pWin != NULL &&
+ nxagentOption(Clipboard) != ClipboardNone && /* FIXME: shouldn't we also check for != ClipboardClient? */
+ (pCurSel->selection == XA_PRIMARY ||
+ pCurSel->selection == clientCLIPBOARD))
{
#ifdef DEBUG
fprintf(stderr, "%s: calling nxagentSetSelectionOwner\n", __func__);
@@ -1512,8 +1607,11 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
*/
void nxagentSetSelectionOwner(Selection *pSelection)
{
- if (agentClipboardStatus != 1)
+ if (!agentClipboardInitialized)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
+ #endif
return;
}
@@ -1534,44 +1632,35 @@ void nxagentSetSelectionOwner(Selection *pSelection)
}
#endif
- /*
- * Only for PRIMARY and CLIPBOARD selections.
- */
-
- for (int i = 0; i < nxagentMaxSelections; i++)
+ int i = nxagentFindCurrentSelectionIndex(pSelection->selection);
+ if (i < NumCurrentSelections)
{
- /* FIXME: using CurrentSelections with the index limited my MaxSelections looks wrong */
- if (pSelection->selection == CurrentSelections[i].selection)
- {
- #ifdef DEBUG
- fprintf(stderr, "%s: lastSelectionOwner.client [%p] index [%d] -> [%p] index [%d]\n", __func__,
- (void *)lastSelectionOwner[i].client,
- CLINDEX(lastSelectionOwner[i].client),
- (void *)pSelection->client,
- CLINDEX(pSelection->client));
- fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__,
- lastSelectionOwner[i].window, pSelection->window);
- fprintf(stderr, "%s: lastSelectionOwner.windowPtr [%p] -> [%p] [0x%x] (serverWindow: [0x%x])\n", __func__,
- (void *)lastSelectionOwner[i].windowPtr, (void *)pSelection->pWin,
- nxagentWindow(pSelection->pWin), serverWindow);
- fprintf(stderr, "%s: lastSelectionOwner.lastTimeChanged [%d]\n", __func__,
- lastSelectionOwner[i].lastTimeChanged);
- #endif
+ #ifdef DEBUG
+ fprintf(stderr, "%s: lastSelectionOwner.client [%p] index [%d] -> [%p] index [%d]\n", __func__,
+ (void *)lastSelectionOwner[i].client, CLINDEX(lastSelectionOwner[i].client),
+ (void *)pSelection->client, CLINDEX(pSelection->client));
+ fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__,
+ lastSelectionOwner[i].window, pSelection->window);
+ fprintf(stderr, "%s: lastSelectionOwner.windowPtr [%p] -> [%p] [0x%x] (serverWindow: [0x%x])\n", __func__,
+ (void *)lastSelectionOwner[i].windowPtr, (void *)pSelection->pWin,
+ nxagentWindow(pSelection->pWin), serverWindow);
+ fprintf(stderr, "%s: lastSelectionOwner.lastTimeChanged [%d]\n", __func__,
+ lastSelectionOwner[i].lastTimeChanged);
+ #endif
- /*
- * inform the real X server that our serverWindow is the
- * clipboard owner.
- */
- XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
+ /*
+ * inform the real X server that our serverWindow is the
+ * clipboard owner.
+ */
+ XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
- /*
- * The real owner window (inside nxagent) is stored in
- * lastSelectionOwner.window. lastSelectionOwner.windowPtr
- * points to the struct that contains all information about the
- * owner window.
- */
- nxagentStoreSelectionOwner(&lastSelectionOwner[i], pSelection);
- }
+ /*
+ * The real owner window (inside nxagent) is stored in
+ * lastSelectionOwner.window. lastSelectionOwner.windowPtr
+ * points to the struct that contains all information about the
+ * owner window.
+ */
+ nxagentStoreSelectionOwner(i, pSelection);
}
lastClientWindowPtr = NULL;
@@ -1582,7 +1671,7 @@ void nxagentSetSelectionOwner(Selection *pSelection)
/*
FIXME
- if (XGetSelectionOwner(nxagentDisplay,pSelection->selection)==serverWindow)
+ if (XGetSelectionOwner(nxagentDisplay,pSelection->selection) == serverWindow)
{
fprintf (stderr, "%s: SetSelectionOwner OK\n", __func__);
@@ -1628,31 +1717,44 @@ void nxagentNotifyConvertFailure(ClientPtr client, Window requestor,
int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
Window requestor, Atom property, Atom target, Time time)
{
- if (agentClipboardStatus != 1 ||
- nxagentOption(Clipboard) == ClipboardServer)
+ if (!agentClipboardInitialized)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
+ #endif
return 0;
}
- for (int i = 0; i < nxagentMaxSelections; i++)
+ if (nxagentOption(Clipboard) == ClipboardServer)
{
- if ((selection == CurrentSelections[i].selection) &&
- (lastSelectionOwner[i].client != NULL))
- {
- /*
- * There is a client owner on the agent side, let normal dix stuff happen.
- */
- return 0;
- }
+ #ifdef DEBUG
+ fprintf(stderr, "%s: clipboard mode 'server' - doing nothing.\n", __func__);
+ #endif
+ return 0;
+ }
+
+ int i = nxagentFindCurrentSelectionIndex(selection);
+ if (i < NumCurrentSelections && IS_INTERNAL_OWNER(i))
+ {
+ /*
+ * There is a client owner on the agent side, let normal dix stuff happen.
+ */
+ return 0;
}
+ /*
+ * if lastClientWindowPtr is set we are waiting for an answer from
+ * the real X server. If that answer takes more than 5 seconds we
+ * consider the conversion failed and tell our client about that.
+ * The new request that lead us here is then processed.
+ */
if (lastClientWindowPtr != NULL)
{
#ifdef TEST
fprintf(stderr, "%s: lastClientWindowPtr != NULL.\n", __func__);
#endif
- if ((GetTimeInMillis() - lastClientReqTime) > 5000)
+ if ((GetTimeInMillis() - lastClientReqTime) >= CONVERSION_TIMEOUT)
{
#ifdef DEBUG
fprintf(stderr, "%s: timeout expired on last request, "
@@ -1667,6 +1769,11 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
else
{
+ /*
+ * we got another convert request while already waiting for an
+ * answer from the real X server to a previous convert request,
+ * which we cannot handle (yet). So return an error.
+ */
#ifdef DEBUG
fprintf(stderr, "%s: got request "
"before timeout expired on last request, notifying failure to client\n", __func__);
@@ -1678,7 +1785,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
}
- #if defined(TEST) || defined(DEBUG)
+ #ifdef DEBUG
fprintf(stderr, "%s: client [%d] requests sel [%s] "
"on window [%x] prop [%d][%s] target [%d][%s].\n", __func__,
CLINDEX(client), validateString(NameForAtom(selection)), requestor,
@@ -1698,15 +1805,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
/*
* The selection request target is TARGETS. The requestor is asking
- * for a list of supported data formats. Currently there's 4 of them.
+ * for a list of supported data formats.
*
- * FIXME: I am wondering if we should align this with
- * nxagentRequestSelection, where we only report one format.
+ * The list is aligned with the one in nxagentRequestSelection.
*/
if (target == clientTARGETS)
{
- /* --- Order changed by dimbor (prevent sending COMPOUND_TEXT to client --- */
- Atom targets[] = {XA_STRING, clientUTF8_STRING, clientTEXT, clientCOMPOUND_TEXT};
+ Atom targets[] = {XA_STRING, clientUTF8_STRING, clientTEXT, clientCOMPOUND_TEXT, clientTARGETS, clientTIMESTAMP};
int numTargets = sizeof(targets) / sizeof(targets[0]);
#ifdef DEBUG
@@ -1740,7 +1845,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
* support conversion to TIMESTAMP, returning the timestamp they
* used to obtain the selection."
*/
- if (target == MakeAtom("TIMESTAMP", 9, 1))
+ if (target == clientTIMESTAMP)
{
int i = nxagentFindCurrentSelectionIndex(selection);
if (i < NumCurrentSelections)
@@ -1768,11 +1873,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
#ifdef DEBUG
- if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < 5000))
+ if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < ACCUM_TIME))
{
/*
* The same client made consecutive requests of clipboard content
* with less than 5 seconds time interval between them.
+ * FIXME: this does not take the selection into account, so a
+ * client requesting PRIMARY and CLIPBOARD would match here, too
*/
fprintf(stderr, "%s: Consecutives request from client [%p] selection [%u] "
@@ -1791,16 +1898,16 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
#endif
- if ((target == clientTEXT) ||
- (target == XA_STRING) ||
- (target == clientCOMPOUND_TEXT) ||
- (target == clientUTF8_STRING))
+ if (target == clientTEXT ||
+ target == XA_STRING ||
+ target == clientCOMPOUND_TEXT ||
+ target == clientUTF8_STRING)
{
lastClientWindowPtr = pWin;
SetClientSelectionStage(None);
/*
* store the original requestor, we need that later after
- * serverCutProperty contains the desired selection content
+ * serverTransToAgentProperty contains the desired selection content
*/
lastClientRequestor = requestor;
lastClientClientPtr = client;
@@ -1810,10 +1917,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
lastClientTarget = target;
/* if the last client request time is more than 5s ago update it. Why? */
- if ((GetTimeInMillis() - lastClientReqTime) > 5000)
+ if ((GetTimeInMillis() - lastClientReqTime) >= CONVERSION_TIMEOUT)
lastClientReqTime = GetTimeInMillis();
- if (selection == MakeAtom("CLIPBOARD", 9, 0))
+ if (selection == clientCLIPBOARD)
{
selection = lastSelectionOwner[nxagentClipboardSelection].selection;
}
@@ -1825,27 +1932,27 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
if (target == clientUTF8_STRING)
{
#ifdef DEBUG
- fprintf(stderr, "%s: Sending XConvertSelection with target [%d][UTF8_STRING], property [%d][NX_CUT_BUFFER_SERVER]\n", __func__,
- serverUTF8_STRING, serverCutProperty);
+ fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][%s]\n", __func__,
+ serverUTF8_STRING, szAgentUTF8_STRING, serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER");
#endif
- XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverCutProperty,
+ XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverTransToAgentProperty,
serverWindow, CurrentTime);
}
else
{
#ifdef DEBUG
- fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][NX_CUT_BUFFER_SERVER]\n", __func__,
- XA_STRING, validateString(NameForAtom(XA_STRING)), serverCutProperty);
+ fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][%s]\n", __func__,
+ XA_STRING, validateString(NameForAtom(XA_STRING)), serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER");
#endif
- XConvertSelection(nxagentDisplay, selection, XA_STRING, serverCutProperty,
+ XConvertSelection(nxagentDisplay, selection, XA_STRING, serverTransToAgentProperty,
serverWindow, CurrentTime);
}
/* FIXME: check returncode of XConvertSelection */
#ifdef DEBUG
- fprintf(stderr, "%s: Sent XConvertSelection with target=[%s], property [%s]\n", __func__,
+ fprintf(stderr, "%s: Sent XConvertSelection with target [%s], property [%s]\n", __func__,
validateString(NameForAtom(target)), validateString(NameForAtom(property)));
#endif
@@ -1854,6 +1961,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
else
{
/* deny request */
+ #ifdef DEBUG
+ fprintf(stderr, "%s: Unsupported target [%d][%s] - denying request\n", __func__, target,
+ validateString(NameForAtom(target)));
+ #endif
SendSelectionNotifyEventToClient(client, time, requestor, selection, target, None);
return 1;
@@ -1867,7 +1978,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
* trigger the dispatch loop in Events.c to run
* nxagentHandleSelectionNotifyFromXServer which in turn will take
* care of transferring the selection content from the owning client
- * to to a property of the server window.
+ * to a property of the server window.
*
* Returning 1 here means the client request will not be further
* handled by dix. Returning 0 means a SelectionNotify event being
@@ -1885,18 +1996,18 @@ int nxagentSendNotify(xEvent *event)
fprintf(stderr, "%s: Got called.\n", __func__);
#endif
- if (agentClipboardStatus != 1)
+ if (!agentClipboardInitialized)
{
#ifdef DEBUG
- fprintf(stderr, "%s: agentClipboardStatus != 1 - doing nothing.\n", __func__);
+ fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return 0;
}
#ifdef DEBUG
fprintf(stderr, "%s: property is [%d][%s].\n", __func__,
- event->u.selectionNotify.property,
- NameForAtom(event->u.selectionNotify.property));
+ event->u.selectionNotify.property,
+ NameForAtom(event->u.selectionNotify.property));
fprintf(stderr, "%s: requestor is [0x%x].\n", __func__, event->u.selectionNotify.requestor);
fprintf(stderr, "%s: lastServerRequestor is [0x%x].\n", __func__, lastServerRequestor);
#endif
@@ -1908,26 +2019,32 @@ int nxagentSendNotify(xEvent *event)
* which can be nxagents themselves). In that case we return 0 (tell
* dix to go on) and do nothing!
*/
- if (event->u.selectionNotify.property == clientCutProperty && lastServerRequestor != None)
+ if (event->u.selectionNotify.property != clientCutProperty || lastServerRequestor == None)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: sent nothing.\n", __func__);
+ #endif
+ return 0;
+ }
+ else
{
-
/*
* Setup selection notify event to real server.
*
* .property must be a server-side Atom. As this property is only
- * set on our serverWindow and normally there are no other
- * properties except serverCutProperty, the only thing we need to
- * ensure is that the internal Atom clientCutProperty must differ
- * from the server-side serverCutProperty Atom. The actual name is
- * not important. To be clean here we use a seperate
- * serverClientCutProperty.
+ * set on our serverWindow and normally there are few other
+ * properties except serverTransToAgentProperty, the only thing
+ * we need to ensure is that the internal Atom clientCutProperty
+ * differs from the server-side serverTransToAgentProperty
+ * Atom. The actual name is not important. To be clean here we use
+ * a separate serverTransFromAgentProperty.
*/
XSelectionEvent eventSelection = {
.requestor = serverWindow,
.selection = event->u.selectionNotify.selection,
.target = event->u.selectionNotify.target,
- .property = serverClientCutProperty,
+ .property = serverTransFromAgentProperty,
.time = CurrentTime,
};
@@ -1939,7 +2056,7 @@ int nxagentSendNotify(xEvent *event)
* X servers (defined in Xatom.h).
*/
- if (event->u.selectionNotify.selection == MakeAtom("CLIPBOARD", 9, 0))
+ if (event->u.selectionNotify.selection == clientCLIPBOARD)
{
eventSelection.selection = lastSelectionOwner[nxagentClipboardSelection].selection;
}
@@ -1958,10 +2075,10 @@ int nxagentSendNotify(xEvent *event)
{
eventSelection.target = serverTEXT;
}
- /*else if (event->u.selectionNotify.target == clientCOMPOUND_TEXT)
+ else if (event->u.selectionNotify.target == clientCOMPOUND_TEXT)
{
eventSelection.target = serverCOMPOUND_TEXT;
- }*/
+ }
else
{
eventSelection.target = XA_STRING;
@@ -1983,22 +2100,24 @@ int nxagentSendNotify(xEvent *event)
return 1;
}
- #ifdef DEBUG
- fprintf(stderr, "%s: sent nothing.\n", __func__);
- #endif
- return 0;
}
+/*
+ * This is called from NXproperty.c to determine if a client sets the
+ * property we are waiting for.
+ * FIXME: in addition we should check if the client is the one we expect
+ */
WindowPtr nxagentGetClipboardWindow(Atom property)
{
int i = nxagentFindLastSelectionOwnerIndex(nxagentLastRequestedSelection);
- if ((i < nxagentMaxSelections) && (property == clientCutProperty) &&
- (lastSelectionOwner[i].windowPtr != NULL))
+ if (i < nxagentMaxSelections &&
+ property == clientCutProperty &&
+ lastSelectionOwner[i].windowPtr != NULL)
{
#ifdef DEBUG
fprintf(stderr, "%s: Returning last [%d] selection owner window [%p] (0x%x).\n", __func__,
- lastSelectionOwner[i].selection,
- (void *)lastSelectionOwner[i].windowPtr, WINDOWID(lastSelectionOwner[i].windowPtr));
+ lastSelectionOwner[i].selection,
+ (void *)lastSelectionOwner[i].windowPtr, WINDOWID(lastSelectionOwner[i].windowPtr));
#endif
return lastSelectionOwner[i].windowPtr;
@@ -2009,75 +2128,74 @@ WindowPtr nxagentGetClipboardWindow(Atom property)
}
}
-void nxagentInitSelectionOwner(SelectionOwner *owner, Atom selection)
-{
- owner->selection = selection;
- owner->client = NullClient;
- owner->window = screenInfo.screens[0]->root->drawable.id;
- owner->windowPtr = NULL;
- owner->lastTimeChanged = GetTimeInMillis();
-}
-
-int nxagentInitClipboard(WindowPtr pWin)
+/*
+ * Initialize the clipboard
+ * Returns: True for success else False
+ */
+Bool nxagentInitClipboard(WindowPtr pWin)
{
- Window iWindow = nxagentWindow(pWin);
-
#ifdef DEBUG
fprintf(stderr, "%s: Got called.\n", __func__);
#endif
- SAFE_free(lastSelectionOwner);
-
- lastSelectionOwner = (SelectionOwner *) malloc(nxagentMaxSelections * sizeof(SelectionOwner));
-
- if (lastSelectionOwner == NULL)
- {
- FatalError("nxagentInitClipboard: Failed to allocate memory for the clipboard selections.\n");
- }
-
- serverTIMESTAMP = nxagentAtoms[11]; /* TIMESTAMP */
-
- nxagentInitSelectionOwner(&lastSelectionOwner[nxagentPrimarySelection], XA_PRIMARY);
- nxagentInitSelectionOwner(&lastSelectionOwner[nxagentClipboardSelection], nxagentAtoms[10]); /* CLIPBOARD */
-
#ifdef NXAGENT_TIMESTAMP
{
- extern unsigned long startTime;
-
- fprintf(stderr, "%s: Initializing start [%d] milliseconds.\n", __func__,
+ fprintf(stderr, "%s: Clipboard init starts at [%ld] ms.\n", __func__,
GetTimeInMillis() - startTime);
}
#endif
- agentClipboardStatus = 0;
- serverWindow = iWindow;
+ agentClipboardInitialized = False;
+ serverWindow = nxagentWindow(pWin);
- /*
- * Local property to hold pasted data.
- */
+ if (!nxagentReconnectTrap)
+ {
+ SAFE_free(lastSelectionOwner);
+
+ lastSelectionOwner = (SelectionOwner *) malloc(nxagentMaxSelections * sizeof(SelectionOwner));
+
+ if (lastSelectionOwner == NULL)
+ {
+ FatalError("nxagentInitClipboard: Failed to allocate memory for the clipboard selections.\n");
+ }
+ nxagentInitSelectionOwner(nxagentPrimarySelection, XA_PRIMARY);
+ nxagentInitSelectionOwner(nxagentClipboardSelection, nxagentAtoms[10]); /* CLIPBOARD */
+ }
+ else
+ {
+ /* the clipboard selection atom might have changed on a new X
+ server. Primary is constant. */
+ lastSelectionOwner[nxagentClipboardSelection].selection = nxagentAtoms[10]; /* CLIPBOARD */
+ }
- serverCutProperty = nxagentAtoms[5]; /* NX_CUT_BUFFER_SERVER */
serverTARGETS = nxagentAtoms[6]; /* TARGETS */
serverTEXT = nxagentAtoms[7]; /* TEXT */
+ serverCOMPOUND_TEXT = nxagentAtoms[16]; /* COMPOUND_TEXT */
serverUTF8_STRING = nxagentAtoms[12]; /* UTF8_STRING */
- /* see nxagentSendNotify for an explanation */
- serverClientCutProperty = nxagentAtoms[15]; /* NX_CUT_BUFFER_CLIENT */
+ serverTIMESTAMP = nxagentAtoms[11]; /* TIMESTAMP */
- if (serverCutProperty == None)
+ /*
+ * Server side properties to hold pasted data.
+ * see nxagentSendNotify for an explanation
+ */
+ serverTransFromAgentProperty = nxagentAtoms[15]; /* NX_SELTRANS_FROM_AGENT */
+ serverTransToAgentProperty = nxagentAtoms[5]; /* NX_CUT_BUFFER_SERVER */
+
+ if (serverTransToAgentProperty == None)
{
#ifdef PANIC
- fprintf(stderr, "%s: PANIC! Could not create NX_CUT_BUFFER_SERVER atom\n", __func__);
+ fprintf(stderr, "%s: PANIC! Could not create %s atom\n", __func__, "NX_CUT_BUFFER_SERVER");
#endif
- return -1;
+ return False;
}
#ifdef TEST
- fprintf(stderr, "%s: Setting owner of selection [%s][%d] on window 0x%x\n", __func__,
- "NX_CUT_BUFFER_SERVER", (int) serverCutProperty, iWindow);
+ fprintf(stderr, "%s: Setting owner of selection [%d][%s] on window 0x%x\n", __func__,
+ (int) serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER", serverWindow);
#endif
- XSetSelectionOwner(nxagentDisplay, serverCutProperty, iWindow, CurrentTime);
+ XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty, serverWindow, CurrentTime);
if (XQueryExtension(nxagentDisplay,
"XFIXES",
@@ -2095,7 +2213,7 @@ int nxagentInitClipboard(WindowPtr pWin)
for (int i = 0; i < nxagentMaxSelections; i++)
{
- XFixesSelectSelectionInput(nxagentDisplay, iWindow,
+ XFixesSelectSelectionInput(nxagentDisplay, serverWindow,
lastSelectionOwner[i].selection,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
@@ -2118,10 +2236,10 @@ int nxagentInitClipboard(WindowPtr pWin)
#ifdef TEST
fprintf(stderr, "%s: setting the ownership of %s to %lx"
" and registering for PropertyChangeMask events\n", __func__,
- validateString(XGetAtomName(nxagentDisplay, nxagentAtoms[10])), iWindow);
+ validateString(XGetAtomName(nxagentDisplay, nxagentAtoms[10])), serverWindow);
#endif
- XSetSelectionOwner(nxagentDisplay, nxagentAtoms[10], iWindow, CurrentTime);
+ XSetSelectionOwner(nxagentDisplay, nxagentAtoms[10], serverWindow, CurrentTime);
pWin -> eventMask |= PropertyChangeMask;
nxagentChangeWindowAttributes(pWin, CWEventMask);
}
@@ -2129,22 +2247,30 @@ int nxagentInitClipboard(WindowPtr pWin)
if (nxagentReconnectTrap)
{
- /*
- * Only for PRIMARY and CLIPBOARD selections.
- */
-
- for (int i = 0; i < nxagentMaxSelections; i++)
+ if (nxagentOption(Clipboard) == ClipboardServer ||
+ nxagentOption(Clipboard) == ClipboardBoth)
{
- if (lastSelectionOwner[i].client && lastSelectionOwner[i].window)
+ for (int i = 0; i < nxagentMaxSelections; i++)
{
- XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, iWindow, CurrentTime);
+ /*
+ * if we have a selection inform the (new) real Xserver and
+ * claim the ownership. Note that we report our serverWindow as
+ * owner, not the real window!
+ */
+ if (IS_INTERNAL_OWNER(i) && lastSelectionOwner[i].window)
+ {
+ XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
+ }
}
}
+ /* FIXME: Shouldn't we reset lastServer* and lastClient* here? */
}
else
{
- lastSelectionOwner[nxagentPrimarySelection].client = NULL;
- lastSelectionOwner[nxagentClipboardSelection].client = NULL;
+ for (int i = 0; i < nxagentMaxSelections; i++)
+ {
+ nxagentClearSelectionOwner(i);
+ }
lastServerRequestor = None;
@@ -2152,25 +2278,27 @@ int nxagentInitClipboard(WindowPtr pWin)
SetClientSelectionStage(None);
lastClientReqTime = GetTimeInMillis();
- clientCutProperty = MakeAtom(szAgentNX_CUT_BUFFER_CLIENT,
- strlen(szAgentNX_CUT_BUFFER_CLIENT), 1);
clientTARGETS = MakeAtom(szAgentTARGETS, strlen(szAgentTARGETS), True);
clientTEXT = MakeAtom(szAgentTEXT, strlen(szAgentTEXT), True);
clientCOMPOUND_TEXT = MakeAtom(szAgentCOMPOUND_TEXT, strlen(szAgentCOMPOUND_TEXT), True);
clientUTF8_STRING = MakeAtom(szAgentUTF8_STRING, strlen(szAgentUTF8_STRING), True);
+ clientTIMESTAMP = MakeAtom(szAgentTIMESTAMP, strlen(szAgentTIMESTAMP), True);
+ clientCLIPBOARD = MakeAtom(szAgentCLIPBOARD, strlen(szAgentCLIPBOARD), True);
+ clientCutProperty = MakeAtom(szAgentNX_CUT_BUFFER_CLIENT,
+ strlen(szAgentNX_CUT_BUFFER_CLIENT), True);
if (clientCutProperty == None)
{
#ifdef PANIC
fprintf(stderr, "%s: PANIC! "
- "Could not create NX_CUT_BUFFER_CLIENT atom.\n", __func__);
+ "Could not create %s atom.\n", __func__, szAgentNX_CUT_BUFFER_CLIENT);
#endif
- return -1;
+ return False;
}
}
- agentClipboardStatus = 1;
+ agentClipboardInitialized = True;
#ifdef DEBUG
fprintf(stderr, "%s: Clipboard initialization completed.\n", __func__);
@@ -2178,12 +2306,10 @@ int nxagentInitClipboard(WindowPtr pWin)
#ifdef NXAGENT_TIMESTAMP
{
- extern unsigned long startTime;
-
- fprintf(stderr, "%s: initializing ends [%d] milliseconds.\n", __func__,
+ fprintf(stderr, "%s: Clipboard init ends at [%ld] ms.\n", __func__,
GetTimeInMillis() - startTime);
}
#endif
- return 1;
+ return True;
}
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h
index c2e783cb9..a7d22ab97 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h
@@ -36,18 +36,17 @@ typedef struct _XFixesAgentInfo
int EventBase;
int ErrorBase;
int Initialized;
-
} XFixesAgentInfoRec;
extern XFixesAgentInfoRec nxagentXFixesInfo;
/*
- * Create the NX_CUT_BUFFER_CLIENT atom and
+ * Create the NX_SELTRANS_FROM_AGENT atom and
* initialize the required property to exchange
* data with the X server.
*/
-extern int nxagentInitClipboard(WindowPtr pWindow);
+extern Bool nxagentInitClipboard(WindowPtr pWindow);
/*
* Called whenever a client or a window is
diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c b/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c
index 9799d80d5..cc10ad760 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c
@@ -94,7 +94,7 @@ nxagentWMStateRec;
#undef DEBUG
#ifdef NXAGENT_CLIPBOARD
-extern WindowPtr nxagentGetClipboardWindow(Atom, WindowPtr);
+extern WindowPtr nxagentGetClipboardWindow(Atom);
#endif
#ifdef NXAGENT_ARTSD
@@ -135,7 +135,7 @@ ProcChangeProperty(ClientPtr client)
REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
#ifdef NXAGENT_CLIPBOARD
- pWin = nxagentGetClipboardWindow(stuff->property, NULL);
+ pWin = nxagentGetClipboardWindow(stuff->property);
if (pWin == NULL)
#endif
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h
index d791d2294..166508ac3 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Options.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h
@@ -49,6 +49,24 @@ typedef enum _BackingStoreMode
} BackingStoreMode;
+/* since nx 2.0.0-32 clipboard data exchange can be limited. Client
+ here means "nxclient":
+
+ Enable or disable copy and paste operations from the user's desktop
+ to the NX session or vice versa. This option can take four values:
+
+ client The content copied on the client can be pasted inside the
+ NX session.
+
+ server The content copied inside the NX session can be pasted
+ on the client.
+
+ both The copy & paste operations are allowed both between the
+ client and the NX session and viceversa.
+
+ none The copy&paste operations between the client and the NX
+ session are never allowed.
+*/
typedef enum _ClipboardMode
{
ClipboardBoth,
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Splash.c b/nx-X11/programs/Xserver/hw/nxagent/Splash.c
index 058269a73..323155299 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Splash.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Splash.c
@@ -412,10 +412,10 @@ void nxagentRemoveSplashWindow(void)
#ifdef TEST
fprintf(stderr, "%s: setting the ownership of %s (%d) on window 0x%lx\n", __func__
- "NX_CUT_BUFFER_SERVER", (int)serverCutProperty, nxagentWindow(screenInfo.screens[0]->root));
+ "NX_CUT_BUFFER_SERVER", (int)serverTransToAgentProperty, nxagentWindow(screenInfo.screens[0]->root));
#endif
- XSetSelectionOwner(nxagentDisplay, serverCutProperty,
+ XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty,
nxagentWindow(screenInfo.screens[0]->root), CurrentTime);
}
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Window.c b/nx-X11/programs/Xserver/hw/nxagent/Window.c
index aa8831055..40af9c60e 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Window.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Window.c
@@ -2602,7 +2602,7 @@ void nxagentMapDefaultWindows(void)
* to notify of the agent start.
*/
- XSetSelectionOwner(nxagentDisplay, serverCutProperty,
+ XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty,
nxagentDefaultWindows[i], CurrentTime);
}
@@ -2802,7 +2802,7 @@ Bool nxagentReconnectAllWindows(void *p0)
fprintf(stderr, "nxagentReconnectAllWindows: All windows reconfigured.\n");
#endif
- if (nxagentInitClipboard(screenInfo.screens[0]->root) == -1)
+ if (!nxagentInitClipboard(screenInfo.screens[0]->root))
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectAllWindows: WARNING! Couldn't initialize the clipboard.\n");
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Windows.h b/nx-X11/programs/Xserver/hw/nxagent/Windows.h
index c742577f5..aa4629b47 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Windows.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Windows.h
@@ -178,7 +178,7 @@ do\
WindowPtr nxagentWindowPtr(Window window);
#ifdef XlibAtom
-extern XlibAtom serverCutProperty;
+extern XlibAtom serverTransToAgentProperty;
#endif
/*