#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "windowstr.h"
#include "dixstruct.h"
#include "dispatch.h"
#include "selection.h"
#include "xace.h"
_X_EXPORT Selection *CurrentSelections;
CallbackListPtr SelectionCallback;
_X_EXPORT int
dixLookupSelection(Selection **result, Atom selectionName,
ClientPtr client, Mask access_mode)
{
Selection *pSel;
int rc = BadMatch;
client->errorValue = selectionName;
for (pSel = CurrentSelections; pSel; pSel = pSel->next)
if (pSel->selection == selectionName)
break;
if (pSel)
rc = XaceHookSelectionAccess(client, &pSel, access_mode);
*result = pSel;
return rc;
}
void
InitSelections(void)
{
Selection *pSel, *pNextSel;
pSel = CurrentSelections;
while (pSel) {
pNextSel = pSel->next;
dixFreePrivates(pSel->devPrivates);
xfree(pSel);
pSel = pNextSel;
}
CurrentSelections = NULL;
}
static _X_INLINE void
CallSelectionCallback(Selection *pSel, ClientPtr client,
SelectionCallbackKind kind)
{
SelectionInfoRec info = { pSel, client, kind };
CallCallbacks(&SelectionCallback, &info);
}
void
DeleteWindowFromAnySelections(WindowPtr pWin)
{
Selection *pSel;
for (pSel = CurrentSelections; pSel; pSel = pSel->next)
if (pSel->pWin == pWin) {
CallSelectionCallback(pSel, NULL, SelectionWindowDestroy);
pSel->pWin = (WindowPtr)NULL;
pSel->window = None;
pSel->client = NullClient;
}
}
void
DeleteClientFromAnySelections(ClientPtr client)
{
Selection *pSel;
for (pSel = CurrentSelections; pSel; pSel = pSel->next)
if (pSel->client == client) {
CallSelectionCallback(pSel, NULL, SelectionClientClose);
pSel->pWin = (WindowPtr)NULL;
pSel->window = None;
pSel->client = NullClient;
}
}
int
ProcSetSelectionOwner(ClientPtr client)
{
WindowPtr pWin = NULL;
TimeStamp time;
Selection *pSel;
int rc;
REQUEST(xSetSelectionOwnerReq);
REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
UpdateCurrentTime();
time = ClientTimeToServerTime(stuff->time);
if (CompareTimeStamps(time, currentTime) == LATER)
return Success;
if (stuff->window != None) {
rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess);
if (rc != Success)
return rc;
}
if (!ValidAtom(stuff->selection)) {
client->errorValue = stuff->selection;
return BadAtom;
}
rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess);
if (rc == Success) {
xEvent event;
if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER)
return Success;
if (pSel->client && (!pWin || (pSel->client != client)))
{
event.u.u.type = SelectionClear;
event.u.selectionClear.time = time.milliseconds;
event.u.selectionClear.window = pSel->window;
event.u.selectionClear.atom = pSel->selection;
TryClientEvents(pSel->client, NULL, &event, 1, NoEventMask,
NoEventMask , NullGrab);
}
}
else if (rc == BadMatch)
{
pSel = xalloc(sizeof(Selection));
if (!pSel)
return BadAlloc;
pSel->selection = stuff->selection;
pSel->devPrivates = NULL;
rc = XaceHookSelectionAccess(client, &pSel,
DixCreateAccess|DixSetAttrAccess);
if (rc != Success) {
xfree(pSel);
return rc;
}
pSel->next = CurrentSelections;
CurrentSelections = pSel;
}
else
return rc;
pSel->lastTimeChanged = time;
pSel->window = stuff->window;
pSel->pWin = pWin;
pSel->client = (pWin ? client : NullClient);
CallSelectionCallback(pSel, client, SelectionSetOwner);
return client->noClientException;
}
int
ProcGetSelectionOwner(ClientPtr client)
{
int rc;
Selection *pSel;
xGetSelectionOwnerReply reply;
REQUEST(xResourceReq);
REQUEST_SIZE_MATCH(xResourceReq);
if (!ValidAtom(stuff->id)) {
client->errorValue = stuff->id;
return BadAtom;
}
reply.type = X_Reply;
reply.length = 0;
reply.sequenceNumber = client->sequence;
rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess);
if (rc == Success)
reply.owner = pSel->window;
else if (rc == BadMatch)
reply.owner = None;
else
return rc;
WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
return client->noClientException;
}
int
ProcConvertSelection(ClientPtr client)
{
Bool paramsOkay;
xEvent event;
WindowPtr pWin;
Selection *pSel;
int rc;
REQUEST(xConvertSelectionReq);
REQUEST_SIZE_MATCH(xConvertSelectionReq);
rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess);
if (rc != Success)
return rc;
paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target);
paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property);
if (!paramsOkay) {
client->errorValue = stuff->property;
return BadAtom;
}
rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess);
if (rc != Success && rc != BadMatch)
return rc;
else if (rc == Success && pSel->window != None) {
event.u.u.type = SelectionRequest;
event.u.selectionRequest.owner = pSel->window;
event.u.selectionRequest.time = stuff->time;
event.u.selectionRequest.requestor = stuff->requestor;
event.u.selectionRequest.selection = stuff->selection;
event.u.selectionRequest.target = stuff->target;
event.u.selectionRequest.property = stuff->property;
if (TryClientEvents(pSel->client, NULL, &event, 1, NoEventMask,
NoEventMask , NullGrab))
return client->noClientException;
}
event.u.u.type = SelectionNotify;
event.u.selectionNotify.time = stuff->time;
event.u.selectionNotify.requestor = stuff->requestor;
event.u.selectionNotify.selection = stuff->selection;
event.u.selectionNotify.target = stuff->target;
event.u.selectionNotify.property = None;
TryClientEvents(client, NULL, &event, 1, NoEventMask,
NoEventMask , NullGrab);
return client->noClientException;
}