Unverified Commit 5405447e authored by Mike Gabriel's avatar Mike Gabriel

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

parents 3a3a3373 72c02240
......@@ -90,6 +90,7 @@ 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 */
NULL,
NULL
};
......
......@@ -30,7 +30,7 @@
#include "../../include/window.h"
#include "screenint.h"
#define NXAGENT_NUMBER_OF_ATOMS 16
#define NXAGENT_NUMBER_OF_ATOMS 17
extern Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS];
......
......@@ -68,7 +68,9 @@ extern Selection *CurrentSelections;
int nxagentLastClipboardClient = -1;
static int agentClipboardStatus;
#ifdef DEBUG
static int clientAccum;
#endif
Atom serverCutProperty;
Atom clientCutProperty;
......@@ -80,18 +82,21 @@ const int nxagentMaxSelections = 2;
typedef struct _SelectionOwner
{
Atom selection;
ClientPtr client;
Window window;
WindowPtr windowPtr;
Time lastTimeChanged;
Atom selection; /* _external_ Atom */
ClientPtr client; /* internal client */
Window window; /* internal window id */
WindowPtr windowPtr; /* internal window struct */
Time lastTimeChanged; /* internal time */
} SelectionOwner;
/*
* this contains the last selection owner in nxagent. The
* lastTimeChanged is always an internal time. If .client is NULL the
* owner is outside nxagent. .selection will _always_ contain the
* external atom of the selection
*/
static SelectionOwner *lastSelectionOwner;
static Atom nxagentLastRequestedSelection;
static Atom nxagentClipboardAtom;
static Atom nxagentTimestampAtom;
/*
* Needed to handle the notify selection event to
......@@ -126,8 +131,10 @@ static Atom lastServerTarget;
static Time lastServerTime;
static Atom serverTARGETS;
static Atom serverTIMESTAMP;
static Atom serverTEXT;
static Atom serverUTF8_STRING;
static Atom serverClientCutProperty;
static Atom clientTARGETS;
static Atom clientTEXT;
static Atom clientCOMPOUND_TEXT;
......@@ -158,6 +165,8 @@ const char * GetClientSelectionStageString(int stage)
}
#define SetClientSelectionStage(stage) do {fprintf(stderr, "%s: Changing selection stage from [%s] to [%s]\n", __func__, GetClientSelectionStageString(lastClientStage), GetClientSelectionStageString(SelectionStage##stage)); lastClientStage = SelectionStage##stage;} while (0)
#define PrintClientSelectionStage() do {fprintf(stderr, "%s: Current selection stage [%s]\n", __func__, GetClientSelectionStageString(lastClientStage));} while (0)
#define WINDOWID(ptr) (ptr) ? (ptr->drawable.id) : 0
#define CLINDEX(clientptr) (clientptr) ? (clientptr->index) : -1
#else
#define SetClientSelectionStage(stage) do {lastClientStage = SelectionStage##stage;} while (0)
#define PrintClientSelectionStage()
......@@ -201,11 +210,13 @@ XFixesAgentInfoRec nxagentXFixesInfo = { -1, -1, -1, 0 };
extern Display *nxagentDisplay;
Bool nxagentValidServerTargets(Atom target);
void nxagentSendSelectionNotify(Atom property);
static void endTransfer(Bool success);
#define SELECTION_SUCCESS True
#define SELECTION_FAULT False
void nxagentTransferSelection(int resource);
void nxagentCollectPropertyEvent(int resource);
void nxagentResetSelectionOwner(void);
WindowPtr nxagentGetClipboardWindow(Atom property, WindowPtr pWin);
WindowPtr nxagentGetClipboardWindow(Atom property);
void nxagentNotifyConvertFailure(ClientPtr client, Window requestor,
Atom selection, Atom target, Time time);
int nxagentSendNotify(xEvent *event);
......@@ -222,16 +233,19 @@ void nxagentPrintSelectionStat(int sel)
#ifdef CLIENTIDS
fprintf(stderr, " lastSelectionOwner[].client [%p] index [%d] PID [%d] Cmd [%s]\n",
(void *)lOwner.client,
lOwner.client ? lOwner.client->index : -1,
CLINDEX(lOwner.client),
GetClientPid(lOwner.client),
GetClientCmdName(lOwner.client));
#else
fprintf(stderr, " lastSelectionOwner[].client [%p] index [%d]\n",
(void *)lOwner.client,
lOwner.client ? lOwner.client->index : -1);
CLINDEX(lOwner.client));
#endif
fprintf(stderr, " lastSelectionOwner[].window [0x%x]\n", lOwner.window);
fprintf(stderr, " lastSelectionOwner[].windowPtr [%p]\n", (void *)lOwner.windowPtr);
if (lOwner.windowPtr)
fprintf(stderr, " lastSelectionOwner[].windowPtr [%p] ([0x%x]\n", (void *)lOwner.windowPtr, WINDOWID(lOwner.windowPtr));
else
fprintf(stderr, " lastSelectionOwner[].windowPtr -\n");
fprintf(stderr, " lastSelectionOwner[].lastTimeChanged [%u]\n", lOwner.lastTimeChanged);
/*
......@@ -250,13 +264,13 @@ void nxagentPrintSelectionStat(int sel)
#ifdef CLIENTIDS
fprintf(stderr, " CurrentSelections[].client [%p] index [%d] PID [%d] Cmd [%s]\n",
(void *)curSel.client,
curSel.client ? curSel.client->index : -1,
CLINDEX(curSel.client),
GetClientPid(curSel.client),
GetClientCmdName(curSel.client));
#else
fprintf(stderr, " CurrentSelections[].client [%p] index [%d]\n",
(void *)curSel.client,
curSel.client ? curSel.client->index : -1);
CLINDEX(curSel.client);
#endif
fprintf(stderr, " CurrentSelections[].window [0x%x]\n", curSel.window);
return;
......@@ -298,7 +312,10 @@ void nxagentPrintClipboardStat(char *header)
fprintf(stderr, " lastServerTime (Time) [%u]\n", lastServerTime);
fprintf(stderr, "lastClient\n");
fprintf(stderr, " lastClientWindowPtr (WindowPtr) [%p]\n", (void *)lastClientWindowPtr);
if (lastClientWindowPtr)
fprintf(stderr, " lastClientWindowPtr (WindowPtr) [%p] ([0x%x])\n", (void *)lastClientWindowPtr, WINDOWID(lastClientWindowPtr));
else
fprintf(stderr, " lastClientWindowPtr (WindowPtr) -\n");
fprintf(stderr, " lastClientClientPtr (ClientPtr) [%p]\n", (void *)lastClientClientPtr);
fprintf(stderr, " lastClientRequestor (Window) [0x%x]\n", lastClientRequestor);
fprintf(stderr, " lastClientProperty (Atom) [% 4d][%s]\n", lastClientProperty, NameForAtom(lastClientProperty));
......@@ -323,11 +340,11 @@ void nxagentPrintClipboardStat(char *header)
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, nxagentClipboardAtom);
fprintf(stderr, " nxagentClipboardAtom [% 4d][%s]\n", nxagentClipboardAtom, s);
SAFE_XFree(s); s = XGetAtomName(nxagentDisplay, nxagentTimestampAtom);
fprintf(stderr, " nxagentTimestampAtom [% 4d][%s]\n", nxagentTimestampAtom, 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));
......@@ -352,6 +369,85 @@ int GetWindowProperty(WindowPtr pWin, Atom property, long longOffset, long longL
unsigned long *nItems, unsigned long *bytesAfter,
unsigned char **propData);
/*
* Send a SelectionNotify event to the real X server and do some error
* handling (in DEBUG mode)
*/
Status SendSelectionNotifyEventToServer(XSelectionEvent *event_to_send)
{
Window w = event_to_send->requestor;
event_to_send->type = SelectionNotify;
event_to_send->send_event = True;
event_to_send->display = nxagentDisplay;
Status result = XSendEvent(nxagentDisplay, w, False, 0L, (XEvent *)event_to_send);
#ifdef DEBUG
/*
* man XSendEvent: XSendEvent returns zero if the conversion to wire
* protocol format failed and returns nonzero otherwise. XSendEvent
* can generate BadValue and BadWindow errors.
*/
if (result == 0)
{
fprintf(stderr, "%s: XSendEvent to [0x%x] failed.\n", __func__, w);
}
else
{
if (result == BadValue || result == BadWindow)
{
fprintf(stderr, "%s: WARNING! XSendEvent to [0x%x] failed: %s\n", __func__, w, GetXErrorString(result));
}
else
{
fprintf(stderr, "%s: XSendEvent() successfully sent to [0x%x]\n", __func__, w);
}
}
#endif
//NXFlushDisplay(nxagentDisplay, NXFlushLink);
return result;
}
int SendEventToClient(ClientPtr client, xEvent *pEvents)
{
return TryClientEvents (client, pEvents, 1, NoEventMask, NoEventMask, NullGrab);
}
int SendSelectionNotifyEventToClient(ClientPtr client,
Time time,
Window requestor,
Atom selection,
Atom target,
Atom property)
{
xEvent x = {0};
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = time;
x.u.selectionNotify.requestor = requestor;
x.u.selectionNotify.selection = selection;
x.u.selectionNotify.target = target;
x.u.selectionNotify.property = property;
#ifdef DEBUG
if (property == None)
fprintf (stderr, "%s: Denying request to client [%d].\n", __func__,
CLINDEX(client));
else
fprintf (stderr, "%s: Sending event to client [%d].\n", __func__,
CLINDEX(client));
#endif
return SendEventToClient(client, &x);
}
/*
* Check if target is a valid content type target sent by the real X
* server, like .e.g XA_STRING or UTF8_STRING. Other, non content type
* targets like "TARGETS" or "TIMESTAMP" will return false.
*/
Bool nxagentValidServerTargets(Atom target)
{
if (target == XA_STRING)
......@@ -383,6 +479,13 @@ Bool nxagentValidServerTargets(Atom target)
#endif
return False;
}
else if (target == serverTIMESTAMP)
{
#ifdef DEBUG
fprintf(stderr, "%s: special target [TIMESTAMP].\n", __func__);
#endif
return False;
}
#ifdef DEBUG
fprintf(stderr, "%s: invalid target [%u].\n", __func__, target);
......@@ -390,11 +493,28 @@ Bool nxagentValidServerTargets(Atom target)
return False;
}
void nxagentClearSelectionOwner(SelectionOwner *owner)
{
/* 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? */
}
void nxagentStoreSelectionOwner(SelectionOwner *owner, Selection *sel)
{
owner->client = sel->client;
owner->window = sel->window;
owner->windowPtr = sel->pWin;
owner->lastTimeChanged = GetTimeInMillis();
}
void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
{
#ifdef DEBUG
fprintf(stderr, "%s: Called with client [%p] window [%p].\n", __func__,
(void *) pClient, (void *) pWindow);
fprintf(stderr, "%s: Called with client [%p] index [%d] window [%p] ([0x%x]).\n", __func__,
(void *) pClient, CLINDEX(pClient), (void *) pWindow, WINDOWID(pWindow));
#endif
nxagentPrintClipboardStat("before nxagentClearClipboard");
......@@ -413,10 +533,9 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
(void *) pClient, (void *) pWindow);
#endif
lastSelectionOwner[i].client = NULL;
lastSelectionOwner[i].window = None;
/* FIXME: why is windowPtr not cleared in the function? */
nxagentClearSelectionOwner(&lastSelectionOwner[i]);
lastSelectionOwner[i].windowPtr = NULL;
lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis();
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
......@@ -434,10 +553,35 @@ void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow)
nxagentPrintClipboardStat("after nxagentClearClipboard");
}
void nxagentClearSelection(XEvent *X)
int nxagentFindLastSelectionOwnerIndex(Atom sel)
{
int i = 0;
while ((i < nxagentMaxSelections) &&
(lastSelectionOwner[i].selection != sel))
{
i++;
}
return i;
}
int nxagentFindCurrentSelectionIndex(Atom sel)
{
int i = 0;
while ((i < NumCurrentSelections) &&
(CurrentSelections[i].selection != sel))
{
i++;
}
return i;
}
/*
* This is called from Events.c dispatch loop on reception of a
* SelectionClear event. We receive this event if someone on the real
* X server claims the selection ownership.
*/
void nxagentClearSelection(XEvent *X)
{
#ifdef DEBUG
fprintf(stderr, "%s: SelectionClear event for selection [%lu].\n", __func__, X->xselectionclear.selection);
#endif
......@@ -450,34 +594,31 @@ void nxagentClearSelection(XEvent *X)
return;
}
while ((i < nxagentMaxSelections) &&
(lastSelectionOwner[i].selection != X->xselectionclear.selection))
{
i++;
}
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionclear.selection);
if (i < nxagentMaxSelections)
{
if (lastSelectionOwner[i].client != NULL)
{
xEvent x;
memset(&x, 0, sizeof(xEvent));
/* send a SelectionClear event to (our) previous owner */
xEvent x = {0};
x.u.u.type = SelectionClear;
x.u.selectionClear.time = GetTimeInMillis();
x.u.selectionClear.window = lastSelectionOwner[i].window;
x.u.selectionClear.atom = CurrentSelections[i].selection;
(void) TryClientEvents(lastSelectionOwner[i].client, &x, 1,
NoEventMask, NoEventMask,
NullGrab);
SendEventToClient(lastSelectionOwner[i].client, &x);
}
/*
* set the root window with the NullClient as selection owner. Our
* clients asking for the owner via XGetSelectionOwner() will get
* these for an answer
*/
CurrentSelections[i].window = screenInfo.screens[0]->root->drawable.id;
CurrentSelections[i].client = NullClient;
lastSelectionOwner[i].client = NULL;
lastSelectionOwner[i].window = None;
lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis();
nxagentClearSelectionOwner(&lastSelectionOwner[i]);
}
lastClientWindowPtr = NULL;
......@@ -485,13 +626,63 @@ void nxagentClearSelection(XEvent *X)
nxagentPrintClipboardStat("after nxagentClearSelection");
}
void nxagentRequestSelection(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.
*/
void nxagentReplyRequestSelection(XEvent *X, Bool success)
{
int i = 0;
XSelectionEvent eventSelection = {0};
XSelectionEvent eventSelection = {
.requestor = X->xselectionrequest.requestor,
.selection = X->xselectionrequest.selection,
.target = X->xselectionrequest.target,
.time = X->xselectionrequest.time,
.property = X->xselectionrequest.property
};
if (!success)
{
#ifdef DEBUG
fprintf(stderr, "%s: Got called.\n", __func__);
fprintf(stderr, "%s: denying request\n", __func__);
#endif
eventSelection.property = None;
}
SendSelectionNotifyEventToServer(&eventSelection);
NXFlushDisplay(nxagentDisplay, NXFlushLink);
}
/*
* This is called from Events.c dispatch loop on reception of a
* SelectionRequest event, meaning a client of the real X server wants
* to have the selection content. The real X server knows the nxagent
* as selection owner. But in reality one of our windows is the owner,
* so we must pass the request on to the real owner.
*/
void nxagentRequestSelection(XEvent *X)
{
#ifdef DEBUG
{
char *strTarget = XGetAtomName(nxagentDisplay, X->xselectionrequest.target);
char *strSelection = XGetAtomName(nxagentDisplay, X->xselectionrequest.selection);
char *strProperty = XGetAtomName(nxagentDisplay, X->xselectionrequest.property);
fprintf(stderr, "%s: Received SelectionRequest from real server: selection [%ld][%s] " \
"target [%ld][%s] requestor [%s/0x%lx] destination [%ld][%s] lastServerRequestor [0x%x]\n",
__func__,
X->xselectionrequest.selection, validateString(strSelection),
X->xselectionrequest.target, validateString(strTarget),
DisplayString(nxagentDisplay), X->xselectionrequest.requestor,
X->xselectionrequest.property, validateString(strProperty),
lastServerRequestor);
SAFE_XFree(strTarget);
SAFE_XFree(strSelection);
SAFE_XFree(strProperty);
}
#endif
nxagentPrintClipboardStat("before nxagentRequestSelection");
......@@ -501,112 +692,122 @@ void nxagentRequestSelection(XEvent *X)
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)))
{
/*
FIXME: Do we need this?
char *strTarget;
strTarget = XGetAtomName(nxagentDisplay, X->xselectionrequest.target);
fprintf(stderr, "SelectionRequest event aborting sele=[%s] target=[%s]\n",
validateString(NameForAtom(X->xselectionrequest.selection)),
validateString(NameForAtom(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
*
* The selection does not matter here, we will return this for
* PRIMARY and CLIPBOARD.
*
* FIXME: shouldn't we support UTF8_STRING, too?
* FIXME: I am wondering if we should align this with
* nxagentConvertSelection, where we report more formats.
* 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: these must be external Atoms!
*/
fprintf(stderr, "SelectionRequest event aborting sele=[%s] ext target=[%s] Atom size is [%d]\n",
validateString(NameForAtom(X->xselectionrequest.selection)), strTarget, sizeof(Atom));
Atom targets[] = {XA_STRING};
int numTargets = 1;
SAFE_XFree(strTarget);
*/
memset(&eventSelection, 0, sizeof(XSelectionEvent));
eventSelection.property = None;
#ifdef DEBUG
fprintf(stderr, "%s: available targets:\n", __func__);
for (int i = 0; i < numTargets; i++)
fprintf(stderr, "%s: %s\n", __func__, NameForAtom(targets[i]));
fprintf(stderr, "\n");
#endif
if (X->xselectionrequest.target == serverTARGETS)
{
Atom xa_STRING = XA_STRING;
XChangeProperty (nxagentDisplay,
/*
* pass on the requested list by setting the property provided
* by the requestor accordingly.
*/
XChangeProperty(nxagentDisplay,
X->xselectionrequest.requestor,
X->xselectionrequest.property,
XInternAtom(nxagentDisplay, "ATOM", 0),
sizeof(Atom)*8,
PropModeReplace,
(unsigned char*)&xa_STRING,
1);
eventSelection.property = X->xselectionrequest.property;
(unsigned char*)&targets,
numTargets);
nxagentReplyRequestSelection(X, True);
}
else if (X->xselectionrequest.target == nxagentTimestampAtom)
else if (X->xselectionrequest.target == serverTIMESTAMP)
{
while ((i < NumCurrentSelections) &&
lastSelectionOwner[i].selection != X->xselectionrequest.selection) i++;
/*
* Section 2.6.2 of the ICCCM states:
* TIMESTAMP - To avoid some race conditions, it is important
* that requestors be able to discover the timestamp the owner
* used to acquire ownership. Until and unless the protocol is
* changed so that a GetSelectionOwner request returns the
* timestamp used to acquire ownership, selection owners must
* support conversion to TIMESTAMP, returning the timestamp they
* used to obtain the selection.
*
* FIXME: ensure we are reporting an _external_ timestamp
*/
if (i < NumCurrentSelections)
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
if (i < nxagentMaxSelections)
{
XChangeProperty(nxagentDisplay,
X->xselectionrequest.requestor,
X->xselectionrequest.property,
X->xselectionrequest.target,
XA_INTEGER,
32,
PropModeReplace,
(unsigned char *) &lastSelectionOwner[i].lastTimeChanged,
1);
eventSelection.property = X->xselectionrequest.property;
}
nxagentReplyRequestSelection(X, True);
}
eventSelection.type = SelectionNotify;
eventSelection.send_event = True;
eventSelection.display = nxagentDisplay;
eventSelection.requestor = X->xselectionrequest.requestor;
eventSelection.selection = X->xselectionrequest.selection;
eventSelection.target = X->xselectionrequest.target;
eventSelection.time = X->xselectionrequest.time;
#ifdef DEBUG
int result =
#endif
XSendEvent(nxagentDisplay,
eventSelection.requestor,
False,
0L,
(XEvent *) &eventSelection);
#ifdef DEBUG
fprintf(stderr, "%s: XSendEvent() returned [%s]\n", __func__, GetXErrorString(result));
if (result == BadValue || result == BadWindow)
{
fprintf(stderr, "%s: WARNING! XSendEvent failed.\n", __func__);
}
else
{
fprintf(stderr, "%s: XSendEvent sent to window [0x%lx].\n", __func__,
eventSelection.requestor);
/* deny the request */
nxagentReplyRequestSelection(X, False);
}
#endif
return;
}
/*
* This is necessary in nxagentGetClipboardWindow.
* reaching this means the request is neither a special request nor
* invalid. We can process it now.
*/
/*
* This is required for nxagentGetClipboardWindow.
*/
nxagentLastRequestedSelection = X->xselectionrequest.selection;
/* FIXME: shouldn't we reset i to 0 here first? */
while ((i < nxagentMaxSelections) &&
(lastSelectionOwner[i].selection != X->xselectionrequest.selection))
{
i++;
}
/* find the index of the requested selection */
int i = nxagentFindLastSelectionOwnerIndex(X->xselectionrequest.selection);
if (i < nxagentMaxSelections)
{
if ((lastClientWindowPtr != NULL) && (lastSelectionOwner[i].client != NULL))
{
/*
* Request the real X server to transfer the selection content
* to the NX_CUT_BUFFER_CLIENT property of the serverWindow.
* FIXME: document how we can end up here
*/
XConvertSelection(nxagentDisplay, CurrentSelections[i].selection,
X->xselectionrequest.target, serverCutProperty,
serverWindow, lastClientTime);
......@@ -617,141 +818,121 @@ FIXME: Do we need this?
}
else
{
/*
* if one of our clients owns the selection we ask it to copy
* the selection to the clientCutProperty on nxagent's root
* window
*/
if (lastSelectionOwner[i].client != NULL &&
nxagentOption(Clipboard) != ClipboardClient)
{
xEvent x;
/*
* store who on the real X server requested the data and how
* and where it wants to have it
*/
lastServerProperty = X->xselectionrequest.property;
lastServerRequestor = X->xselectionrequest.requestor;
lastServerTarget = X->xselectionrequest.target;
lastServerTime = X->xselectionrequest.time;
/* by dimbor */
if (lastServerTarget != XA_STRING)
lastServerTarget = serverUTF8_STRING;
lastServerTime = X->xselectionrequest.time;
memset(&x, 0, sizeof(xEvent));
/* prepare the request (like XConvertSelection, but internally) */
xEvent x = {0};
x.u.u.type = SelectionRequest;
x.u.selectionRequest.time = GetTimeInMillis();
x.u.selectionRequest.owner = lastSelectionOwner[i].window;
x.u.selectionRequest.selection = CurrentSelections[i].selection;
x.u.selectionRequest.property = clientCutProperty;
x.u.selectionRequest.requestor = screenInfo.screens[0]->root->drawable.id; /* Fictitious window.*/
/*
* Fictitious window.
*/
x.u.selectionRequest.requestor = screenInfo.screens[0]->root->drawable.id;
/*
* Don't send the same window, some programs are
* clever and verify cut and paste operations
* inside the same window and don't Notify at all.
* Don't send the same window, some programs are clever and
* verify cut and paste operations inside the same window and
* don't Notify at all.
*
* x.u.selectionRequest.requestor = lastSelectionOwnerWindow;
*/
x.u.selectionRequest.selection = CurrentSelections[i].selection;
/* by dimbor (idea from zahvatov) */
if (X->xselectionrequest.target != XA_STRING)
x.u.selectionRequest.target = clientUTF8_STRING;
else
x.u.selectionRequest.target = XA_STRING;
x.u.selectionRequest.property = clientCutProperty;
(void) TryClientEvents(lastSelectionOwner[i].client, &x, 1,
NoEventMask, NoEventMask /* CantBeFiltered */,
NullGrab);
#ifdef DEBUG
fprintf(stderr, "%s: Executed TryClientEvents with clientCutProperty.\n", __func__);
#endif
}
else
{
/*
* Probably we must send a Notify
* to requestor with property None.
*/
eventSelection.type = SelectionNotify;
eventSelection.send_event = True;
eventSelection.display = nxagentDisplay;
eventSelection.requestor = X->xselectionrequest.requestor;
eventSelection.selection = X->xselectionrequest.selection;
eventSelection.target = X->xselectionrequest.target;
eventSelection.property = None;
eventSelection.time = X->xselectionrequest.time;
SendEventToClient(lastSelectionOwner[i].client, &x);
#ifdef DEBUG
int result =
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);
#endif
XSendEvent(nxagentDisplay,
eventSelection.requestor,
False,
0L,
(XEvent *) &eventSelection);
#ifdef DEBUG
fprintf(stderr, "%s: XSendEvent() returned [%s]\n", __func__, GetXErrorString(result));
if (result == BadValue || result == BadWindow)
{
fprintf(stderr, "%s: WARNING! XSendEvent failed.\n", __func__);
}
else
{
fprintf(stderr, "%s: XSendEvent with property None sent to window [0x%lx].\n", __func__,
eventSelection.requestor);
}
#endif
/* deny the request */
nxagentReplyRequestSelection(X, False);
}
}
}
nxagentPrintClipboardStat("after nxagentRequestSelection");
}
void nxagentSendSelectionNotify(Atom property)
/*
* end current selection transfer by sending a notification to the
* client and resetting the corresponding variables and the state
* machine. If success is False send a None reply, meaning "request
* denied/failed"
* Use SELECTION_SUCCESS and SELECTION_FAULT macros for success.
*/
static void endTransfer(Bool success)
{
xEvent x;
if (lastClientClientPtr == NULL)
{
#ifdef DEBUG
fprintf (stderr, "%s: Sending event to client [%d].\n", __func__,
lastClientClientPtr -> index);
fprintf(stderr, "%s: lastClientClientPtr is NULL - doing nothing.\n", __func__);
#endif
return;
}
memset(&x, 0, sizeof(xEvent));
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = lastClientTime;
x.u.selectionNotify.requestor = lastClientRequestor;
x.u.selectionNotify.selection = lastClientSelection;
x.u.selectionNotify.target = lastClientTarget;
x.u.selectionNotify.property = property;
#ifdef DEBUG
if (success == SELECTION_SUCCESS)
fprintf(stderr, "%s: sending notification to client [%d], property [%d][%s]\n", __func__,
CLINDEX(lastClientClientPtr), lastClientProperty, NameForAtom(lastClientProperty));
else
fprintf(stderr, "%s: sending negative notification to client [%d]\n", __func__,
CLINDEX(lastClientClientPtr));
#endif
TryClientEvents(lastClientClientPtr, &x, 1, NoEventMask,
NoEventMask , NullGrab);
SendSelectionNotifyEventToClient(lastClientClientPtr,
lastClientTime,
lastClientRequestor,
lastClientSelection,
lastClientTarget,
success == SELECTION_SUCCESS ? lastClientProperty : None);
return;
/*
* Enable further requests from clients.
*/
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
}
void nxagentTransferSelection(int resource)
{
int result;
if (lastClientClientPtr -> index != resource)
{
#ifdef DEBUG
fprintf (stderr, "%s: WARNING! Inconsistent resource [%d] with current client [%d].\n", __func__,
resource, lastClientClientPtr -> index);
resource, CLINDEX(lastClientClientPtr));
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
endTransfer(SELECTION_FAULT);
return;
}
......@@ -760,6 +941,8 @@ void nxagentTransferSelection(int resource)
{
case SelectionStageQuerySize:
{
int result;
PrintClientSelectionStage();
/*
* Don't get data yet, just get size. We skip
......@@ -793,23 +976,24 @@ void nxagentTransferSelection(int resource)
{
#ifdef DEBUG
fprintf (stderr, "%s: Aborting selection notify procedure for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
endTransfer(SELECTION_FAULT);
return;
}
SetClientSelectionStage(WaitSize);
NXFlushDisplay(nxagentDisplay, NXFlushLink);
break;
}
case SelectionStageQueryData:
{
int result;
PrintClientSelectionStage();
/*
......@@ -846,26 +1030,27 @@ void nxagentTransferSelection(int resource)
{
#ifdef DEBUG
fprintf (stderr, "%s: Aborting selection notify procedure for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
endTransfer(SELECTION_FAULT);
return;
}
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 */
NXFlushDisplay(nxagentDisplay, NXFlushLink);
break;
}
default:
{
#ifdef DEBUG
fprintf (stderr, "%s: WARNING! Inconsistent state [%s] for client [%d].\n", __func__,
GetClientSelectionStageString(lastClientStage), lastClientClientPtr -> index);
GetClientSelectionStageString(lastClientStage), CLINDEX(lastClientClientPtr));
#endif
break;
......@@ -873,6 +1058,13 @@ void nxagentTransferSelection(int resource)
}
}
/*
Called from Events.c/nxagentHandlePropertyNotify
This event is generated after XChangeProperty(), XDeleteProperty() or
XGetWindowProperty(delete=True)
*/
void nxagentCollectPropertyEvent(int resource)
{
Atom atomReturnType;
......@@ -883,9 +1075,8 @@ void nxagentCollectPropertyEvent(int resource)
int result;
/*
* We have received the notification so
* we can safely retrieve data from the
* client structure.
* We have received the notification so we can safely retrieve data
* from the client structure.
*/
result = NXGetCollectedProperty(nxagentDisplay,
......@@ -901,37 +1092,21 @@ void nxagentCollectPropertyEvent(int resource)
if (result == 0)
{
#ifdef DEBUG
fprintf (stderr, "%s: Failed to get reply data for client [%d].\n", __func__,
lastClientClientPtr -> index);
fprintf (stderr, "%s: Failed to get reply data.\n", __func__);
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
SAFE_XFree(pszReturnData);
return;
endTransfer(SELECTION_FAULT);
}
if (resultFormat != 8 && resultFormat != 16 && resultFormat != 32)
else if (resultFormat != 8 && resultFormat != 16 && resultFormat != 32)
{
#ifdef DEBUG
fprintf (stderr, "%s: WARNING! Invalid property value.\n", __func__);
fprintf (stderr, "%s: WARNING! Invalid property format.\n", __func__);
#endif
if (lastClientClientPtr != NULL)
{
nxagentSendSelectionNotify(None);
}
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
SAFE_XFree(pszReturnData);
return;
endTransfer(SELECTION_FAULT);
}
else
{
switch (lastClientStage)
{
case SelectionStageWaitSize:
......@@ -939,25 +1114,19 @@ void nxagentCollectPropertyEvent(int resource)
PrintClientSelectionStage();
#ifdef DEBUG
fprintf (stderr, "%s: Got size notify event for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
if (ulReturnBytesLeft == 0)
{
#ifdef DEBUG
fprintf (stderr, "%s: Aborting selection notify procedure for client [%d].\n", __func__,
lastClientClientPtr -> index);
fprintf (stderr, "%s: Aborting selection notify procedure.\n", __func__);
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
SAFE_XFree(pszReturnData);
return;
endTransfer(SELECTION_FAULT);
}
else
{
#ifdef DEBUG
fprintf(stderr, "%s: Got property size from remote server.\n", __func__);
#endif
......@@ -965,12 +1134,11 @@ void nxagentCollectPropertyEvent(int resource)
/*
* Request the selection data now.
*/
lastClientPropertySize = ulReturnBytesLeft;
SetClientSelectionStage(QueryData);
nxagentTransferSelection(resource);
}
break;
}
case SelectionStageWaitData:
......@@ -978,25 +1146,19 @@ void nxagentCollectPropertyEvent(int resource)
PrintClientSelectionStage();
#ifdef DEBUG
fprintf (stderr, "%s: Got data notify event for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
if (ulReturnBytesLeft != 0)
{
#ifdef DEBUG
fprintf (stderr, "%s: Aborting selection notify procedure for client [%d].\n", __func__,
lastClientClientPtr -> index);
fprintf (stderr, "%s: Aborting selection notify procedure.\n", __func__);
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
SAFE_XFree(pszReturnData);
return;
endTransfer(SELECTION_FAULT);
}
else
{
#ifdef DEBUG
fprintf(stderr, "%s: Got property content from remote server.\n", __func__);
#endif
......@@ -1008,61 +1170,73 @@ void nxagentCollectPropertyEvent(int resource)
ulReturnItems, pszReturnData, 1);
#ifdef DEBUG
fprintf(stderr, "%s: Selection property [%s] changed to [%s]\n", __func__,
validateString(NameForAtom(lastClientProperty)), pszReturnData);
fprintf(stderr, "%s: Selection property [%d][%s] changed to [\"%*.*s\"...]\n", __func__,
lastClientProperty, validateString(NameForAtom(lastClientProperty)),
(int)(min(20, ulReturnItems * resultFormat / 8)),
(int)(min(20, ulReturnItems * resultFormat / 8)),
pszReturnData);
#endif
nxagentSendSelectionNotify(lastClientProperty);
/*
* Enable further requests from clients.
*/
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
endTransfer(SELECTION_SUCCESS);
}
break;
}
default:
{
#ifdef DEBUG
fprintf (stderr, "%s: WARNING! Inconsistent state [%s] for client [%d].\n", __func__,
GetClientSelectionStageString(lastClientStage), lastClientClientPtr -> index);
GetClientSelectionStageString(lastClientStage), CLINDEX(lastClientClientPtr));
#endif
break;
}
}
}
SAFE_XFree(pszReturnData);
}
void nxagentNotifySelection(XEvent *X)
/*
* This is _only_ called from Events.c dispatch loop on reception of a
* SelectionNotify event from the real X server. These events are
* sent out by nxagent itself!
*/
void nxagentHandleSelectionNotifyFromXServer(XEvent *X)
{
XSelectionEvent eventSelection;
#ifdef DEBUG
fprintf(stderr, "%s: Got called.\n", __func__);
#endif
if (agentClipboardStatus != 1)
{
return;
}
#ifdef DEBUG
fprintf(stderr, "%s: SelectionNotify event.\n", __func__);
{
XSelectionEvent * e = (XSelectionEvent *)X;
char * s = XGetAtomName(nxagentDisplay, e->property);
char * t = XGetAtomName(nxagentDisplay, e->target);
fprintf(stderr, "%s: SelectionNotify event from real X server, property "\
"[%ld][%s] requestor [0x%lx] target [%ld][%s] time [%ld] send_event [%d].\n",
__func__, e->property, validateString(s), e->requestor, e->target,
validateString(t), e->time, e->send_event);
SAFE_XFree(s);
SAFE_XFree(t);
}
#endif
PrintClientSelectionStage();
if (lastClientWindowPtr != NULL)
{
/*
* 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.
*/
if ((lastClientStage == SelectionStageNone) && (X->xselection.property == serverCutProperty))
{
#ifdef DEBUG
fprintf(stderr, "%s: Starting selection transferral for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
/*
......@@ -1085,31 +1259,21 @@ void nxagentNotifySelection(XEvent *X)
{
#ifdef DEBUG
fprintf(stderr, "%s: WARNING! Resetting selection transferral for client [%d].\n", __func__,
lastClientClientPtr -> index);
CLINDEX(lastClientClientPtr));
#endif
nxagentSendSelectionNotify(None);
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
endTransfer(SELECTION_FAULT);
}
return;
}
else
{
int i = 0;
while ((i < nxagentMaxSelections) && (lastSelectionOwner[i].selection != X->xselection.selection))
{
i++;
}
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 == clientCutProperty))
(X->xselection.property == serverClientCutProperty))
{
Atom atomReturnType;
int resultFormat;
......@@ -1117,38 +1281,44 @@ void nxagentNotifySelection(XEvent *X)
unsigned long ulReturnBytesLeft;
unsigned char *pszReturnData = NULL;
/* first get size values ... */
int result = GetWindowProperty(lastSelectionOwner[i].windowPtr, clientCutProperty, 0, 0, False,
AnyPropertyType, &atomReturnType, &resultFormat,
&ulReturnItems, &ulReturnBytesLeft, &pszReturnData);
#ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() returned [%s]\n", __func__, GetXErrorString(result));
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__,
lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
#endif
if (result == BadAlloc || result == BadAtom ||
result == BadWindow || result == BadValue)
{
fprintf (stderr, "Client GetProperty failed. Error = %s", GetXErrorString(result));
lastServerProperty = None;
}
else
{
/* ... then use the size values for the actual request */
result = GetWindowProperty(lastSelectionOwner[i].windowPtr, clientCutProperty, 0,
ulReturnBytesLeft, False, AnyPropertyType, &atomReturnType,
&resultFormat, &ulReturnItems, &ulReturnBytesLeft,
&pszReturnData);
#ifdef DEBUG
fprintf(stderr, "%s: GetWindowProperty() returned [%s]\n", __func__, GetXErrorString(result));
fprintf(stderr, "%s: GetWindowProperty() window [0x%x] property [%d] returned [%s]\n", __func__,
lastSelectionOwner[i].window, clientCutProperty, GetXErrorString(result));
#endif
if (result == BadAlloc || result == BadAtom ||
result == BadWindow || result == BadValue)
{
fprintf (stderr, "SelectionNotify - XChangeProperty failed. Error = %s\n", GetXErrorString(result));
lastServerProperty = None;
}
else
{
result = XChangeProperty(nxagentDisplay,
/* Fill the property on the initial requestor with the requested data */
/* The XChangeProperty source code reveals it will always
return 1, no matter what, so no need to check the result */
/* FIXME: better use the format returned by above request */
XChangeProperty(nxagentDisplay,
lastServerRequestor,
lastServerProperty,
lastServerTarget,
......@@ -1156,55 +1326,52 @@ void nxagentNotifySelection(XEvent *X)
PropModeReplace,
pszReturnData,
ulReturnItems);
}
#ifdef DEBUG
fprintf(stderr, "%s: XChangeProperty() returned [%s]\n", __func__, GetXErrorString(result));
{
char *s = XGetAtomName(nxagentDisplay, lastServerProperty);
fprintf(stderr, "%s: XChangeProperty sent to window [0x%x] for property [%d][%s] value [\"%*.*s\"...]\n",
__func__,
lastServerRequestor,
lastServerProperty,
s,
(int)(min(20, ulReturnItems * 8 / 8)),
(int)(min(20, ulReturnItems * 8 / 8)),
pszReturnData);
SAFE_XFree(s);
}
#endif
}
/* FIXME: free it or not? */
/*
* SAFE_XFree(pszReturnData);
*/
}
memset(&eventSelection, 0, sizeof(XSelectionEvent));
eventSelection.type = SelectionNotify;
eventSelection.send_event = True;
eventSelection.display = nxagentDisplay;
eventSelection.requestor = lastServerRequestor;
eventSelection.selection = X->xselection.selection;
/*
* eventSelection.target = X->xselection.target;
* inform the initial requestor that the requested data has
* arrived in the desired property. If we have been unable to
* get the data from the owner XChangeProperty will not have
* been called and lastServerProperty will be None which
* effectively will send a "Request denied" to the initial
* requestor.
*/
eventSelection.target = lastServerTarget;
eventSelection.property = lastServerProperty;
eventSelection.time = lastServerTime;
/*
* eventSelection.time = CurrentTime;
* eventSelection.time = lastServerTime;
*/
XSelectionEvent eventSelection = {
.requestor = lastServerRequestor,
.selection = X->xselection.selection,
/* .target = X->xselection.target, */
.target = lastServerTarget,
.property = lastServerProperty,
.time = lastServerTime,
/* .time = CurrentTime */
};
#ifdef DEBUG
fprintf(stderr, "%s: Sending event to requestor [%p].\n", __func__, (void *)eventSelection.requestor);
fprintf(stderr, "%s: Sending SelectionNotify event to requestor [%p].\n", __func__,
(void *)eventSelection.requestor);
#endif
result = XSendEvent(nxagentDisplay,
eventSelection.requestor,
False,
0L,
(XEvent *) &eventSelection);
#ifdef DEBUG
fprintf(stderr, "%s: XSendEvent() returned [%s]\n", __func__, GetXErrorString(result));
#endif
if (result == BadValue || result == BadWindow)
{
fprintf (stderr, "SelectionRequest - XSendEvent failed\n");
}
SendSelectionNotifyEventToServer(&eventSelection);
lastServerRequestor = None; /* allow further request */
}
......@@ -1213,21 +1380,24 @@ void nxagentNotifySelection(XEvent *X)
}
/*
* Acquire selection so we don't get selection
* requests from real X clients.
* Let nxagent's serverWindow acquire the selection. All requests from
* the real X server (or its clients) will be sent to this window. The
* real X server never communicates with our windows directly.
*/
void nxagentResetSelectionOwner(void)
{
int i;
if (lastServerRequestor != None)
{
#ifdef TEST
/*
* we are in the process of communicating back and forth between
* real X server and nxagent's clients - let's not disturb.
*/
#if defined(TEST) || defined(DEBUG)
fprintf(stderr, "%s: WARNING! Requestor window [0x%x] already found.\n", __func__,
lastServerRequestor);
#endif
/* FIXME: maybe we should put back the event that lead us here. */
return;
}
......@@ -1235,39 +1405,44 @@ void nxagentResetSelectionOwner(void)
* Only for PRIMARY and CLIPBOARD selections.
*/
for (i = 0; i < nxagentMaxSelections; i++)
for (int i = 0; i < nxagentMaxSelections; i++)
{
XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
#ifdef DEBUG
fprintf(stderr, "%s: Reset clipboard state.\n", __func__);
fprintf(stderr, "%s: Reset selection state for selection [%d].\n", __func__, i);
#endif
lastSelectionOwner[i].client = NULL;
lastSelectionOwner[i].window = None;
nxagentClearSelectionOwner(&lastSelectionOwner[i]);
lastSelectionOwner[i].windowPtr = NULL;
lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis();
}
lastClientWindowPtr = NULL;
SetClientSelectionStage(None);
/* Hmm, this is already None when reaching this */
lastServerRequestor = None;
return;
}
#ifdef NXAGENT_CLIPBOARD
/*
* The callback is called from dix. This is the normal operation
* mode. The callback is also called when nxagent gets XFixes events
* from the real X server. In that case the Trap is set and the
* callback will do nothing.
*/
void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
void *args)
{
/*
* Only act if the Trap is unset. The trap indicates that we are
* triggered by a clipboard event originating from the real X
* server. In that case we do not want to propagate back changes to
* the real X server, because it already knows about them and we
* Only act if the trap is unset. The trap indicates that we are
* triggered by an XFixes clipboard event originating from the real
* X server. In that case we do not want to propagate back changes
* to the real X server, because it already knows about them and we
* would end up in an infinite loop of events. If there was a better
* way to identify that situation during Callback processing we
* way to identify that situation during callback processing we
* could get rid of the Trap...
*/
if (nxagentExternalClipboardEventTrap != 0)
......@@ -1290,7 +1465,7 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
{
#ifdef DEBUG
fprintf(stderr, "%s: called with SelectionCallbackKind SelectionSetOwner\n", __func__);
fprintf(stderr, "%s: pCurSel->pWin [0x%x]\n", __func__, pCurSel->pWin ? pCurSel->pWin->drawable.id : NULL);
fprintf(stderr, "%s: pCurSel->pWin [0x%x]\n", __func__, WINDOWID(pCurSel->pWin));
fprintf(stderr, "%s: pCurSel->selection [%s]\n", __func__, NameForAtom(pCurSel->selection));
#endif
......@@ -1326,12 +1501,12 @@ void nxagentSetSelectionCallback(CallbackListPtr *callbacks, void *data,
}
#endif
/*
* This is called from the nxagentSetSelectionCallback, so it is using
* internal Atoms
*/
void nxagentSetSelectionOwner(Selection *pSelection)
{
#ifdef DEBUG
fprintf(stderr, "%s: Got called.\n", __func__);
#endif
if (agentClipboardStatus != 1)
{
return;
......@@ -1342,10 +1517,14 @@ void nxagentSetSelectionOwner(Selection *pSelection)
serverWindow);
#endif
#ifdef TEST
#if defined(TEST) || defined(DEBUG)
if (lastServerRequestor != None)
{
fprintf (stderr, "%s: WARNING! Requestor window [0x%x] already found.\n", __func__,
/*
* we are in the process of communicating back and forth between
* real X server and nxagent's clients - let's not disturb
*/
fprintf (stderr, "%s: WARNING! Requestor window [0x%x] already set.\n", __func__,
lastServerRequestor);
}
#endif
......@@ -1356,28 +1535,37 @@ void nxagentSetSelectionOwner(Selection *pSelection)
for (int i = 0; i < nxagentMaxSelections; i++)
{
/* FIXME: using CurrentSelections with the index limited my MaxSelections looks wrong */
if (pSelection->selection == CurrentSelections[i].selection)
{
#ifdef DEBUG
fprintf(stderr, "%s: lastSelectionOwner.client [0x%x] -> [0x%x]\n", __func__, lastSelectionOwner[i].client, pSelection->client);
fprintf(stderr, "%s: lastSelectionOwner.window [0x%x] -> [0x%x]\n", __func__, lastSelectionOwner[i].window, pSelection->window);
fprintf(stderr, "%s: lastSelectionOwner.windowPtr [0x%x] -> [0x%x] [0x%x] (serverWindow: [0x%x])\n", __func__, lastSelectionOwner[i].windowPtr, pSelection->pWin, nxagentWindow(pSelection->pWin), serverWindow);
fprintf(stderr, "%s: lastSelectionOwner.lastTimeChanged [%d]\n", __func__, lastSelectionOwner[i].lastTimeChanged);
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. 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
* clipboard owner.
*/
XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime);
lastSelectionOwner[i].client = pSelection->client;
lastSelectionOwner[i].window = pSelection->window;
lastSelectionOwner[i].windowPtr = pSelection->pWin;
lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis();
/*
* 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);
}
}
......@@ -1410,12 +1598,9 @@ FIXME
void nxagentNotifyConvertFailure(ClientPtr client, Window requestor,
Atom selection, Atom target, Time time)
{
xEvent x;
/*
FIXME: Why this pointer can be not a valid
client pointer?
*/
/*
* Check if the client is still valid.
*/
if (clients[client -> index] != client)
{
#ifdef WARNING
......@@ -1425,43 +1610,33 @@ FIXME: Why this pointer can be not a valid
return;
}
memset(&x, 0, sizeof(xEvent));
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = time;
x.u.selectionNotify.requestor = requestor;
x.u.selectionNotify.selection = selection;
x.u.selectionNotify.target = target;
x.u.selectionNotify.property = None;
(void) TryClientEvents(client, &x, 1, NoEventMask,
NoEventMask , NullGrab);
SendSelectionNotifyEventToClient(client, time, requestor, selection, target, None);
}
/*
* This is called from dix (ProcConvertSelection) if an nxagent client
* issues a ConvertSelection request. So all the Atoms are internal
* return codes:
* 0: let dix process the request
* 1: don't let dix process the request
*/
int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
Window requestor, Atom property, Atom target, Time time)
{
const char *strTarget;
int i;
if (agentClipboardStatus != 1 ||
nxagentOption(Clipboard) == ClipboardServer)
{
return 0;
}
/*
* There is a client owner on the agent side, let normal stuff happen.
*/
/*
* Only for PRIMARY and CLIPBOARD selections.
*/
for (i = 0; i < nxagentMaxSelections; i++)
for (int i = 0; i < nxagentMaxSelections; i++)
{
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;
}
}
......@@ -1498,111 +1673,118 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
}
#ifdef TEST
fprintf(stderr, "%s: client [%d] ask for sel [%s] "
"on window [%x] prop [%s] target [%s].\n", __func__,
client -> index, validateString(NameForAtom(selection)), requestor,
validateString(NameForAtom(property)), validateString(NameForAtom(target)));
#if defined(TEST) || defined(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,
property, validateString(NameForAtom(property)),
target, validateString(NameForAtom(target)));
#endif
strTarget = NameForAtom(target);
const char *strTarget = NameForAtom(target);
if (strTarget == NULL)
{
#ifdef DEBUG
fprintf(stderr, "%s: cannot find name for target Atom [%d] - returning\n", __func__, target);
#endif
return 1;
}
/*
* The selection request target is TARGETS. The requestor is asking
* for a list of supported data formats. Currently there's 4 of them.
*
* FIXME: I am wondering if we should align this with
* nxagentRequestSelection, where we only report one format.
*/
if (target == clientTARGETS)
{
Atom xa_STRING[4];
xEvent x;
/* --- Order changed by dimbor (prevent sending COMPOUND_TEXT to client --- */
xa_STRING[0] = XA_STRING;
xa_STRING[1] = clientUTF8_STRING;
xa_STRING[2] = clientTEXT;
xa_STRING[3] = clientCOMPOUND_TEXT;
Atom targets[] = {XA_STRING, clientUTF8_STRING, clientTEXT, clientCOMPOUND_TEXT};
int numTargets = 4;
#ifdef DEBUG
fprintf(stderr, "%s: available targets:\n", __func__);
for (int i = 0; i < numTargets; i++)
fprintf(stderr, "%s: %s\n", __func__, NameForAtom(targets[i]));
fprintf(stderr, "\n");
#endif
ChangeWindowProperty(pWin,
property,
MakeAtom("ATOM", 4, 1),
sizeof(Atom)*8,
PropModeReplace,
4,
&xa_STRING, 1);
memset(&x, 0, sizeof(xEvent));
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = time;
x.u.selectionNotify.requestor = requestor;
x.u.selectionNotify.selection = selection;
x.u.selectionNotify.target = target;
x.u.selectionNotify.property = property;
numTargets,
&targets,
1);
(void) TryClientEvents(client, &x, 1, NoEventMask,
NoEventMask , NullGrab);
SendSelectionNotifyEventToClient(client, time, requestor, selection, target, property);
return 1;
}
/*
* Section 2.6.2 of the ICCCM states:
* "TIMESTAMP - To avoid some race conditions, it is important
* that requestors be able to discover the timestamp the owner
* used to acquire ownership. Until and unless the protocol is
* changed so that a GetSelectionOwner request returns the
* timestamp used to acquire ownership, selection owners must
* support conversion to TIMESTAMP, returning the timestamp they
* used to obtain the selection."
*/
if (target == MakeAtom("TIMESTAMP", 9, 1))
{
int i = 0;
while ((i < NumCurrentSelections) &&
CurrentSelections[i].selection != selection) i++;
int i = nxagentFindCurrentSelectionIndex(selection);
if (i < NumCurrentSelections)
{
xEvent x;
/*
* "If the specified property is not None, the owner should place
* the data resulting from converting the selection into the
* specified property on the requestor window and should set the
* property's type to some appropriate value, which need not be
* the same as the specified target."
*/
ChangeWindowProperty(pWin,
property,
target,
XA_INTEGER,
32,
PropModeReplace,
1,
(unsigned char *) &lastSelectionOwner[i].lastTimeChanged,
1);
memset(&x, 0, sizeof(xEvent));
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = time;
x.u.selectionNotify.requestor = requestor;
x.u.selectionNotify.selection = selection;
x.u.selectionNotify.target = target;
x.u.selectionNotify.property = property;
(void) TryClientEvents(client, &x, 1, NoEventMask,
NoEventMask , NullGrab);
SendSelectionNotifyEventToClient(client, time, requestor, selection, target, property);
return 1;
}
}
#ifdef DEBUG
if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < 5000))
{
/*
* The same client made consecutive requests
* of clipboard contents with less than 5
* seconds time interval between them.
* The same client made consecutive requests of clipboard content
* with less than 5 seconds time interval between them.
*/
#ifdef DEBUG
fprintf(stderr, "%s: Consecutives request from client [%p] selection [%u] "
"elapsed time [%u] clientAccum [%d]\n", __func__, (void *) client, selection,
GetTimeInMillis() - lastClientReqTime, clientAccum);
#endif
clientAccum++;
}
else
{
/* reset clientAccum as now another client requested the clipboard content */
if (lastClientClientPtr != client)
{
clientAccum = 0;
}
}
#endif
if ((target == clientTEXT) ||
(target == XA_STRING) ||
......@@ -1611,6 +1793,10 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
{
lastClientWindowPtr = pWin;
SetClientSelectionStage(None);
/*
* store the original requestor, we need that later after
* serverCutProperty contains the desired selection content
*/
lastClientRequestor = requestor;
lastClientClientPtr = client;
lastClientTime = time;
......@@ -1618,25 +1804,41 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
lastClientSelection = selection;
lastClientTarget = target;
lastClientReqTime = (GetTimeInMillis() - lastClientReqTime) > 5000 ?
GetTimeInMillis() : lastClientReqTime;
/* if the last client request time is more than 5s ago update it. Why? */
if ((GetTimeInMillis() - lastClientReqTime) > 5000)
lastClientReqTime = GetTimeInMillis();
if (selection == MakeAtom("CLIPBOARD", 9, 0))
{
selection = lastSelectionOwner[nxagentClipboardSelection].selection;
}
/*
* we only convert to either UTF8 or XA_STRING, despite accepting
* TEXT and COMPOUND_TEXT.
*/
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);
#endif
XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverCutProperty,
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);
#endif
XConvertSelection(nxagentDisplay, selection, XA_STRING, serverCutProperty,
serverWindow, CurrentTime);
}
/* FIXME: check returncode of XConvertSelection */
#ifdef DEBUG
fprintf(stderr, "%s: Sent XConvertSelection with target=[%s], property [%s]\n", __func__,
validateString(NameForAtom(target)), validateString(NameForAtom(property)));
......@@ -1646,26 +1848,32 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection,
}
else
{
xEvent x;
#ifdef DEBUG
fprintf(stderr, "%s: Xserver generates a SelectionNotify event "
"to the requestor with property None.\n", __func__);
#endif
/* deny request */
SendSelectionNotifyEventToClient(client, time, requestor, selection, target, None);
memset(&x, 0, sizeof(xEvent));
x.u.u.type = SelectionNotify;
x.u.selectionNotify.time = time;
x.u.selectionNotify.requestor = requestor;
x.u.selectionNotify.selection = selection;
x.u.selectionNotify.target = target;
x.u.selectionNotify.property = None;
(void) TryClientEvents(client, &x, 1, NoEventMask, NoEventMask , NullGrab);
return 1;
}
return 0;
}
/*
* This is _only_ called from ProcSendEvent in NXevents.c. It is used
* to send a SelectionNotify event to our server window which will
* 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.
*
* Returning 1 here means the client request will not be further
* handled by dix. Returning 0 means a SelectionNotify event being
* pushed out to our clients.
*
* From https://tronche.com/gui/x/xlib/events/client-communication/selection.html:
* "This event is generated by the X server in response to a
* ConvertSelection protocol request when there is no owner for the
* selection. When there is an owner, it should be generated by the
* owner of the selection by using XSendEvent()."
*/
int nxagentSendNotify(xEvent *event)
{
#ifdef DEBUG
......@@ -1681,56 +1889,92 @@ int nxagentSendNotify(xEvent *event)
}
#ifdef DEBUG
fprintf(stderr, "%s: property is [%d][%s].\n", __func__, event->u.selectionNotify.property, NameForAtom(event->u.selectionNotify.property));
fprintf(stderr, "%s: property is [%d][%s].\n", __func__,
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
if (event->u.selectionNotify.property == clientCutProperty)
/*
* If we have nested sessions there are situations where we do not
* need to send out anything to the real X server because
* communication happens completely between our own clients (some of
* 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)
{
XSelectionEvent x;
int result;
/*
* 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.
*/
memset(&x, 0, sizeof(XSelectionEvent));
x.type = SelectionNotify;
x.send_event = True;
x.display = nxagentDisplay;
x.requestor = serverWindow;
XSelectionEvent eventSelection = {
.requestor = serverWindow,
.selection = event->u.selectionNotify.selection,
.target = event->u.selectionNotify.target,
.property = serverClientCutProperty,
.time = CurrentTime,
};
/*
* On real server, the right CLIPBOARD atom is
* XInternAtom(nxagentDisplay, "CLIPBOARD", 1).
* On the real server, the right CLIPBOARD atom is
* XInternAtom(nxagentDisplay, "CLIPBOARD", 1), which is stored in
* lastSelectionOwner[nxagentClipboardSelection].selection. For
* PRIMARY there's nothing to map because that is identical on all
* X servers (defined in Xatom.h).
*/
if (event->u.selectionNotify.selection == MakeAtom("CLIPBOARD", 9, 0))
{
x.selection = lastSelectionOwner[nxagentClipboardSelection].selection;
eventSelection.selection = lastSelectionOwner[nxagentClipboardSelection].selection;
}
/*
* .target must be translated, too, as a client on the real
* server is requested to fill our property and it needs to know
* the format.
*/
if (event->u.selectionNotify.target == clientUTF8_STRING)
{
eventSelection.target = serverUTF8_STRING;
}
else if (event->u.selectionNotify.target == clientTEXT)
{
eventSelection.target = serverTEXT;
}
/*else if (event->u.selectionNotify.target == clientCOMPOUND_TEXT)
{
eventSelection.target = serverCOMPOUND_TEXT;
}*/
else
{
x.selection = event->u.selectionNotify.selection;
eventSelection.target = XA_STRING;
}
x.target = event->u.selectionNotify.target;
x.property = event->u.selectionNotify.property;
x.time = CurrentTime;
#ifdef DEBUG
fprintf(stderr, "%s: Propagating clientCutProperty to requestor [%p].\n", __func__, (void *)x.requestor);
fprintf(stderr, "%s: mapping local to remote Atom: [%d] -> [%ld] [%s]\n", __func__,
event->u.selectionNotify.selection, eventSelection.selection,
NameForAtom(event->u.selectionNotify.selection));
fprintf(stderr, "%s: mapping local to remote Atom: [%d] -> [%ld] [%s]\n", __func__,
event->u.selectionNotify.target, eventSelection.target,
NameForAtom(event->u.selectionNotify.target));
fprintf(stderr, "%s: mapping local to remote Atom: [%d] -> [%ld] [%s]\n", __func__,
event->u.selectionNotify.property, eventSelection.property,
NameForAtom(event->u.selectionNotify.property));
#endif
result = XSendEvent (nxagentDisplay, x.requestor, False,
0L, (XEvent *) &x);
#ifdef DEBUG
fprintf(stderr, "%s: XSendEvent() returned [%s]\n", __func__, GetXErrorString(result));
#endif
if (result == BadValue || result == BadWindow)
{
fprintf (stderr, "%s: XSendEvent failed.\n", __func__);
}
SendSelectionNotifyEventToServer(&eventSelection);
return 1;
}
......@@ -1740,43 +1984,38 @@ int nxagentSendNotify(xEvent *event)
return 0;
}
WindowPtr nxagentGetClipboardWindow(Atom property, WindowPtr pWin)
WindowPtr nxagentGetClipboardWindow(Atom property)
{
int i = 0;
#ifdef DEBUG
fprintf(stderr, "%s: Got called, property [%d][%s] window [%p].\n", __func__, property, NameForAtom(property), (void *)pWin);
#endif
while ((i < nxagentMaxSelections) &&
(lastSelectionOwner[i].selection != nxagentLastRequestedSelection))
{
i++;
}
int i = nxagentFindLastSelectionOwnerIndex(nxagentLastRequestedSelection);
if ((i < nxagentMaxSelections) && (property == clientCutProperty) &&
(lastSelectionOwner[i].windowPtr != NULL))
{
#ifdef DEBUG
fprintf(stderr, "%s: Returning last clipboard owner window [%p].\n", __func__, (void *)lastSelectionOwner[i].windowPtr);
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));
#endif
return lastSelectionOwner[i].windowPtr;
}
else
{
#ifdef DEBUG
fprintf(stderr, "%s: Returning original target window [%p].\n", __func__, (void *)pWin);
#endif
return pWin;
return NULL;
}
}
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)
{
int i;
Window iWindow = nxagentWindow(pWin);
#ifdef DEBUG
......@@ -1792,20 +2031,10 @@ int nxagentInitClipboard(WindowPtr pWin)
FatalError("nxagentInitClipboard: Failed to allocate memory for the clipboard selections.\n");
}
nxagentClipboardAtom = nxagentAtoms[10]; /* CLIPBOARD */
nxagentTimestampAtom = nxagentAtoms[11]; /* TIMESTAMP */
serverTIMESTAMP = nxagentAtoms[11]; /* TIMESTAMP */
lastSelectionOwner[nxagentPrimarySelection].selection = XA_PRIMARY;
lastSelectionOwner[nxagentPrimarySelection].client = NullClient;
lastSelectionOwner[nxagentPrimarySelection].window = screenInfo.screens[0]->root->drawable.id;
lastSelectionOwner[nxagentPrimarySelection].windowPtr = NULL;
lastSelectionOwner[nxagentPrimarySelection].lastTimeChanged = GetTimeInMillis();
lastSelectionOwner[nxagentClipboardSelection].selection = nxagentClipboardAtom;
lastSelectionOwner[nxagentClipboardSelection].client = NullClient;
lastSelectionOwner[nxagentClipboardSelection].window = screenInfo.screens[0]->root->drawable.id;
lastSelectionOwner[nxagentClipboardSelection].windowPtr = NULL;
lastSelectionOwner[nxagentClipboardSelection].lastTimeChanged = GetTimeInMillis();
nxagentInitSelectionOwner(&lastSelectionOwner[nxagentPrimarySelection], XA_PRIMARY);
nxagentInitSelectionOwner(&lastSelectionOwner[nxagentClipboardSelection], nxagentAtoms[10]); /* CLIPBOARD */
#ifdef NXAGENT_TIMESTAMP
{
......@@ -1827,6 +2056,8 @@ int nxagentInitClipboard(WindowPtr pWin)
serverTARGETS = nxagentAtoms[6]; /* TARGETS */
serverTEXT = nxagentAtoms[7]; /* TEXT */
serverUTF8_STRING = nxagentAtoms[12]; /* UTF8_STRING */
/* see nxagentSendNotify for an explanation */
serverClientCutProperty = nxagentAtoms[15]; /* NX_CUT_BUFFER_CLIENT */
if (serverCutProperty == None)
{
......@@ -1858,7 +2089,7 @@ int nxagentInitClipboard(WindowPtr pWin)
fprintf(stderr, "%s: Registering for XFixesSelectionNotify events.\n", __func__);
#endif
for (i = 0; i < nxagentMaxSelections; i++)
for (int i = 0; i < nxagentMaxSelections; i++)
{
XFixesSelectSelectionInput(nxagentDisplay, iWindow,
lastSelectionOwner[i].selection,
......@@ -1898,7 +2129,7 @@ int nxagentInitClipboard(WindowPtr pWin)
* Only for PRIMARY and CLIPBOARD selections.
*/
for (i = 0; i < nxagentMaxSelections; i++)
for (int i = 0; i < nxagentMaxSelections; i++)
{
if (lastSelectionOwner[i].client && lastSelectionOwner[i].window)
{
......
......@@ -64,6 +64,7 @@ extern int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom select
void nxagentClearSelection();
void nxagentRequestSelection();
void nxagentNotifySelection();
void nxagentHandleSelectionNotifyFromXServer();
int nxagentFindCurrentSelectionIndex(Atom sel);
#endif /* __Clipboard_H__ */
......@@ -944,7 +944,7 @@ void nxagentDispatchEvents(PredicateFuncPtr predicate)
fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionNotify event.\n");
#endif
nxagentNotifySelection(&X);
nxagentHandleSelectionNotifyFromXServer(&X);
break;
}
......@@ -2933,12 +2933,7 @@ int nxagentHandleXFixesSelectionNotify(XEvent *X)
if (SelectionCallback)
{
int i = 0;
while ((i < NumCurrentSelections) &&
CurrentSelections[i].selection != local)
i++;
int i = nxagentFindCurrentSelectionIndex(local);
if (i < NumCurrentSelections)
{
SelectionInfoRec info;
......
......@@ -691,11 +691,7 @@ ProcConvertSelection(register ClientPtr client)
(stuff->selection == MakeAtom("CLIPBOARD", 9, 0))) &&
nxagentOption(Clipboard) != ClipboardNone)
{
int i = 0;
while ((i < NumCurrentSelections) &&
CurrentSelections[i].selection != stuff->selection) i++;
int i = nxagentFindCurrentSelectionIndex(stuff->selection);
if ((i < NumCurrentSelections) && (CurrentSelections[i].window != None))
{
if (nxagentConvertSelection(client, pWin, stuff->selection, stuff->requestor,
......
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