Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / selection.c
... / ...
CommitLineData
1/************************************************************
2
3Copyright 1987, 1989, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46
47#ifdef HAVE_DIX_CONFIG_H
48#include <dix-config.h>
49#endif
50
51#include "windowstr.h"
52#include "dixstruct.h"
53#include "dispatch.h"
54#include "selection.h"
55#include "xace.h"
56
57/*****************************************************************
58 * Selection Stuff
59 *
60 * dixLookupSelection
61 *
62 * Selections are global to the server. The list of selections should
63 * not be traversed directly. Instead, use the functions listed above.
64 *
65 *****************************************************************/
66
67Selection *CurrentSelections;
68CallbackListPtr SelectionCallback;
69
70int
71dixLookupSelection(Selection ** result, Atom selectionName,
72 ClientPtr client, Mask access_mode)
73{
74 Selection *pSel;
75 int rc = BadMatch;
76
77 client->errorValue = selectionName;
78
79 for (pSel = CurrentSelections; pSel; pSel = pSel->next)
80 if (pSel->selection == selectionName)
81 break;
82
83 if (pSel)
84 rc = XaceHookSelectionAccess(client, &pSel, access_mode);
85 *result = pSel;
86 return rc;
87}
88
89void
90InitSelections(void)
91{
92 Selection *pSel, *pNextSel;
93
94 pSel = CurrentSelections;
95 while (pSel) {
96 pNextSel = pSel->next;
97 dixFreeObjectWithPrivates(pSel, PRIVATE_SELECTION);
98 pSel = pNextSel;
99 }
100
101 CurrentSelections = NULL;
102}
103
104static _X_INLINE void
105CallSelectionCallback(Selection * pSel, ClientPtr client,
106 SelectionCallbackKind kind)
107{
108 SelectionInfoRec info = { pSel, client, kind };
109 CallCallbacks(&SelectionCallback, &info);
110}
111
112void
113DeleteWindowFromAnySelections(WindowPtr pWin)
114{
115 Selection *pSel;
116
117 for (pSel = CurrentSelections; pSel; pSel = pSel->next)
118 if (pSel->pWin == pWin) {
119 CallSelectionCallback(pSel, NULL, SelectionWindowDestroy);
120
121 pSel->pWin = (WindowPtr) NULL;
122 pSel->window = None;
123 pSel->client = NullClient;
124 }
125}
126
127void
128DeleteClientFromAnySelections(ClientPtr client)
129{
130 Selection *pSel;
131
132 for (pSel = CurrentSelections; pSel; pSel = pSel->next)
133 if (pSel->client == client) {
134 CallSelectionCallback(pSel, NULL, SelectionClientClose);
135
136 pSel->pWin = (WindowPtr) NULL;
137 pSel->window = None;
138 pSel->client = NullClient;
139 }
140}
141
142int
143ProcSetSelectionOwner(ClientPtr client)
144{
145 WindowPtr pWin = NULL;
146 TimeStamp time;
147 Selection *pSel;
148 int rc;
149
150 REQUEST(xSetSelectionOwnerReq);
151 REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
152
153 UpdateCurrentTime();
154 time = ClientTimeToServerTime(stuff->time);
155
156 /* If the client's time stamp is in the future relative to the server's
157 time stamp, do not set the selection, just return success. */
158 if (CompareTimeStamps(time, currentTime) == LATER)
159 return Success;
160
161 if (stuff->window != None) {
162 rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess);
163 if (rc != Success)
164 return rc;
165 }
166 if (!ValidAtom(stuff->selection)) {
167 client->errorValue = stuff->selection;
168 return BadAtom;
169 }
170
171 /*
172 * First, see if the selection is already set...
173 */
174 rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess);
175
176 if (rc == Success) {
177 /* If the timestamp in client's request is in the past relative
178 to the time stamp indicating the last time the owner of the
179 selection was set, do not set the selection, just return
180 success. */
181 if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER)
182 return Success;
183 if (pSel->client && (!pWin || (pSel->client != client))) {
184 xEvent event = {
185 .u.selectionClear.time = time.milliseconds,
186 .u.selectionClear.window = pSel->window,
187 .u.selectionClear.atom = pSel->selection
188 };
189 event.u.u.type = SelectionClear;
190 WriteEventsToClient(pSel->client, 1, &event);
191 }
192 }
193 else if (rc == BadMatch) {
194 /*
195 * It doesn't exist, so add it...
196 */
197 pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION);
198 if (!pSel)
199 return BadAlloc;
200
201 pSel->selection = stuff->selection;
202
203 /* security creation/labeling check */
204 rc = XaceHookSelectionAccess(client, &pSel,
205 DixCreateAccess | DixSetAttrAccess);
206 if (rc != Success) {
207 free(pSel);
208 return rc;
209 }
210
211 pSel->next = CurrentSelections;
212 CurrentSelections = pSel;
213 }
214 else
215 return rc;
216
217 pSel->lastTimeChanged = time;
218 pSel->window = stuff->window;
219 pSel->pWin = pWin;
220 pSel->client = (pWin ? client : NullClient);
221
222 CallSelectionCallback(pSel, client, SelectionSetOwner);
223 return Success;
224}
225
226int
227ProcGetSelectionOwner(ClientPtr client)
228{
229 int rc;
230 Selection *pSel;
231 xGetSelectionOwnerReply reply;
232
233 REQUEST(xResourceReq);
234 REQUEST_SIZE_MATCH(xResourceReq);
235
236 if (!ValidAtom(stuff->id)) {
237 client->errorValue = stuff->id;
238 return BadAtom;
239 }
240
241 reply = (xGetSelectionOwnerReply) {
242 .type = X_Reply,
243 .sequenceNumber = client->sequence,
244 .length = 0,
245 };
246
247 rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess);
248 if (rc == Success)
249 reply.owner = pSel->window;
250 else if (rc == BadMatch)
251 reply.owner = None;
252 else
253 return rc;
254
255 WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
256 return Success;
257}
258
259int
260ProcConvertSelection(ClientPtr client)
261{
262 Bool paramsOkay;
263 xEvent event;
264 WindowPtr pWin;
265 Selection *pSel;
266 int rc;
267
268 REQUEST(xConvertSelectionReq);
269 REQUEST_SIZE_MATCH(xConvertSelectionReq);
270
271 rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess);
272 if (rc != Success)
273 return rc;
274
275 paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target);
276 paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property);
277 if (!paramsOkay) {
278 client->errorValue = stuff->property;
279 return BadAtom;
280 }
281
282 rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess);
283
284 memset(&event, 0, sizeof(xEvent));
285 if (rc != Success && rc != BadMatch)
286 return rc;
287 else if (rc == Success && pSel->window != None) {
288 event.u.u.type = SelectionRequest;
289 event.u.selectionRequest.owner = pSel->window;
290 event.u.selectionRequest.time = stuff->time;
291 event.u.selectionRequest.requestor = stuff->requestor;
292 event.u.selectionRequest.selection = stuff->selection;
293 event.u.selectionRequest.target = stuff->target;
294 event.u.selectionRequest.property = stuff->property;
295 if (pSel->client && pSel->client != serverClient &&
296 !pSel->client->clientGone) {
297 WriteEventsToClient(pSel->client, 1, &event);
298 return Success;
299 }
300 }
301
302 event.u.u.type = SelectionNotify;
303 event.u.selectionNotify.time = stuff->time;
304 event.u.selectionNotify.requestor = stuff->requestor;
305 event.u.selectionNotify.selection = stuff->selection;
306 event.u.selectionNotify.target = stuff->target;
307 event.u.selectionNotify.property = None;
308 WriteEventsToClient(client, 1, &event);
309 return Success;
310}