summaryrefslogtreecommitdiff
path: root/xfixes/select.c
diff options
context:
space:
mode:
authorStuart Kreitman <stuart.kreitman@sun.com>2004-07-29 14:33:43 +0000
committerStuart Kreitman <stuart.kreitman@sun.com>2004-07-29 14:33:43 +0000
commit6ed1c3845517c7731dcc74baa51bb801838afaff (patch)
tree36b4ef8bf8a3806d11af6024883925d5491f9873 /xfixes/select.c
parent736e511824c4f5e77e637c680a4e45f0b7631644 (diff)
bugzilla 859 -merging DAMAGE-XFIXES into trunk
Diffstat (limited to 'xfixes/select.c')
-rwxr-xr-xxfixes/select.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/xfixes/select.c b/xfixes/select.c
new file mode 100755
index 000000000..6cccfa504
--- /dev/null
+++ b/xfixes/select.c
@@ -0,0 +1,278 @@
+/*
+ * $Id$
+ *
+ * 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_CONFIG_H
+#include <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.sequenceNumber = e->pClient->sequence;
+ 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 = (SelectionEventPtr) xalloc (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))
+ {
+ xfree (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)
+{
+ register int n;
+ REQUEST(xXFixesSelectSelectionInputReq);
+
+ swaps(&stuff->length, n);
+ swapl(&stuff->window, n);
+ swapl(&stuff->selection, n);
+ swapl(&stuff->eventMask, n);
+ 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;
+ xfree (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;
+}