Unverified Commit e89fb895 authored by Mike Gabriel's avatar Mike Gabriel

Merge branch 'uli42-pr/more_clipboard_improvements' into 3.6.x

parents 057ce728 30fb45b2
...@@ -81,6 +81,9 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] = ...@@ -81,6 +81,9 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] =
"WM_NX_READY", /* 3 */ "WM_NX_READY", /* 3 */
"MCOPGLOBALS", /* 4 */ "MCOPGLOBALS", /* 4 */
"NX_CUT_BUFFER_SERVER", /* 5 */ "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 */ "TARGETS", /* 6 */
"TEXT", /* 7 */ "TEXT", /* 7 */
"NX_AGENT_SIGNATURE", /* 8 */ "NX_AGENT_SIGNATURE", /* 8 */
...@@ -90,7 +93,8 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] = ...@@ -90,7 +93,8 @@ static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] =
"UTF8_STRING", /* 12 */ "UTF8_STRING", /* 12 */
"_NET_WM_STATE", /* 13 */ "_NET_WM_STATE", /* 13 */
"_NET_WM_STATE_FULLSCREEN", /* 14 */ "_NET_WM_STATE_FULLSCREEN", /* 14 */
"NX_CUT_BUFFER_CLIENT", /* 15 */ "NX_SELTRANS_FROM_AGENT", /* 15 */
"COMPOUND_TEXT", /* 16 */
NULL, NULL,
NULL NULL
}; };
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "../../include/window.h" #include "../../include/window.h"
#include "screenint.h" #include "screenint.h"
#define NXAGENT_NUMBER_OF_ATOMS 17 #define NXAGENT_NUMBER_OF_ATOMS 18
extern Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS]; extern Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS];
......
...@@ -67,12 +67,12 @@ extern Selection *CurrentSelections; ...@@ -67,12 +67,12 @@ extern Selection *CurrentSelections;
int nxagentLastClipboardClient = -1; int nxagentLastClipboardClient = -1;
static int agentClipboardStatus; static int agentClipboardInitialized = False;
#ifdef DEBUG #ifdef DEBUG
static int clientAccum; static int clientAccum;
#endif #endif
XlibAtom serverCutProperty; XlibAtom serverTransToAgentProperty;
Atom clientCutProperty; Atom clientCutProperty;
static Window serverWindow; static Window serverWindow;
...@@ -98,6 +98,8 @@ typedef struct _SelectionOwner ...@@ -98,6 +98,8 @@ typedef struct _SelectionOwner
static SelectionOwner *lastSelectionOwner; static SelectionOwner *lastSelectionOwner;
static XlibAtom nxagentLastRequestedSelection; static XlibAtom nxagentLastRequestedSelection;
#define IS_INTERNAL_OWNER(lsoindex) (lastSelectionOwner[lsoindex].client != NULL)
/* /*
* Needed to handle the notify selection event to * Needed to handle the notify selection event to
* be sent to client once the selection property * be sent to client once the selection property
...@@ -133,18 +135,34 @@ static Time lastServerTime; ...@@ -133,18 +135,34 @@ static Time lastServerTime;
static XlibAtom serverTARGETS; static XlibAtom serverTARGETS;
static XlibAtom serverTIMESTAMP; static XlibAtom serverTIMESTAMP;
static XlibAtom serverTEXT; static XlibAtom serverTEXT;
static XlibAtom serverCOMPOUND_TEXT;
static XlibAtom serverUTF8_STRING; static XlibAtom serverUTF8_STRING;
static XlibAtom serverClientCutProperty; static XlibAtom serverTransFromAgentProperty;
static Atom clientTARGETS; static Atom clientTARGETS;
static Atom clientTIMESTAMP;
static Atom clientTEXT; static Atom clientTEXT;
static Atom clientCOMPOUND_TEXT; static Atom clientCOMPOUND_TEXT;
static Atom clientUTF8_STRING; static Atom clientUTF8_STRING;
static Atom clientCLIPBOARD;
static char szAgentTARGETS[] = "TARGETS"; static char szAgentTARGETS[] = "TARGETS";
static char szAgentTEXT[] = "TEXT"; static char szAgentTEXT[] = "TEXT";
static char szAgentTIMESTAMP[] = "TIMESTAMP";
static char szAgentCOMPOUND_TEXT[] = "COMPOUND_TEXT"; static char szAgentCOMPOUND_TEXT[] = "COMPOUND_TEXT";
static char szAgentUTF8_STRING[] = "UTF8_STRING"; static char szAgentUTF8_STRING[] = "UTF8_STRING";
static char szAgentNX_CUT_BUFFER_CLIENT[] = "NX_CUT_BUFFER_CLIENT"; 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 * some helpers for debugging output
...@@ -170,10 +188,12 @@ const char * GetClientSelectionStageString(int stage) ...@@ -170,10 +188,12 @@ const char * GetClientSelectionStageString(int stage)
#else #else
#define SetClientSelectionStage(stage) do {lastClientStage = SelectionStage##stage;} while (0) #define SetClientSelectionStage(stage) do {lastClientStage = SelectionStage##stage;} while (0)
#define PrintClientSelectionStage() #define PrintClientSelectionStage()
#endif
/* /*
* see also nx-X11/lib/src/ErrDes.c * 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) const char * GetXErrorString(int code)
{ {
...@@ -200,6 +220,7 @@ const char * GetXErrorString(int code) ...@@ -200,6 +220,7 @@ const char * GetXErrorString(int code)
default: return("UNKNOWN!"); break;; default: return("UNKNOWN!"); break;;
} }
} }
#endif
/* /*
* Save the values queried from X server. * Save the values queried from X server.
...@@ -223,6 +244,10 @@ int nxagentSendNotify(xEvent *event); ...@@ -223,6 +244,10 @@ int nxagentSendNotify(xEvent *event);
void nxagentPrintClipboardStat(char *); void nxagentPrintClipboardStat(char *);
#ifdef NXAGENT_TIMESTAMP
extern unsigned long startTime;
#endif
#ifdef DEBUG #ifdef DEBUG
void nxagentPrintSelectionStat(int sel) void nxagentPrintSelectionStat(int sel)
{ {
...@@ -280,19 +305,19 @@ void nxagentPrintSelectionStat(int sel) ...@@ -280,19 +305,19 @@ void nxagentPrintSelectionStat(int sel)
void nxagentPrintClipboardStat(char *header) void nxagentPrintClipboardStat(char *header)
{ {
#ifdef DEBUG #ifdef DEBUG
char *s =NULL; char *s = NULL;
fprintf(stderr, "/----- Clipboard internal status - %s -----\n", header); fprintf(stderr, "/----- Clipboard internal status - %s -----\n", header);
fprintf(stderr, " current time (Time) [%u]\n", GetTimeInMillis()); 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, " clientAccum (int) [%d]\n", clientAccum);
fprintf(stderr, " nxagentMaxSelections (int) [%d]\n", nxagentMaxSelections); fprintf(stderr, " nxagentMaxSelections (int) [%d]\n", nxagentMaxSelections);
fprintf(stderr, " NumCurrentSelections (int) [%d]\n", NumCurrentSelections); fprintf(stderr, " NumCurrentSelections (int) [%d]\n", NumCurrentSelections);
fprintf(stderr, " serverWindow (Window) [0x%x]\n", serverWindow); fprintf(stderr, " serverWindow (Window) [0x%x]\n", serverWindow);
fprintf(stderr, " nxagentLastClipboardClient (int) [%d]\n", nxagentLastClipboardClient); fprintf(stderr, " nxagentLastClipboardClient (int) [%d]\n", nxagentLastClipboardClient);
fprintf(stderr, " ClipboardMode "); fprintf(stderr, " Clipboard mode ");
switch(nxagentOption(Clipboard)) switch(nxagentOption(Clipboard))
{ {
case ClipboardBoth: fprintf(stderr, "[Both]"); break;; case ClipboardBoth: fprintf(stderr, "[Both]"); break;;
...@@ -301,7 +326,7 @@ void nxagentPrintClipboardStat(char *header) ...@@ -301,7 +326,7 @@ void nxagentPrintClipboardStat(char *header)
case ClipboardNone: fprintf(stderr, "[None]"); break;; case ClipboardNone: fprintf(stderr, "[None]"); break;;
default: fprintf(stderr, "[UNKNOWN] (FAIL!)"); break;; default: fprintf(stderr, "[UNKNOWN] (FAIL!)"); break;;
} }
fprintf(stderr,"\n"); fprintf(stderr, "\n");
fprintf(stderr, "lastServer\n"); fprintf(stderr, "lastServer\n");
fprintf(stderr, " lastServerRequestor (Window) [0x%x]\n", lastServerRequestor); fprintf(stderr, " lastServerRequestor (Window) [0x%x]\n", lastServerRequestor);
...@@ -336,21 +361,25 @@ void nxagentPrintClipboardStat(char *header) ...@@ -336,21 +361,25 @@ void nxagentPrintClipboardStat(char *header)
fprintf(stderr, " serverTARGETS [% 4d][%s]\n", serverTARGETS, validateString(s)); fprintf(stderr, " serverTARGETS [% 4d][%s]\n", serverTARGETS, validateString(s));
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTEXT); SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTEXT);
fprintf(stderr, " serverTEXT [% d][%s]\n", serverTEXT, s); 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); SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverUTF8_STRING);
fprintf(stderr, " serverUTF8_STRING [% 4d][%s]\n", serverUTF8_STRING, s); fprintf(stderr, " serverUTF8_STRING [% 4d][%s]\n", serverUTF8_STRING, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverCutProperty); SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTransToAgentProperty);
fprintf(stderr, " serverCutProperty [% 4d][%s]\n", serverCutProperty, s); fprintf(stderr, " serverTransToAgentProperty [% 4d][%s]\n", serverTransFromAgentProperty, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverClientCutProperty); SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTransFromAgentProperty);
fprintf(stderr, " serverClientCutProperty [% 4d][%s]\n", serverClientCutProperty, s); fprintf(stderr, " serverTransFromAgentProperty [% 4d][%s]\n", serverTransToAgentProperty, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTIMESTAMP); SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, serverTIMESTAMP);
fprintf(stderr, " serverTIMESTAMP [% 4d][%s]\n", serverTIMESTAMP, s); fprintf(stderr, " serverTIMESTAMP [% 4d][%s]\n", serverTIMESTAMP, s);
fprintf(stderr, "Atoms (inside nxagent)\n"); fprintf(stderr, "Atoms (inside nxagent)\n");
fprintf(stderr, " clientTARGETS [% 4d][%s]\n", clientTARGETS, NameForAtom(clientTARGETS)); 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, " clientTEXT [% 4d][%s]\n", clientTEXT, NameForAtom(clientTEXT));
fprintf(stderr, " clientCOMPOUND_TEXT [% 4d][%s]\n", clientCOMPOUND_TEXT, NameForAtom(clientCOMPOUND_TEXT)); 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, " 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, " clientCutProperty [% 4d][%s]\n", clientCutProperty, NameForAtom(clientCutProperty));
fprintf(stderr, " nxagentLastRequestedSelection [% 4d][%s]\n", nxagentLastRequestedSelection, NameForAtom(nxagentLastRequestedSelection)); fprintf(stderr, " nxagentLastRequestedSelection [% 4d][%s]\n", nxagentLastRequestedSelection, NameForAtom(nxagentLastRequestedSelection));
...@@ -406,7 +435,7 @@ Status SendSelectionNotifyEventToServer(XSelectionEvent *event_to_send) ...@@ -406,7 +435,7 @@ Status SendSelectionNotifyEventToServer(XSelectionEvent *event_to_send)
} }
#endif #endif
//NXFlushDisplay(nxagentDisplay, NXFlushLink); NXFlushDisplay(nxagentDisplay, NXFlushLink);
return result; return result;
} }
...@@ -472,6 +501,13 @@ Bool nxagentValidServerTargets(XlibAtom target) ...@@ -472,6 +501,13 @@ Bool nxagentValidServerTargets(XlibAtom target)
#endif #endif
return True; 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) else if (target == serverTARGETS)
{ {
#ifdef DEBUG #ifdef DEBUG
...@@ -493,21 +529,36 @@ Bool nxagentValidServerTargets(XlibAtom target) ...@@ -493,21 +529,36 @@ Bool nxagentValidServerTargets(XlibAtom target)
return False; 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 */ lastSelectionOwner[index].client = NULL;
owner->client = NULL; lastSelectionOwner[index].window = None;
owner->window = None; lastSelectionOwner[index].lastTimeChanged = GetTimeInMillis();
owner->lastTimeChanged = GetTimeInMillis(); /* FIXME: why is windowPtr not cleared in the function? */
/* 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; lastSelectionOwner[index].client = sel->client;
owner->window = sel->window; lastSelectionOwner[index].window = sel->window;
owner->windowPtr = sel->pWin; lastSelectionOwner[index].windowPtr = sel->pWin;
owner->lastTimeChanged = GetTimeInMillis(); 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) void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
...@@ -525,8 +576,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow) ...@@ -525,8 +576,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
for (int i = 0; i < nxagentMaxSelections; i++) for (int i = 0; i < nxagentMaxSelections; i++)
{ {
if ((pClient != NULL && lastSelectionOwner[i].client == pClient) || if (nxagentMatchSelectionOwner(i, pClient, pWindow))
(pWindow != NULL && lastSelectionOwner[i].windowPtr == pWindow))
{ {
#ifdef TEST #ifdef TEST
fprintf(stderr, "%s: Resetting state with client [%p] window [%p].\n", __func__, fprintf(stderr, "%s: Resetting state with client [%p] window [%p].\n", __func__,
...@@ -534,7 +584,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow) ...@@ -534,7 +584,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
#endif #endif
/* FIXME: why is windowPtr not cleared in the function? */ /* FIXME: why is windowPtr not cleared in the function? */
nxagentClearSelectionOwner(&lastSelectionOwner[i]); nxagentClearSelectionOwner(i);
lastSelectionOwner[i].windowPtr = NULL; lastSelectionOwner[i].windowPtr = NULL;
lastClientWindowPtr = NULL; lastClientWindowPtr = NULL;
...@@ -544,7 +594,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow) ...@@ -544,7 +594,7 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
} }
} }
if (pWindow == lastClientWindowPtr) if (pWindow && pWindow == lastClientWindowPtr)
{ {
lastClientWindowPtr = NULL; lastClientWindowPtr = NULL;
SetClientSelectionStage(None); SetClientSelectionStage(None);
...@@ -553,22 +603,30 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow) ...@@ -553,22 +603,30 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
nxagentPrintClipboardStat("after nxagentClearClipboard"); 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 nxagentFindLastSelectionOwnerIndex(XlibAtom sel)
{ {
int i = 0; int i = 0;
while ((i < nxagentMaxSelections) && while (i < nxagentMaxSelections &&
(lastSelectionOwner[i].selection != sel)) lastSelectionOwner[i].selection != sel)
{ {
i++; i++;
} }
return i; return i;
} }
/*
* Find the index of CurrentSelection with the selection
* sel. sel is an internal atom.
*/
int nxagentFindCurrentSelectionIndex(Atom sel) int nxagentFindCurrentSelectionIndex(Atom sel)
{ {
int i = 0; int i = 0;
while ((i < NumCurrentSelections) && while (i < NumCurrentSelections &&
(CurrentSelections[i].selection != sel)) CurrentSelections[i].selection != sel)
{ {
i++; i++;
} }
...@@ -588,17 +646,26 @@ void nxagentClearSelection(XEvent *X) ...@@ -588,17 +646,26 @@ void nxagentClearSelection(XEvent *X)
nxagentPrintClipboardStat("before nxagentClearSelection"); nxagentPrintClipboardStat("before nxagentClearSelection");
if (agentClipboardStatus != 1 || if (!agentClipboardInitialized)
nxagentOption(Clipboard) == ClipboardServer)
{ {
#ifdef DEBUG
fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return; 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 (i < nxagentMaxSelections)
{ {
if (lastSelectionOwner[i].client != NULL) if (IS_INTERNAL_OWNER(i))
{ {
/* send a SelectionClear event to (our) previous owner */ /* send a SelectionClear event to (our) previous owner */
xEvent x = {0}; xEvent x = {0};
...@@ -618,7 +685,7 @@ void nxagentClearSelection(XEvent *X) ...@@ -618,7 +685,7 @@ void nxagentClearSelection(XEvent *X)
CurrentSelections[i].window = screenInfo.screens[0]->root->drawable.id; CurrentSelections[i].window = screenInfo.screens[0]->root->drawable.id;
CurrentSelections[i].client = NullClient; CurrentSelections[i].client = NullClient;
nxagentClearSelectionOwner(&lastSelectionOwner[i]); nxagentClearSelectionOwner(i);
} }
lastClientWindowPtr = NULL; lastClientWindowPtr = NULL;
...@@ -629,9 +696,8 @@ void nxagentClearSelection(XEvent *X) ...@@ -629,9 +696,8 @@ void nxagentClearSelection(XEvent *X)
/* /*
* Send a SelectionNotify event as reply to the RequestSelection * Send a SelectionNotify event as reply to the RequestSelection
* event X. If success is True take the property from the event, else * 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) void nxagentReplyRequestSelection(XEvent *X, Bool success)
{ {
XSelectionEvent eventSelection = { XSelectionEvent eventSelection = {
...@@ -651,8 +717,6 @@ void nxagentReplyRequestSelection(XEvent *X, Bool success) ...@@ -651,8 +717,6 @@ void nxagentReplyRequestSelection(XEvent *X, Bool success)
} }
SendSelectionNotifyEventToServer(&eventSelection); SendSelectionNotifyEventToServer(&eventSelection);
NXFlushDisplay(nxagentDisplay, NXFlushLink);
} }
/* /*
...@@ -687,56 +751,71 @@ void nxagentRequestSelection(XEvent *X) ...@@ -687,56 +751,71 @@ void nxagentRequestSelection(XEvent *X)
nxagentPrintClipboardStat("before nxagentRequestSelection"); nxagentPrintClipboardStat("before nxagentRequestSelection");
if (agentClipboardStatus != 1) if (!agentClipboardInitialized)
{ {
#ifdef DEBUG
fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return; return;
} }
/* /* lastServerRequestor in non-NULL (= we are currently in the transfer phase) */
* check if this request needs special treatment by checking if (lastServerRequestor != None)
* if any of the following is true: {
* - this is a special request like TARGETS or TIMESTAMP #ifdef DEBUG
* - lastServerRequestor in non-NULL (= we are currenty in the transfer phase) fprintf(stderr, "%s: denying additional request during transfer phase.\n", __func__);
* - the selection in this request is none we own. #endif
* In all cases we'll send back a SelectionNotify event with an
* appropriate answer nxagentReplyRequestSelection(X, False);
*/ return;
if (!nxagentValidServerTargets(X->xselectionrequest.target) || }
(lastServerRequestor != None) ||
((X->xselectionrequest.selection != lastSelectionOwner[nxagentPrimarySelection].selection) && /* the selection in this request is none we own. */
(X->xselectionrequest.selection != lastSelectionOwner[nxagentClipboardSelection].selection))) {
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) if (X->xselectionrequest.target == serverTARGETS)
{ {
/* /*
* the selection request target is TARGETS. The requestor is * the selection request target is TARGETS. The requestor is
* asking for a list of supported data formats. Currently * asking for a list of supported data formats.
* there's only one format we support: XA_STRING
* *
* The selection does not matter here, we will return this for * The selection does not matter here, we will return this for
* PRIMARY and CLIPBOARD. * PRIMARY and CLIPBOARD.
* *
* FIXME: I am wondering if we should align this with * The list is aligned with the one in nxagentConvertSelection.
* nxagentConvertSelection, where we report more formats. *
* FIXME: the perfect solution should not just answer with * FIXME: the perfect solution should not just answer with
* XA_STRING but ask the real owner what format it supports. The * XA_STRING but ask the real owner what format it supports. The
* should then be sent to the original requestor. * 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]); int numTargets = sizeof(targets) / sizeof(targets[0]);
#ifdef DEBUG #ifdef DEBUG
{ {
fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets); fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets);
for (int i = 0; i < numTargets; i++) for (int i = 0; i < numTargets; i++)
{ {
char *s = XGetAtomName(nxagentDisplay, targets[i]); char *s = XGetAtomName(nxagentDisplay, targets[i]);
fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], s); fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], s);
SAFE_XFree(s); SAFE_XFree(s);
} }
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
#endif #endif
...@@ -768,6 +847,7 @@ void nxagentRequestSelection(XEvent *X) ...@@ -768,6 +847,7 @@ void nxagentRequestSelection(XEvent *X)
* used to obtain the selection. * used to obtain the selection.
* *
* FIXME: ensure we are reporting an _external_ timestamp * 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); int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
...@@ -786,15 +866,21 @@ void nxagentRequestSelection(XEvent *X) ...@@ -786,15 +866,21 @@ void nxagentRequestSelection(XEvent *X)
} }
else 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); nxagentReplyRequestSelection(X, False);
} }
return; return;
} }
/* /*
* reaching this means the request is neither a special request nor * reaching this means the request is a normal, valid request. We
* invalid. We can process it now. * can process it now.
*/ */
/* /*
...@@ -806,15 +892,15 @@ void nxagentRequestSelection(XEvent *X) ...@@ -806,15 +892,15 @@ void nxagentRequestSelection(XEvent *X)
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection); int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
if (i < nxagentMaxSelections) 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 * 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 * FIXME: document how we can end up here
*/ */
XConvertSelection(nxagentDisplay, CurrentSelections[i].selection, XConvertSelection(nxagentDisplay, CurrentSelections[i].selection,
X->xselectionrequest.target, serverCutProperty, X->xselectionrequest.target, serverTransToAgentProperty,
serverWindow, lastClientTime); serverWindow, lastClientTime);
#ifdef DEBUG #ifdef DEBUG
...@@ -826,14 +912,16 @@ void nxagentRequestSelection(XEvent *X) ...@@ -826,14 +912,16 @@ void nxagentRequestSelection(XEvent *X)
/* /*
* if one of our clients owns the selection we ask it to copy * if one of our clients owns the selection we ask it to copy
* the selection to the clientCutProperty on nxagent's root * 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 && if (IS_INTERNAL_OWNER(i) &&
nxagentOption(Clipboard) != ClipboardClient) (nxagentOption(Clipboard) == ClipboardServer ||
nxagentOption(Clipboard) == ClipboardBoth))
{ {
/* /*
* store who on the real X server requested the data and how * 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; lastServerProperty = X->xselectionrequest.property;
lastServerRequestor = X->xselectionrequest.requestor; lastServerRequestor = X->xselectionrequest.requestor;
...@@ -871,16 +959,16 @@ void nxagentRequestSelection(XEvent *X) ...@@ -871,16 +959,16 @@ void nxagentRequestSelection(XEvent *X)
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: sent SelectionRequest event to client [%d] property [%d][%s]" \ fprintf(stderr, "%s: sent SelectionRequest event to client [%d] property [%d][%s]" \
"target [%d][%s] requestor [0x%x].\n", __func__, "target [%d][%s] requestor [0x%x].\n", __func__,
CLINDEX(lastSelectionOwner[i].client), CLINDEX(lastSelectionOwner[i].client),
x.u.selectionRequest.property, NameForAtom(x.u.selectionRequest.property), x.u.selectionRequest.property, NameForAtom(x.u.selectionRequest.property),
x.u.selectionRequest.target, NameForAtom(x.u.selectionRequest.target), x.u.selectionRequest.target, NameForAtom(x.u.selectionRequest.target),
x.u.selectionRequest.requestor); x.u.selectionRequest.requestor);
#endif #endif
} }
else else
{ {
/* deny the request */ /* deny the request */
nxagentReplyRequestSelection(X, False); nxagentReplyRequestSelection(X, False);
} }
} }
...@@ -908,10 +996,10 @@ static void endTransfer(Bool success) ...@@ -908,10 +996,10 @@ static void endTransfer(Bool success)
#ifdef DEBUG #ifdef DEBUG
if (success == SELECTION_SUCCESS) if (success == SELECTION_SUCCESS)
fprintf(stderr, "%s: sending notification to client [%d], property [%d][%s]\n", __func__, fprintf(stderr, "%s: sending notification to client [%d], property [%d][%s]\n", __func__,
CLINDEX(lastClientClientPtr), lastClientProperty, NameForAtom(lastClientProperty)); CLINDEX(lastClientClientPtr), lastClientProperty, NameForAtom(lastClientProperty));
else else
fprintf(stderr, "%s: sending negative notification to client [%d]\n", __func__, fprintf(stderr, "%s: sending negative notification to client [%d]\n", __func__,
CLINDEX(lastClientClientPtr)); CLINDEX(lastClientClientPtr));
#endif #endif
SendSelectionNotifyEventToClient(lastClientClientPtr, SendSelectionNotifyEventToClient(lastClientClientPtr,
...@@ -949,10 +1037,10 @@ void nxagentTransferSelection(int resource) ...@@ -949,10 +1037,10 @@ void nxagentTransferSelection(int resource)
int result; int result;
PrintClientSelectionStage(); PrintClientSelectionStage();
/* /*
* Don't get data yet, just get size. We skip * Don't get data yet, just get size. We skip this stage in
* this stage in current implementation and * current implementation and go straight to the data.
* go straight to the data.
*/ */
nxagentLastClipboardClient = NXGetCollectPropertyResource(nxagentDisplay); nxagentLastClipboardClient = NXGetCollectPropertyResource(nxagentDisplay);
...@@ -970,7 +1058,7 @@ void nxagentTransferSelection(int resource) ...@@ -970,7 +1058,7 @@ void nxagentTransferSelection(int resource)
result = NXCollectProperty(nxagentDisplay, result = NXCollectProperty(nxagentDisplay,
nxagentLastClipboardClient, nxagentLastClipboardClient,
serverWindow, serverWindow,
serverCutProperty, serverTransToAgentProperty,
0, 0,
0, 0,
False, False,
...@@ -1024,7 +1112,7 @@ void nxagentTransferSelection(int resource) ...@@ -1024,7 +1112,7 @@ void nxagentTransferSelection(int resource)
result = NXCollectProperty(nxagentDisplay, result = NXCollectProperty(nxagentDisplay,
nxagentLastClipboardClient, nxagentLastClipboardClient,
serverWindow, serverWindow,
serverCutProperty, serverTransToAgentProperty,
0, 0,
lastClientPropertySize, lastClientPropertySize,
False, False,
...@@ -1046,7 +1134,7 @@ void nxagentTransferSelection(int resource) ...@@ -1046,7 +1134,7 @@ void nxagentTransferSelection(int resource)
SetClientSelectionStage(WaitData); SetClientSelectionStage(WaitData);
/* we've seen situations where you had to move the mouse or press a /* 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); NXFlushDisplay(nxagentDisplay, NXFlushLink);
break; break;
...@@ -1206,8 +1294,11 @@ void nxagentCollectPropertyEvent(int resource) ...@@ -1206,8 +1294,11 @@ void nxagentCollectPropertyEvent(int resource)
*/ */
void nxagentHandleSelectionNotifyFromXServer(XEvent *X) void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
{ {
if (agentClipboardStatus != 1) if (!agentClipboardInitialized)
{ {
#ifdef DEBUG
fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return; return;
} }
...@@ -1233,11 +1324,12 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) ...@@ -1233,11 +1324,12 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
* We reach here after a paste inside the nxagent, triggered by * We reach here after a paste inside the nxagent, triggered by
* the XConvertSelection call in nxagentConvertSelection(). This * the XConvertSelection call in nxagentConvertSelection(). This
* means that data we need has been transferred to the * means that data we need has been transferred to the
* serverCutProperty of the serverWindow (our window on the real X * serverTransToAgentProperty of the serverWindow (our window on
* server). We now need to transfer it to the original requestor, * the real X server). We now need to transfer it to the original
* which is stored in the lastClient* variables. * requestor, which is stored in the lastClient* variables.
*/ */
if ((lastClientStage == SelectionStageNone) && (X->xselection.property == serverCutProperty)) if (lastClientStage == SelectionStageNone &&
X->xselection.property == serverTransToAgentProperty)
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Starting selection transferral for client [%d].\n", __func__, fprintf(stderr, "%s: Starting selection transferral for client [%d].\n", __func__,
...@@ -1275,10 +1367,13 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) ...@@ -1275,10 +1367,13 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
int i = nxagentFindLastSelectionOwnerIndex(X->xselection.selection); int i = nxagentFindLastSelectionOwnerIndex(X->xselection.selection);
if (i < nxagentMaxSelections) if (i < nxagentMaxSelections)
{ {
/* if the last owner was an internal one */ /* if the last owner was an internal one, read the
if ((lastSelectionOwner[i].client != NULL) && * clientCutProperty and push the contents to the
(lastSelectionOwner[i].windowPtr != NULL) && * lastServerRequestor on the real X server.
(X->xselection.property == serverClientCutProperty)) */
if (IS_INTERNAL_OWNER(i) &&
lastSelectionOwner[i].windowPtr != NULL &&
X->xselection.property == serverTransFromAgentProperty)
{ {
Atom atomReturnType; Atom atomReturnType;
int resultFormat; int resultFormat;
...@@ -1293,7 +1388,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) ...@@ -1293,7 +1388,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__, 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 #endif
if (result == BadAlloc || result == BadAtom || if (result == BadAlloc || result == BadAtom ||
result == BadWindow || result == BadValue) result == BadWindow || result == BadValue)
...@@ -1309,7 +1404,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) ...@@ -1309,7 +1404,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
&pszReturnData); &pszReturnData);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__, 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 #endif
if (result == BadAlloc || result == BadAtom || if (result == BadAlloc || result == BadAtom ||
...@@ -1373,7 +1468,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X) ...@@ -1373,7 +1468,7 @@ void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
}; };
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Sending SelectionNotify event to requestor [%p].\n", __func__, fprintf(stderr, "%s: Sending SelectionNotify event to requestor [%p].\n", __func__,
(void *)eventSelection.requestor); (void *)eventSelection.requestor);
#endif #endif
SendSelectionNotifyEventToServer(&eventSelection); SendSelectionNotifyEventToServer(&eventSelection);
...@@ -1418,7 +1513,7 @@ void nxagentResetSelectionOwner(void) ...@@ -1418,7 +1513,7 @@ void nxagentResetSelectionOwner(void)
fprintf(stderr, "%s: Reset selection state for selection [%d].\n", __func__, i); fprintf(stderr, "%s: Reset selection state for selection [%d].\n", __func__, i);
#endif #endif
nxagentClearSelectionOwner(&lastSelectionOwner[i]); nxagentClearSelectionOwner(i);
lastSelectionOwner[i].windowPtr = NULL; lastSelectionOwner[i].windowPtr = NULL;
} }
...@@ -1474,10 +1569,10 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data, ...@@ -1474,10 +1569,10 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
fprintf(stderr, "%s: pCurSel->selection [%s]\n", __func__, NameForAtom(pCurSel->selection)); fprintf(stderr, "%s: pCurSel->selection [%s]\n", __func__, NameForAtom(pCurSel->selection));
#endif #endif
if ((pCurSel->pWin != NULL) && if (pCurSel->pWin != NULL &&
(nxagentOption(Clipboard) != ClipboardNone) && nxagentOption(Clipboard) != ClipboardNone && /* FIXME: shouldn't we also check for != ClipboardClient? */
((pCurSel->selection == XA_PRIMARY) || (pCurSel->selection == XA_PRIMARY ||
(pCurSel->selection == MakeAtom("CLIPBOARD", 9, 0)))) pCurSel->selection == clientCLIPBOARD))
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: calling nxagentSetSelectionOwner\n", __func__); fprintf(stderr, "%s: calling nxagentSetSelectionOwner\n", __func__);
...@@ -1512,8 +1607,11 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data, ...@@ -1512,8 +1607,11 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
*/ */
void nxagentSetSelectionOwner(Selection *pSelection) void nxagentSetSelectionOwner(Selection *pSelection)
{ {
if (agentClipboardStatus != 1) if (!agentClipboardInitialized)
{ {
#ifdef DEBUG
fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return; return;
} }
...@@ -1534,44 +1632,35 @@ void nxagentSetSelectionOwner(Selection *pSelection) ...@@ -1534,44 +1632,35 @@ void nxagentSetSelectionOwner(Selection *pSelection)
} }
#endif #endif
/* int i = nxagentFindCurrentSelectionIndex(pSelection->selection);
* Only for PRIMARY and CLIPBOARD selections. if (i < NumCurrentSelections)
*/
for (int i = 0; i < nxagentMaxSelections; i++)
{ {
/* FIXME: using CurrentSelections with the index limited my MaxSelections looks wrong */ #ifdef DEBUG
if (pSelection->selection == CurrentSelections[i].selection) fprintf(stderr, "%s: lastSelectionOwner.client [%p] index [%d] -> [%p] index [%d]\n", __func__,
{ (void *)lastSelectionOwner[i].client, CLINDEX(lastSelectionOwner[i].client),
#ifdef DEBUG (void *)pSelection->client, CLINDEX(pSelection->client));
fprintf(stderr, "%s: lastSelectionOwner.client [%p] index [%d] -> [%p] index [%d]\n", __func__, fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__,
(void *)lastSelectionOwner[i].client, lastSelectionOwner[i].window, pSelection->window);
CLINDEX(lastSelectionOwner[i].client), fprintf(stderr, "%s: lastSelectionOwner.windowPtr [%p] -> [%p] [0x%x] (serverWindow: [0x%x])\n", __func__,
(void *)pSelection->client, (void *)lastSelectionOwner[i].windowPtr, (void *)pSelection->pWin,
CLINDEX(pSelection->client)); nxagentWindow(pSelection->pWin), serverWindow);
fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__, fprintf(stderr, "%s: lastSelectionOwner.lastTimeChanged [%d]\n", __func__,
lastSelectionOwner[i].window, pSelection->window); lastSelectionOwner[i].lastTimeChanged);
fprintf(stderr, "%s: lastSelectionOwner.windowPtr [%p] -> [%p] [0x%x] (serverWindow: [0x%x])\n", __func__, #endif
(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 * inform the real X server that our serverWindow is the
* clipboard owner. * clipboard owner.
*/ */
XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime); XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
/* /*
* The real owner window (inside nxagent) is stored in * The real owner window (inside nxagent) is stored in
* lastSelectionOwner.window. lastSelectionOwner.windowPtr * lastSelectionOwner.window. lastSelectionOwner.windowPtr
* points to the struct that contains all information about the * points to the struct that contains all information about the
* owner window. * owner window.
*/ */
nxagentStoreSelectionOwner(&lastSelectionOwner[i], pSelection); nxagentStoreSelectionOwner(i, pSelection);
}
} }
lastClientWindowPtr = NULL; lastClientWindowPtr = NULL;
...@@ -1582,7 +1671,7 @@ void nxagentSetSelectionOwner(Selection *pSelection) ...@@ -1582,7 +1671,7 @@ void nxagentSetSelectionOwner(Selection *pSelection)
/* /*
FIXME FIXME
if (XGetSelectionOwner(nxagentDisplay,pSelection->selection)==serverWindow) if (XGetSelectionOwner(nxagentDisplay,pSelection->selection) == serverWindow)
{ {
fprintf (stderr, "%s: SetSelectionOwner OK\n", __func__); fprintf (stderr, "%s: SetSelectionOwner OK\n", __func__);
...@@ -1628,31 +1717,44 @@ void nxagentNotifyConvertFailure(ClientPtr client, Window requestor, ...@@ -1628,31 +1717,44 @@ void nxagentNotifyConvertFailure(ClientPtr client, Window requestor,
int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
Window requestor, Atom property, Atom target, Time time) Window requestor, Atom property, Atom target, Time time)
{ {
if (agentClipboardStatus != 1 || if (!agentClipboardInitialized)
nxagentOption(Clipboard) == ClipboardServer)
{ {
#ifdef DEBUG
fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif
return 0; return 0;
} }
for (int i = 0; i < nxagentMaxSelections; i++) if (nxagentOption(Clipboard) == ClipboardServer)
{ {
if ((selection == CurrentSelections[i].selection) && #ifdef DEBUG
(lastSelectionOwner[i].client != NULL)) fprintf(stderr, "%s: clipboard mode 'server' - doing nothing.\n", __func__);
{ #endif
/* return 0;
* There is a client owner on the agent side, let normal dix stuff happen. }
*/
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) if (lastClientWindowPtr != NULL)
{ {
#ifdef TEST #ifdef TEST
fprintf(stderr, "%s: lastClientWindowPtr != NULL.\n", __func__); fprintf(stderr, "%s: lastClientWindowPtr != NULL.\n", __func__);
#endif #endif
if ((GetTimeInMillis() - lastClientReqTime) > 5000) if ((GetTimeInMillis() - lastClientReqTime) >= CONVERSION_TIMEOUT)
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: timeout expired on last request, " fprintf(stderr, "%s: timeout expired on last request, "
...@@ -1667,6 +1769,11 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1667,6 +1769,11 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
} }
else 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 #ifdef DEBUG
fprintf(stderr, "%s: got request " fprintf(stderr, "%s: got request "
"before timeout expired on last request, notifying failure to client\n", __func__); "before timeout expired on last request, notifying failure to client\n", __func__);
...@@ -1678,7 +1785,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -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] " fprintf(stderr, "%s: client [%d] requests sel [%s] "
"on window [%x] prop [%d][%s] target [%d][%s].\n", __func__, "on window [%x] prop [%d][%s] target [%d][%s].\n", __func__,
CLINDEX(client), validateString(NameForAtom(selection)), requestor, CLINDEX(client), validateString(NameForAtom(selection)), requestor,
...@@ -1698,15 +1805,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1698,15 +1805,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
/* /*
* The selection request target is TARGETS. The requestor is asking * 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 * The list is aligned with the one in nxagentRequestSelection.
* nxagentRequestSelection, where we only report one format.
*/ */
if (target == clientTARGETS) if (target == clientTARGETS)
{ {
/* --- Order changed by dimbor (prevent sending COMPOUND_TEXT to client --- */ Atom targets[] = {XA_STRING, clientUTF8_STRING, clientTEXT, clientCOMPOUND_TEXT, clientTARGETS, clientTIMESTAMP};
Atom targets[] = {XA_STRING, clientUTF8_STRING, clientTEXT, clientCOMPOUND_TEXT};
int numTargets = sizeof(targets) / sizeof(targets[0]); int numTargets = sizeof(targets) / sizeof(targets[0]);
#ifdef DEBUG #ifdef DEBUG
...@@ -1740,7 +1845,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1740,7 +1845,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
* support conversion to TIMESTAMP, returning the timestamp they * support conversion to TIMESTAMP, returning the timestamp they
* used to obtain the selection." * used to obtain the selection."
*/ */
if (target == MakeAtom("TIMESTAMP", 9, 1)) if (target == clientTIMESTAMP)
{ {
int i = nxagentFindCurrentSelectionIndex(selection); int i = nxagentFindCurrentSelectionIndex(selection);
if (i < NumCurrentSelections) if (i < NumCurrentSelections)
...@@ -1768,11 +1873,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1768,11 +1873,13 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
} }
#ifdef DEBUG #ifdef DEBUG
if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < 5000)) if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < ACCUM_TIME))
{ {
/* /*
* The same client made consecutive requests of clipboard content * The same client made consecutive requests of clipboard content
* with less than 5 seconds time interval between them. * 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] " fprintf(stderr, "%s: Consecutives request from client [%p] selection [%u] "
...@@ -1791,16 +1898,16 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1791,16 +1898,16 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
} }
#endif #endif
if ((target == clientTEXT) || if (target == clientTEXT ||
(target == XA_STRING) || target == XA_STRING ||
(target == clientCOMPOUND_TEXT) || target == clientCOMPOUND_TEXT ||
(target == clientUTF8_STRING)) target == clientUTF8_STRING)
{ {
lastClientWindowPtr = pWin; lastClientWindowPtr = pWin;
SetClientSelectionStage(None); SetClientSelectionStage(None);
/* /*
* store the original requestor, we need that later after * store the original requestor, we need that later after
* serverCutProperty contains the desired selection content * serverTransToAgentProperty contains the desired selection content
*/ */
lastClientRequestor = requestor; lastClientRequestor = requestor;
lastClientClientPtr = client; lastClientClientPtr = client;
...@@ -1810,10 +1917,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1810,10 +1917,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
lastClientTarget = target; lastClientTarget = target;
/* if the last client request time is more than 5s ago update it. Why? */ /* 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(); lastClientReqTime = GetTimeInMillis();
if (selection == MakeAtom("CLIPBOARD", 9, 0)) if (selection == clientCLIPBOARD)
{ {
selection = lastSelectionOwner[nxagentClipboardSelection].selection; selection = lastSelectionOwner[nxagentClipboardSelection].selection;
} }
...@@ -1825,27 +1932,27 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1825,27 +1932,27 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
if (target == clientUTF8_STRING) if (target == clientUTF8_STRING)
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Sending XConvertSelection with target [%d][UTF8_STRING], property [%d][NX_CUT_BUFFER_SERVER]\n", __func__, fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][%s]\n", __func__,
serverUTF8_STRING, serverCutProperty); serverUTF8_STRING, szAgentUTF8_STRING, serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER");
#endif #endif
XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverCutProperty, XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverTransToAgentProperty,
serverWindow, CurrentTime); serverWindow, CurrentTime);
} }
else else
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][NX_CUT_BUFFER_SERVER]\n", __func__, fprintf(stderr, "%s: Sending XConvertSelection with target [%d][%s], property [%d][%s]\n", __func__,
XA_STRING, validateString(NameForAtom(XA_STRING)), serverCutProperty); XA_STRING, validateString(NameForAtom(XA_STRING)), serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER");
#endif #endif
XConvertSelection(nxagentDisplay, selection, XA_STRING, serverCutProperty, XConvertSelection(nxagentDisplay, selection, XA_STRING, serverTransToAgentProperty,
serverWindow, CurrentTime); serverWindow, CurrentTime);
} }
/* FIXME: check returncode of XConvertSelection */ /* FIXME: check returncode of XConvertSelection */
#ifdef DEBUG #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))); validateString(NameForAtom(target)), validateString(NameForAtom(property)));
#endif #endif
...@@ -1854,6 +1961,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1854,6 +1961,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
else else
{ {
/* deny request */ /* 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); SendSelectionNotifyEventToClient(client, time, requestor, selection, target, None);
return 1; return 1;
...@@ -1867,7 +1978,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, ...@@ -1867,7 +1978,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
* trigger the dispatch loop in Events.c to run * trigger the dispatch loop in Events.c to run
* nxagentHandleSelectionNotifyFromXServer which in turn will take * nxagentHandleSelectionNotifyFromXServer which in turn will take
* care of transferring the selection content from the owning client * 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 * Returning 1 here means the client request will not be further
* handled by dix. Returning 0 means a SelectionNotify event being * handled by dix. Returning 0 means a SelectionNotify event being
...@@ -1885,18 +1996,18 @@ int nxagentSendNotify(xEvent *event) ...@@ -1885,18 +1996,18 @@ int nxagentSendNotify(xEvent *event)
fprintf(stderr, "%s: Got called.\n", __func__); fprintf(stderr, "%s: Got called.\n", __func__);
#endif #endif
if (agentClipboardStatus != 1) if (!agentClipboardInitialized)
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: agentClipboardStatus != 1 - doing nothing.\n", __func__); fprintf(stderr, "%s: clipboard not initialized - doing nothing.\n", __func__);
#endif #endif
return 0; return 0;
} }
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: property is [%d][%s].\n", __func__, fprintf(stderr, "%s: property is [%d][%s].\n", __func__,
event->u.selectionNotify.property, event->u.selectionNotify.property,
NameForAtom(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: requestor is [0x%x].\n", __func__, event->u.selectionNotify.requestor);
fprintf(stderr, "%s: lastServerRequestor is [0x%x].\n", __func__, lastServerRequestor); fprintf(stderr, "%s: lastServerRequestor is [0x%x].\n", __func__, lastServerRequestor);
#endif #endif
...@@ -1908,26 +2019,32 @@ int nxagentSendNotify(xEvent *event) ...@@ -1908,26 +2019,32 @@ int nxagentSendNotify(xEvent *event)
* which can be nxagents themselves). In that case we return 0 (tell * which can be nxagents themselves). In that case we return 0 (tell
* dix to go on) and do nothing! * 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. * Setup selection notify event to real server.
* *
* .property must be a server-side Atom. As this property is only * .property must be a server-side Atom. As this property is only
* set on our serverWindow and normally there are no other * set on our serverWindow and normally there are few other
* properties except serverCutProperty, the only thing we need to * properties except serverTransToAgentProperty, the only thing
* ensure is that the internal Atom clientCutProperty must differ * we need to ensure is that the internal Atom clientCutProperty
* from the server-side serverCutProperty Atom. The actual name is * differs from the server-side serverTransToAgentProperty
* not important. To be clean here we use a seperate * Atom. The actual name is not important. To be clean here we use
* serverClientCutProperty. * a separate serverTransFromAgentProperty.
*/ */
XSelectionEvent eventSelection = { XSelectionEvent eventSelection = {
.requestor = serverWindow, .requestor = serverWindow,
.selection = event->u.selectionNotify.selection, .selection = event->u.selectionNotify.selection,
.target = event->u.selectionNotify.target, .target = event->u.selectionNotify.target,
.property = serverClientCutProperty, .property = serverTransFromAgentProperty,
.time = CurrentTime, .time = CurrentTime,
}; };
...@@ -1939,7 +2056,7 @@ int nxagentSendNotify(xEvent *event) ...@@ -1939,7 +2056,7 @@ int nxagentSendNotify(xEvent *event)
* X servers (defined in Xatom.h). * 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; eventSelection.selection = lastSelectionOwner[nxagentClipboardSelection].selection;
} }
...@@ -1958,10 +2075,10 @@ int nxagentSendNotify(xEvent *event) ...@@ -1958,10 +2075,10 @@ int nxagentSendNotify(xEvent *event)
{ {
eventSelection.target = serverTEXT; eventSelection.target = serverTEXT;
} }
/*else if (event->u.selectionNotify.target == clientCOMPOUND_TEXT) else if (event->u.selectionNotify.target == clientCOMPOUND_TEXT)
{ {
eventSelection.target = serverCOMPOUND_TEXT; eventSelection.target = serverCOMPOUND_TEXT;
}*/ }
else else
{ {
eventSelection.target = XA_STRING; eventSelection.target = XA_STRING;
...@@ -1983,22 +2100,24 @@ int nxagentSendNotify(xEvent *event) ...@@ -1983,22 +2100,24 @@ int nxagentSendNotify(xEvent *event)
return 1; 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) WindowPtr nxagentGetClipboardWindow(Atom property)
{ {
int i = nxagentFindLastSelectionOwnerIndex(nxagentLastRequestedSelection); int i = nxagentFindLastSelectionOwnerIndex(nxagentLastRequestedSelection);
if ((i < nxagentMaxSelections) && (property == clientCutProperty) && if (i < nxagentMaxSelections &&
(lastSelectionOwner[i].windowPtr != NULL)) property == clientCutProperty &&
lastSelectionOwner[i].windowPtr != NULL)
{ {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Returning last [%d] selection owner window [%p] (0x%x).\n", __func__, fprintf(stderr, "%s: Returning last [%d] selection owner window [%p] (0x%x).\n", __func__,
lastSelectionOwner[i].selection, lastSelectionOwner[i].selection,
(void *)lastSelectionOwner[i].windowPtr, WINDOWID(lastSelectionOwner[i].windowPtr)); (void *)lastSelectionOwner[i].windowPtr, WINDOWID(lastSelectionOwner[i].windowPtr));
#endif #endif
return lastSelectionOwner[i].windowPtr; return lastSelectionOwner[i].windowPtr;
...@@ -2009,75 +2128,74 @@ WindowPtr nxagentGetClipboardWindow(Atom property) ...@@ -2009,75 +2128,74 @@ WindowPtr nxagentGetClipboardWindow(Atom property)
} }
} }
void nxagentInitSelectionOwner(SelectionOwner *owner, Atom selection) /*
{ * Initialize the clipboard
owner->selection = selection; * Returns: True for success else False
owner->client = NullClient; */
owner->window = screenInfo.screens[0]->root->drawable.id; Bool nxagentInitClipboard(WindowPtr pWin)
owner->windowPtr = NULL;
owner->lastTimeChanged = GetTimeInMillis();
}
int nxagentInitClipboard(WindowPtr pWin)
{ {
Window iWindow = nxagentWindow(pWin);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Got called.\n", __func__); fprintf(stderr, "%s: Got called.\n", __func__);
#endif #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 #ifdef NXAGENT_TIMESTAMP
{ {
extern unsigned long startTime; fprintf(stderr, "%s: Clipboard init starts at [%ld] ms.\n", __func__,
fprintf(stderr, "%s: Initializing start [%d] milliseconds.\n", __func__,
GetTimeInMillis() - startTime); GetTimeInMillis() - startTime);
} }
#endif #endif
agentClipboardStatus = 0; agentClipboardInitialized = False;
serverWindow = iWindow; serverWindow = nxagentWindow(pWin);
/* if (!nxagentReconnectTrap)
* Local property to hold pasted data. {
*/ 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 */ serverTARGETS = nxagentAtoms[6]; /* TARGETS */
serverTEXT = nxagentAtoms[7]; /* TEXT */ serverTEXT = nxagentAtoms[7]; /* TEXT */
serverCOMPOUND_TEXT = nxagentAtoms[16]; /* COMPOUND_TEXT */
serverUTF8_STRING = nxagentAtoms[12]; /* UTF8_STRING */ serverUTF8_STRING = nxagentAtoms[12]; /* UTF8_STRING */
/* see nxagentSendNotify for an explanation */ serverTIMESTAMP = nxagentAtoms[11]; /* TIMESTAMP */
serverClientCutProperty = nxagentAtoms[15]; /* NX_CUT_BUFFER_CLIENT */
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 #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 #endif
return -1; return False;
} }
#ifdef TEST #ifdef TEST
fprintf(stderr, "%s: Setting owner of selection [%s][%d] on window 0x%x\n", __func__, fprintf(stderr, "%s: Setting owner of selection [%d][%s] on window 0x%x\n", __func__,
"NX_CUT_BUFFER_SERVER", (int) serverCutProperty, iWindow); (int) serverTransToAgentProperty, "NX_CUT_BUFFER_SERVER", serverWindow);
#endif #endif
XSetSelectionOwner(nxagentDisplay, serverCutProperty, iWindow, CurrentTime); XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty, serverWindow, CurrentTime);
if (XQueryExtension(nxagentDisplay, if (XQueryExtension(nxagentDisplay,
"XFIXES", "XFIXES",
...@@ -2095,7 +2213,7 @@ int nxagentInitClipboard(WindowPtr pWin) ...@@ -2095,7 +2213,7 @@ int nxagentInitClipboard(WindowPtr pWin)
for (int i = 0; i < nxagentMaxSelections; i++) for (int i = 0; i < nxagentMaxSelections; i++)
{ {
XFixesSelectSelectionInput(nxagentDisplay, iWindow, XFixesSelectSelectionInput(nxagentDisplay, serverWindow,
lastSelectionOwner[i].selection, lastSelectionOwner[i].selection,
XFixesSetSelectionOwnerNotifyMask | XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask | XFixesSelectionWindowDestroyNotifyMask |
...@@ -2118,10 +2236,10 @@ int nxagentInitClipboard(WindowPtr pWin) ...@@ -2118,10 +2236,10 @@ int nxagentInitClipboard(WindowPtr pWin)
#ifdef TEST #ifdef TEST
fprintf(stderr, "%s: setting the ownership of %s to %lx" fprintf(stderr, "%s: setting the ownership of %s to %lx"
" and registering for PropertyChangeMask events\n", __func__, " and registering for PropertyChangeMask events\n", __func__,
validateString(XGetAtomName(nxagentDisplay, nxagentAtoms[10])), iWindow); validateString(XGetAtomName(nxagentDisplay, nxagentAtoms[10])), serverWindow);
#endif #endif
XSetSelectionOwner(nxagentDisplay, nxagentAtoms[10], iWindow, CurrentTime); XSetSelectionOwner(nxagentDisplay, nxagentAtoms[10], serverWindow, CurrentTime);
pWin -> eventMask |= PropertyChangeMask; pWin -> eventMask |= PropertyChangeMask;
nxagentChangeWindowAttributes(pWin, CWEventMask); nxagentChangeWindowAttributes(pWin, CWEventMask);
} }
...@@ -2129,22 +2247,30 @@ int nxagentInitClipboard(WindowPtr pWin) ...@@ -2129,22 +2247,30 @@ int nxagentInitClipboard(WindowPtr pWin)
if (nxagentReconnectTrap) if (nxagentReconnectTrap)
{ {
/* if (nxagentOption(Clipboard) == ClipboardServer ||
* Only for PRIMARY and CLIPBOARD selections. nxagentOption(Clipboard) == ClipboardBoth)
*/
for (int i = 0; i < nxagentMaxSelections; i++)
{ {
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 else
{ {
lastSelectionOwner[nxagentPrimarySelection].client = NULL; for (int i = 0; i < nxagentMaxSelections; i++)
lastSelectionOwner[nxagentClipboardSelection].client = NULL; {
nxagentClearSelectionOwner(i);
}
lastServerRequestor = None; lastServerRequestor = None;
...@@ -2152,25 +2278,27 @@ int nxagentInitClipboard(WindowPtr pWin) ...@@ -2152,25 +2278,27 @@ int nxagentInitClipboard(WindowPtr pWin)
SetClientSelectionStage(None); SetClientSelectionStage(None);
lastClientReqTime = GetTimeInMillis(); lastClientReqTime = GetTimeInMillis();
clientCutProperty = MakeAtom(szAgentNX_CUT_BUFFER_CLIENT,
strlen(szAgentNX_CUT_BUFFER_CLIENT), 1);
clientTARGETS = MakeAtom(szAgentTARGETS, strlen(szAgentTARGETS), True); clientTARGETS = MakeAtom(szAgentTARGETS, strlen(szAgentTARGETS), True);
clientTEXT = MakeAtom(szAgentTEXT, strlen(szAgentTEXT), True); clientTEXT = MakeAtom(szAgentTEXT, strlen(szAgentTEXT), True);
clientCOMPOUND_TEXT = MakeAtom(szAgentCOMPOUND_TEXT, strlen(szAgentCOMPOUND_TEXT), True); clientCOMPOUND_TEXT = MakeAtom(szAgentCOMPOUND_TEXT, strlen(szAgentCOMPOUND_TEXT), True);
clientUTF8_STRING = MakeAtom(szAgentUTF8_STRING, strlen(szAgentUTF8_STRING), 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) if (clientCutProperty == None)
{ {
#ifdef PANIC #ifdef PANIC
fprintf(stderr, "%s: 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 #endif
return -1; return False;
} }
} }
agentClipboardStatus = 1; agentClipboardInitialized = True;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "%s: Clipboard initialization completed.\n", __func__); fprintf(stderr, "%s: Clipboard initialization completed.\n", __func__);
...@@ -2178,12 +2306,10 @@ int nxagentInitClipboard(WindowPtr pWin) ...@@ -2178,12 +2306,10 @@ int nxagentInitClipboard(WindowPtr pWin)
#ifdef NXAGENT_TIMESTAMP #ifdef NXAGENT_TIMESTAMP
{ {
extern unsigned long startTime; fprintf(stderr, "%s: Clipboard init ends at [%ld] ms.\n", __func__,
fprintf(stderr, "%s: initializing ends [%d] milliseconds.\n", __func__,
GetTimeInMillis() - startTime); GetTimeInMillis() - startTime);
} }
#endif #endif
return 1; return True;
} }
...@@ -36,18 +36,17 @@ typedef struct _XFixesAgentInfo ...@@ -36,18 +36,17 @@ typedef struct _XFixesAgentInfo
int EventBase; int EventBase;
int ErrorBase; int ErrorBase;
int Initialized; int Initialized;
} XFixesAgentInfoRec; } XFixesAgentInfoRec;
extern XFixesAgentInfoRec nxagentXFixesInfo; 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 * initialize the required property to exchange
* data with the X server. * data with the X server.
*/ */
extern int nxagentInitClipboard(WindowPtr pWindow); extern Bool nxagentInitClipboard(WindowPtr pWindow);
/* /*
* Called whenever a client or a window is * Called whenever a client or a window is
......
...@@ -94,7 +94,7 @@ nxagentWMStateRec; ...@@ -94,7 +94,7 @@ nxagentWMStateRec;
#undef DEBUG #undef DEBUG
#ifdef NXAGENT_CLIPBOARD #ifdef NXAGENT_CLIPBOARD
extern WindowPtr nxagentGetClipboardWindow(Atom, WindowPtr); extern WindowPtr nxagentGetClipboardWindow(Atom);
#endif #endif
#ifdef NXAGENT_ARTSD #ifdef NXAGENT_ARTSD
...@@ -135,7 +135,7 @@ ProcChangeProperty(ClientPtr client) ...@@ -135,7 +135,7 @@ ProcChangeProperty(ClientPtr client)
REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
#ifdef NXAGENT_CLIPBOARD #ifdef NXAGENT_CLIPBOARD
pWin = nxagentGetClipboardWindow(stuff->property, NULL); pWin = nxagentGetClipboardWindow(stuff->property);
if (pWin == NULL) if (pWin == NULL)
#endif #endif
......
...@@ -49,6 +49,24 @@ typedef enum _BackingStoreMode ...@@ -49,6 +49,24 @@ typedef enum _BackingStoreMode
} 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 typedef enum _ClipboardMode
{ {
ClipboardBoth, ClipboardBoth,
......
...@@ -412,10 +412,10 @@ void nxagentRemoveSplashWindow(void) ...@@ -412,10 +412,10 @@ void nxagentRemoveSplashWindow(void)
#ifdef TEST #ifdef TEST
fprintf(stderr, "%s: setting the ownership of %s (%d) on window 0x%lx\n", __func__ 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 #endif
XSetSelectionOwner(nxagentDisplay, serverCutProperty, XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty,
nxagentWindow(screenInfo.screens[0]->root), CurrentTime); nxagentWindow(screenInfo.screens[0]->root), CurrentTime);
} }
......
...@@ -2602,7 +2602,7 @@ void nxagentMapDefaultWindows(void) ...@@ -2602,7 +2602,7 @@ void nxagentMapDefaultWindows(void)
* to notify of the agent start. * to notify of the agent start.
*/ */
XSetSelectionOwner(nxagentDisplay, serverCutProperty, XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty,
nxagentDefaultWindows[i], CurrentTime); nxagentDefaultWindows[i], CurrentTime);
} }
...@@ -2802,7 +2802,7 @@ Bool nxagentReconnectAllWindows(void *p0) ...@@ -2802,7 +2802,7 @@ Bool nxagentReconnectAllWindows(void *p0)
fprintf(stderr, "nxagentReconnectAllWindows: All windows reconfigured.\n"); fprintf(stderr, "nxagentReconnectAllWindows: All windows reconfigured.\n");
#endif #endif
if (nxagentInitClipboard(screenInfo.screens[0]->root) == -1) if (!nxagentInitClipboard(screenInfo.screens[0]->root))
{ {
#ifdef WARNING #ifdef WARNING
fprintf(stderr, "nxagentReconnectAllWindows: WARNING! Couldn't initialize the clipboard.\n"); fprintf(stderr, "nxagentReconnectAllWindows: WARNING! Couldn't initialize the clipboard.\n");
......
...@@ -178,7 +178,7 @@ do\ ...@@ -178,7 +178,7 @@ do\
WindowPtr nxagentWindowPtr(Window window); WindowPtr nxagentWindowPtr(Window window);
#ifdef XlibAtom #ifdef XlibAtom
extern XlibAtom serverCutProperty; extern XlibAtom serverTransToAgentProperty;
#endif #endif
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment