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
XFixesSelectionCallback(CallbackListPtr * callbacks,void * data,void * args)54 XFixesSelectionCallback(CallbackListPtr *callbacks, void *data, void *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 UpdateCurrentTimeIf();
79 for (e = selectionEvents; e; e = e->next) {
80 if (e->selection == selection->selection && (e->eventMask & eventMask)) {
81 xXFixesSelectionNotifyEvent ev = {
82 .type = XFixesEventBase + XFixesSelectionNotify,
83 .subtype = subtype,
84 .window = e->pWindow->drawable.id,
85 .owner = (subtype == XFixesSetSelectionOwnerNotify) ?
86 selection->window : 0,
87 .selection = e->selection,
88 .timestamp = currentTime.milliseconds,
89 .selectionTimestamp = selection->lastTimeChanged.milliseconds
90 };
91 WriteEventsToClient(e->pClient, 1, (xEvent *) &ev);
92 }
93 }
94 }
95
96 static Bool
CheckSelectionCallback(void)97 CheckSelectionCallback(void)
98 {
99 if (selectionEvents) {
100 if (!SelectionCallbackRegistered) {
101 if (!AddCallback(&SelectionCallback, XFixesSelectionCallback, NULL))
102 return FALSE;
103 SelectionCallbackRegistered = TRUE;
104 }
105 }
106 else {
107 if (SelectionCallbackRegistered) {
108 DeleteCallback(&SelectionCallback, XFixesSelectionCallback, NULL);
109 SelectionCallbackRegistered = FALSE;
110 }
111 }
112 return TRUE;
113 }
114
115 #define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\
116 XFixesSelectionWindowDestroyNotifyMask |\
117 XFixesSelectionClientCloseNotifyMask)
118
119 static int
XFixesSelectSelectionInput(ClientPtr pClient,Atom selection,WindowPtr pWindow,CARD32 eventMask)120 XFixesSelectSelectionInput(ClientPtr pClient,
121 Atom selection, WindowPtr pWindow, CARD32 eventMask)
122 {
123 void *val;
124 int rc;
125 SelectionEventPtr *prev, e;
126
127 rc = XaceHook(XACE_SELECTION_ACCESS, pClient, selection, DixGetAttrAccess);
128 if (rc != Success)
129 return rc;
130
131 for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
132 if (e->selection == selection &&
133 e->pClient == pClient && e->pWindow == pWindow) {
134 break;
135 }
136 }
137 if (!eventMask) {
138 if (e) {
139 FreeResource(e->clientResource, 0);
140 }
141 return Success;
142 }
143 if (!e) {
144 e = (SelectionEventPtr) malloc(sizeof(SelectionEventRec));
145 if (!e)
146 return BadAlloc;
147
148 e->next = 0;
149 e->selection = selection;
150 e->pClient = pClient;
151 e->pWindow = pWindow;
152 e->clientResource = FakeClientID(pClient->index);
153
154 /*
155 * Add a resource hanging from the window to
156 * catch window destroy
157 */
158 rc = dixLookupResourceByType(&val, pWindow->drawable.id,
159 SelectionWindowType, serverClient,
160 DixGetAttrAccess);
161 if (rc != Success)
162 if (!AddResource(pWindow->drawable.id, SelectionWindowType,
163 (void *) pWindow)) {
164 free(e);
165 return BadAlloc;
166 }
167
168 if (!AddResource(e->clientResource, SelectionClientType, (void *) e))
169 return BadAlloc;
170
171 *prev = e;
172 if (!CheckSelectionCallback()) {
173 FreeResource(e->clientResource, 0);
174 return BadAlloc;
175 }
176 }
177 e->eventMask = eventMask;
178 return Success;
179 }
180
181 int
ProcXFixesSelectSelectionInput(ClientPtr client)182 ProcXFixesSelectSelectionInput(ClientPtr client)
183 {
184 REQUEST(xXFixesSelectSelectionInputReq);
185 WindowPtr pWin;
186 int rc;
187
188 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
189 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
190 if (rc != Success)
191 return rc;
192 if (stuff->eventMask & ~SelectionAllEvents) {
193 client->errorValue = stuff->eventMask;
194 return BadValue;
195 }
196 return XFixesSelectSelectionInput(client, stuff->selection,
197 pWin, stuff->eventMask);
198 }
199
200 int _X_COLD
SProcXFixesSelectSelectionInput(ClientPtr client)201 SProcXFixesSelectSelectionInput(ClientPtr client)
202 {
203 REQUEST(xXFixesSelectSelectionInputReq);
204
205 REQUEST_SIZE_MATCH(xXFixesSelectSelectionInputReq);
206 swaps(&stuff->length);
207 swapl(&stuff->window);
208 swapl(&stuff->selection);
209 swapl(&stuff->eventMask);
210 return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
211 }
212
213 void _X_COLD
SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,xXFixesSelectionNotifyEvent * to)214 SXFixesSelectionNotifyEvent(xXFixesSelectionNotifyEvent * from,
215 xXFixesSelectionNotifyEvent * to)
216 {
217 to->type = from->type;
218 cpswaps(from->sequenceNumber, to->sequenceNumber);
219 cpswapl(from->window, to->window);
220 cpswapl(from->owner, to->owner);
221 cpswapl(from->selection, to->selection);
222 cpswapl(from->timestamp, to->timestamp);
223 cpswapl(from->selectionTimestamp, to->selectionTimestamp);
224 }
225
226 static int
SelectionFreeClient(void * data,XID id)227 SelectionFreeClient(void *data, XID id)
228 {
229 SelectionEventPtr old = (SelectionEventPtr) data;
230 SelectionEventPtr *prev, e;
231
232 for (prev = &selectionEvents; (e = *prev); prev = &e->next) {
233 if (e == old) {
234 *prev = e->next;
235 free(e);
236 CheckSelectionCallback();
237 break;
238 }
239 }
240 return 1;
241 }
242
243 static int
SelectionFreeWindow(void * data,XID id)244 SelectionFreeWindow(void *data, XID id)
245 {
246 WindowPtr pWindow = (WindowPtr) data;
247 SelectionEventPtr e, next;
248
249 for (e = selectionEvents; e; e = next) {
250 next = e->next;
251 if (e->pWindow == pWindow) {
252 FreeResource(e->clientResource, 0);
253 }
254 }
255 return 1;
256 }
257
258 Bool
XFixesSelectionInit(void)259 XFixesSelectionInit(void)
260 {
261 SelectionClientType = CreateNewResourceType(SelectionFreeClient,
262 "XFixesSelectionClient");
263 SelectionWindowType = CreateNewResourceType(SelectionFreeWindow,
264 "XFixesSelectionWindow");
265 return SelectionClientType && SelectionWindowType;
266 }
267