257 lines
7.6 KiB
C
257 lines
7.6 KiB
C
/*
|
|
* Copyright © 2002 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include "xfixesint.h"
|
|
|
|
static RESTYPE SelectionClientType, SelectionWindowType;
|
|
|
|
static Bool SelectionCallbackRegistered = FALSE;
|
|
|
|
/*
|
|
* There is a global list of windows selecting for selection events
|
|
* on every selection. This should be plenty efficient for the
|
|
* expected usage, if it does become a problem, it should be easily
|
|
* replaced with a hash table of some kind keyed off the selection atom
|
|
*/
|
|
|
|
typedef struct _SelectionEvent *SelectionEventPtr;
|
|
|
|
typedef struct _SelectionEvent {
|
|
SelectionEventPtr next;
|
|
Atom selection;
|
|
CARD32 eventMask;
|
|
ClientPtr pClient;
|
|
WindowPtr pWindow;
|
|
XID clientResource;
|
|
} SelectionEventRec;
|
|
|
|
static SelectionEventPtr selectionEvents;
|
|
|
|
static void
|
|
XFixesSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
|
|
{
|
|
SelectionEventPtr e;
|
|
SelectionInfoRec *info = (SelectionInfoRec *) args;
|
|
Selection *selection = info->selection;
|
|
int subtype;
|
|
CARD32 eventMask;
|
|
|
|
switch (info->kind) {
|
|
case SelectionSetOwner:
|
|
subtype = XFixesSetSelectionOwnerNotify;
|
|
eventMask = XFixesSetSelectionOwnerNotifyMask;
|
|
break;
|
|
case SelectionWindowDestroy:
|
|
subtype = XFixesSelectionWindowDestroyNotify;
|
|
eventMask = XFixesSelectionWindowDestroyNotifyMask;
|
|
break;
|
|
case SelectionClientClose:
|
|
subtype = XFixesSelectionClientCloseNotify;
|
|
eventMask = XFixesSelectionClientCloseNotifyMask;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
for (e = selectionEvents; e; e = e->next) {
|
|
if (e->selection == selection->selection && (e->eventMask & eventMask)) {
|
|
xXFixesSelectionNotifyEvent ev;
|
|
|
|
ev.type = XFixesEventBase + XFixesSelectionNotify;
|
|
ev.subtype = subtype;
|
|
ev.window = e->pWindow->drawable.id;
|
|
if (subtype == XFixesSetSelectionOwnerNotify)
|
|
ev.owner = selection->window;
|
|
else
|
|
ev.owner = 0;
|
|
ev.selection = e->selection;
|
|
ev.timestamp = currentTime.milliseconds;
|
|
ev.selectionTimestamp = selection->lastTimeChanged.milliseconds;
|
|
WriteEventsToClient(e->pClient, 1, (xEvent *) &ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
CheckSelectionCallback(void)
|
|
{
|
|
if (selectionEvents) {
|
|
if (!SelectionCallbackRegistered) {
|
|
if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL))
|
|
return FALSE;
|
|
SelectionCallbackRegistered = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (SelectionCallbackRegistered) {
|
|
DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL);
|
|
SelectionCallbackRegistered = FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\
|
|
XFixesSelectionWindowDestroyNotifyMask |\
|
|
XFixesSelectionClientCloseNotifyMask)
|
|
|
|
static int
|
|
XFixesSelectSelectionInput(ClientPtr pClient,
|
|
Atom selection, WindowPtr pWindow, CARD32 eventMask)
|
|
{
|
|
SelectionEventPtr *prev, e;
|
|
|
|
for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
|
|
if (e->selection == selection &&
|
|
e->pClient == pClient && e->pWindow == pWindow) {
|
|
break;
|
|
}
|
|
}
|
|
if (!eventMask) {
|
|
if (e) {
|
|
FreeResource(e->clientResource, 0);
|
|
}
|
|
return Success;
|
|
}
|
|
if (!e) {
|
|
e = malloc(sizeof(SelectionEventRec));
|
|
if (!e)
|
|
return BadAlloc;
|
|
|
|
e->next = 0;
|
|
e->selection = selection;
|
|
e->pClient = pClient;
|
|
e->pWindow = pWindow;
|
|
e->clientResource = FakeClientID(pClient->index);
|
|
|
|
/*
|
|
* Add a resource hanging from the window to
|
|
* catch window destroy
|
|
*/
|
|
if (!LookupIDByType(pWindow->drawable.id, SelectionWindowType))
|
|
if (!AddResource(pWindow->drawable.id, SelectionWindowType,
|
|
(pointer) pWindow)) {
|
|
free(e);
|
|
return BadAlloc;
|
|
}
|
|
|
|
if (!AddResource(e->clientResource, SelectionClientType, (pointer) e))
|
|
return BadAlloc;
|
|
|
|
*prev = e;
|
|
if (!CheckSelectionCallback()) {
|
|
FreeResource(e->clientResource, 0);
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
e->eventMask = eventMask;
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXFixesSelectSelectionInput(ClientPtr client)
|
|
{
|
|
REQUEST(xXFixesSelectSelectionInputReq);
|
|
WindowPtr pWin;
|
|
|
|
REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
|
|
pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client,
|
|
SecurityReadAccess);
|
|
if (!pWin)
|
|
return (BadWindow);
|
|
if (stuff->eventMask & ~SelectionAllEvents) {
|
|
client->errorValue = stuff->eventMask;
|
|
return (BadValue);
|
|
}
|
|
return XFixesSelectSelectionInput(client, stuff->selection,
|
|
pWin, stuff->eventMask);
|
|
}
|
|
|
|
int
|
|
SProcXFixesSelectSelectionInput(ClientPtr client)
|
|
{
|
|
|
|
REQUEST(xXFixesSelectSelectionInputReq);
|
|
|
|
swaps(&stuff->length);
|
|
swapl(&stuff->window);
|
|
swapl(&stuff->selection);
|
|
swapl(&stuff->eventMask);
|
|
return ProcXFixesSelectSelectionInput(client);
|
|
}
|
|
|
|
void
|
|
SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,
|
|
xXFixesSelectionNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswapl(from->window, to->window);
|
|
cpswapl(from->owner, to->owner);
|
|
cpswapl(from->selection, to->selection);
|
|
cpswapl(from->timestamp, to->timestamp);
|
|
cpswapl(from->selectionTimestamp, to->selectionTimestamp);
|
|
}
|
|
|
|
static int
|
|
SelectionFreeClient(pointer data, XID id)
|
|
{
|
|
SelectionEventPtr old = (SelectionEventPtr) data;
|
|
SelectionEventPtr *prev, e;
|
|
|
|
for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
|
|
if (e == old) {
|
|
*prev = e->next;
|
|
free(e);
|
|
CheckSelectionCallback();
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
SelectionFreeWindow(pointer data, XID id)
|
|
{
|
|
WindowPtr pWindow = (WindowPtr) data;
|
|
SelectionEventPtr e, next;
|
|
|
|
for (e = selectionEvents; e; e = next) {
|
|
next = e->next;
|
|
if (e->pWindow == pWindow) {
|
|
FreeResource(e->clientResource, 0);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
Bool
|
|
XFixesSelectionInit(void)
|
|
{
|
|
SelectionClientType = CreateNewResourceType(SelectionFreeClient);
|
|
SelectionWindowType = CreateNewResourceType(SelectionFreeWindow);
|
|
return SelectionClientType && SelectionWindowType;
|
|
}
|