xref: /OK3568_Linux_fs/external/xserver/xfixes/select.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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