ee8ed6f682c0c7480bd598b046a5760b2c20a3e1
[deb_xorg-server.git] / xfixes / select.c
1 /*
2 * Copyright © 2002 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
26
27 #include "xfixesint.h"
28 #include "xace.h"
29
30 static RESTYPE SelectionClientType, SelectionWindowType;
31 static Bool SelectionCallbackRegistered = FALSE;
32
33 /*
34 * There is a global list of windows selecting for selection events
35 * on every selection. This should be plenty efficient for the
36 * expected usage, if it does become a problem, it should be easily
37 * replaced with a hash table of some kind keyed off the selection atom
38 */
39
40 typedef struct _SelectionEvent *SelectionEventPtr;
41
42 typedef struct _SelectionEvent {
43 SelectionEventPtr next;
44 Atom selection;
45 CARD32 eventMask;
46 ClientPtr pClient;
47 WindowPtr pWindow;
48 XID clientResource;
49 } SelectionEventRec;
50
51 static SelectionEventPtr selectionEvents;
52
53 static void
54 XFixesSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
55 {
56 SelectionEventPtr e;
57 SelectionInfoRec *info = (SelectionInfoRec *) args;
58 Selection *selection = info->selection;
59 int subtype;
60 CARD32 eventMask;
61
62 switch (info->kind) {
63 case SelectionSetOwner:
64 subtype = XFixesSetSelectionOwnerNotify;
65 eventMask = XFixesSetSelectionOwnerNotifyMask;
66 break;
67 case SelectionWindowDestroy:
68 subtype = XFixesSelectionWindowDestroyNotify;
69 eventMask = XFixesSelectionWindowDestroyNotifyMask;
70 break;
71 case SelectionClientClose:
72 subtype = XFixesSelectionClientCloseNotify;
73 eventMask = XFixesSelectionClientCloseNotifyMask;
74 break;
75 default:
76 return;
77 }
78 for (e = selectionEvents; e; e = e->next) {
79 if (e->selection == selection->selection && (e->eventMask & eventMask)) {
80 xXFixesSelectionNotifyEvent ev = {
81 .type = XFixesEventBase + XFixesSelectionNotify,
82 .subtype = subtype,
83 .window = e->pWindow->drawable.id,
84 .owner = (subtype == XFixesSetSelectionOwnerNotify) ?
85 selection->window : 0,
86 .selection = e->selection,
87 .timestamp = currentTime.milliseconds,
88 .selectionTimestamp = selection->lastTimeChanged.milliseconds
89 };
90 WriteEventsToClient(e->pClient, 1, (xEvent *) &ev);
91 }
92 }
93 }
94
95 static Bool
96 CheckSelectionCallback(void)
97 {
98 if (selectionEvents) {
99 if (!SelectionCallbackRegistered) {
100 if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL))
101 return FALSE;
102 SelectionCallbackRegistered = TRUE;
103 }
104 }
105 else {
106 if (SelectionCallbackRegistered) {
107 DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL);
108 SelectionCallbackRegistered = FALSE;
109 }
110 }
111 return TRUE;
112 }
113
114 #define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\
115 XFixesSelectionWindowDestroyNotifyMask |\
116 XFixesSelectionClientCloseNotifyMask)
117
118 static int
119 XFixesSelectSelectionInput(ClientPtr pClient,
120 Atom selection, WindowPtr pWindow, CARD32 eventMask)
121 {
122 pointer val;
123 int rc;
124 SelectionEventPtr *prev, e;
125
126 rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess);
127 if (rc != Success)
128 return rc;
129
130 for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
131 if (e->selection == selection &&
132 e->pClient == pClient && e->pWindow == pWindow) {
133 break;
134 }
135 }
136 if (!eventMask) {
137 if (e) {
138 FreeResource(e->clientResource, 0);
139 }
140 return Success;
141 }
142 if (!e) {
143 e = (SelectionEventPtr) malloc(sizeof(SelectionEventRec));
144 if (!e)
145 return BadAlloc;
146
147 e->next = 0;
148 e->selection = selection;
149 e->pClient = pClient;
150 e->pWindow = pWindow;
151 e->clientResource = FakeClientID(pClient->index);
152
153 /*
154 * Add a resource hanging from the window to
155 * catch window destroy
156 */
157 rc = dixLookupResourceByType(&val, pWindow->drawable.id,
158 SelectionWindowType, serverClient,
159 DixGetAttrAccess);
160 if (rc != Success)
161 if (!AddResource(pWindow->drawable.id, SelectionWindowType,
162 (pointer) pWindow)) {
163 free(e);
164 return BadAlloc;
165 }
166
167 if (!AddResource(e->clientResource, SelectionClientType, (pointer) e))
168 return BadAlloc;
169
170 *prev = e;
171 if (!CheckSelectionCallback()) {
172 FreeResource(e->clientResource, 0);
173 return BadAlloc;
174 }
175 }
176 e->eventMask = eventMask;
177 return Success;
178 }
179
180 int
181 ProcXFixesSelectSelectionInput(ClientPtr client)
182 {
183 REQUEST(xXFixesSelectSelectionInputReq);
184 WindowPtr pWin;
185 int rc;
186
187 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
188 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
189 if (rc != Success)
190 return rc;
191 if (stuff->eventMask & ~SelectionAllEvents) {
192 client->errorValue = stuff->eventMask;
193 return BadValue;
194 }
195 return XFixesSelectSelectionInput(client, stuff->selection,
196 pWin, stuff->eventMask);
197 }
198
199 int
200 SProcXFixesSelectSelectionInput(ClientPtr client)
201 {
202 REQUEST(xXFixesSelectSelectionInputReq);
203
204 swaps(&stuff->length);
205 swapl(&stuff->window);
206 swapl(&stuff->selection);
207 swapl(&stuff->eventMask);
208 return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
209 }
210
211 void
212 SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,
213 xXFixesSelectionNotifyEvent * to)
214 {
215 to->type = from->type;
216 cpswaps(from->sequenceNumber, to->sequenceNumber);
217 cpswapl(from->window, to->window);
218 cpswapl(from->owner, to->owner);
219 cpswapl(from->selection, to->selection);
220 cpswapl(from->timestamp, to->timestamp);
221 cpswapl(from->selectionTimestamp, to->selectionTimestamp);
222 }
223
224 static int
225 SelectionFreeClient(pointer data, XID id)
226 {
227 SelectionEventPtr old = (SelectionEventPtr) data;
228 SelectionEventPtr *prev, e;
229
230 for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
231 if (e == old) {
232 *prev = e->next;
233 free(e);
234 CheckSelectionCallback();
235 break;
236 }
237 }
238 return 1;
239 }
240
241 static int
242 SelectionFreeWindow(pointer data, XID id)
243 {
244 WindowPtr pWindow = (WindowPtr) data;
245 SelectionEventPtr e, next;
246
247 for (e = selectionEvents; e; e = next) {
248 next = e->next;
249 if (e->pWindow == pWindow) {
250 FreeResource(e->clientResource, 0);
251 }
252 }
253 return 1;
254 }
255
256 Bool
257 XFixesSelectionInit(void)
258 {
259 SelectionClientType = CreateNewResourceType(SelectionFreeClient,
260 "XFixesSelectionClient");
261 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow,
262 "XFixesSelectionWindow");
263 return SelectionClientType && SelectionWindowType;
264 }