1706f2543Smrg/************************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1989, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg********************************************************/
47706f2543Smrg
48706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
49706f2543Smrg#include <dix-config.h>
50706f2543Smrg#endif
51706f2543Smrg
52706f2543Smrg#include "windowstr.h"
53706f2543Smrg#include "dixstruct.h"
54706f2543Smrg#include "dispatch.h"
55706f2543Smrg#include "selection.h"
56706f2543Smrg#include "xace.h"
57706f2543Smrg
58706f2543Smrg/*****************************************************************
59706f2543Smrg * Selection Stuff
60706f2543Smrg *
61706f2543Smrg *    dixLookupSelection
62706f2543Smrg *
63706f2543Smrg *   Selections are global to the server.  The list of selections should
64706f2543Smrg *   not be traversed directly.  Instead, use the functions listed above.
65706f2543Smrg *
66706f2543Smrg *****************************************************************/
67706f2543Smrg
68706f2543SmrgSelection *CurrentSelections;
69706f2543SmrgCallbackListPtr SelectionCallback;
70706f2543Smrg
71706f2543Smrgint
72706f2543SmrgdixLookupSelection(Selection **result, Atom selectionName,
73706f2543Smrg		   ClientPtr client, Mask access_mode)
74706f2543Smrg{
75706f2543Smrg    Selection *pSel;
76706f2543Smrg    int rc = BadMatch;
77706f2543Smrg    client->errorValue = selectionName;
78706f2543Smrg
79706f2543Smrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
80706f2543Smrg	if (pSel->selection == selectionName)
81706f2543Smrg	    break;
82706f2543Smrg
83706f2543Smrg    if (pSel)
84706f2543Smrg	rc = XaceHookSelectionAccess(client, &pSel, access_mode);
85706f2543Smrg    *result = pSel;
86706f2543Smrg    return rc;
87706f2543Smrg}
88706f2543Smrg
89706f2543Smrgvoid
90706f2543SmrgInitSelections(void)
91706f2543Smrg{
92706f2543Smrg    Selection *pSel, *pNextSel;
93706f2543Smrg
94706f2543Smrg    pSel = CurrentSelections;
95706f2543Smrg    while (pSel) {
96706f2543Smrg	pNextSel = pSel->next;
97706f2543Smrg	dixFreeObjectWithPrivates(pSel, PRIVATE_SELECTION);
98706f2543Smrg	pSel = pNextSel;
99706f2543Smrg    }
100706f2543Smrg
101706f2543Smrg    CurrentSelections = NULL;
102706f2543Smrg}
103706f2543Smrg
104706f2543Smrgstatic _X_INLINE void
105706f2543SmrgCallSelectionCallback(Selection *pSel, ClientPtr client,
106706f2543Smrg		      SelectionCallbackKind kind)
107706f2543Smrg{
108706f2543Smrg    SelectionInfoRec info = { pSel, client, kind };
109706f2543Smrg    CallCallbacks(&SelectionCallback, &info);
110706f2543Smrg}
111706f2543Smrg
112706f2543Smrgvoid
113706f2543SmrgDeleteWindowFromAnySelections(WindowPtr pWin)
114706f2543Smrg{
115706f2543Smrg    Selection *pSel;
116706f2543Smrg
117706f2543Smrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
118706f2543Smrg        if (pSel->pWin == pWin) {
119706f2543Smrg	    CallSelectionCallback(pSel, NULL, SelectionWindowDestroy);
120706f2543Smrg
121706f2543Smrg            pSel->pWin = (WindowPtr)NULL;
122706f2543Smrg            pSel->window = None;
123706f2543Smrg	    pSel->client = NullClient;
124706f2543Smrg	}
125706f2543Smrg}
126706f2543Smrg
127706f2543Smrgvoid
128706f2543SmrgDeleteClientFromAnySelections(ClientPtr client)
129706f2543Smrg{
130706f2543Smrg    Selection *pSel;
131706f2543Smrg
132706f2543Smrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
133706f2543Smrg        if (pSel->client == client) {
134706f2543Smrg	    CallSelectionCallback(pSel, NULL, SelectionClientClose);
135706f2543Smrg
136706f2543Smrg            pSel->pWin = (WindowPtr)NULL;
137706f2543Smrg            pSel->window = None;
138706f2543Smrg	    pSel->client = NullClient;
139706f2543Smrg	}
140706f2543Smrg}
141706f2543Smrg
142706f2543Smrgint
143706f2543SmrgProcSetSelectionOwner(ClientPtr client)
144706f2543Smrg{
145706f2543Smrg    WindowPtr pWin = NULL;
146706f2543Smrg    TimeStamp time;
147706f2543Smrg    Selection *pSel;
148706f2543Smrg    int rc;
149706f2543Smrg
150706f2543Smrg    REQUEST(xSetSelectionOwnerReq);
151706f2543Smrg    REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
152706f2543Smrg
153706f2543Smrg    UpdateCurrentTime();
154706f2543Smrg    time = ClientTimeToServerTime(stuff->time);
155706f2543Smrg
156706f2543Smrg    /* If the client's time stamp is in the future relative to the server's
157706f2543Smrg	time stamp, do not set the selection, just return success. */
158706f2543Smrg    if (CompareTimeStamps(time, currentTime) == LATER)
159706f2543Smrg    	return Success;
160706f2543Smrg
161706f2543Smrg    if (stuff->window != None) {
162706f2543Smrg	rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess);
163706f2543Smrg        if (rc != Success)
164706f2543Smrg            return rc;
165706f2543Smrg    }
166706f2543Smrg    if (!ValidAtom(stuff->selection)) {
167706f2543Smrg	client->errorValue = stuff->selection;
168706f2543Smrg        return BadAtom;
169706f2543Smrg    }
170706f2543Smrg
171706f2543Smrg    /*
172706f2543Smrg     * First, see if the selection is already set...
173706f2543Smrg     */
174706f2543Smrg    rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess);
175706f2543Smrg
176706f2543Smrg    if (rc == Success) {
177706f2543Smrg	xEvent event;
178706f2543Smrg
179706f2543Smrg	/* If the timestamp in client's request is in the past relative
180706f2543Smrg	   to the time stamp indicating the last time the owner of the
181706f2543Smrg	   selection was set, do not set the selection, just return
182706f2543Smrg	   success. */
183706f2543Smrg	if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER)
184706f2543Smrg	    return Success;
185706f2543Smrg	if (pSel->client && (!pWin || (pSel->client != client)))
186706f2543Smrg	{
187706f2543Smrg	    event.u.u.type = SelectionClear;
188706f2543Smrg	    event.u.selectionClear.time = time.milliseconds;
189706f2543Smrg	    event.u.selectionClear.window = pSel->window;
190706f2543Smrg	    event.u.selectionClear.atom = pSel->selection;
191706f2543Smrg	    WriteEventsToClient(pSel->client, 1, &event);
192706f2543Smrg	}
193706f2543Smrg    }
194706f2543Smrg    else if (rc == BadMatch)
195706f2543Smrg    {
196706f2543Smrg	/*
197706f2543Smrg	 * It doesn't exist, so add it...
198706f2543Smrg	 */
199706f2543Smrg	pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION);
200706f2543Smrg	if (!pSel)
201706f2543Smrg	    return BadAlloc;
202706f2543Smrg
203706f2543Smrg	pSel->selection = stuff->selection;
204706f2543Smrg
205706f2543Smrg	/* security creation/labeling check */
206706f2543Smrg	rc = XaceHookSelectionAccess(client, &pSel,
207706f2543Smrg				     DixCreateAccess|DixSetAttrAccess);
208706f2543Smrg	if (rc != Success) {
209706f2543Smrg	    free(pSel);
210706f2543Smrg	    return rc;
211706f2543Smrg	}
212706f2543Smrg
213706f2543Smrg	pSel->next = CurrentSelections;
214706f2543Smrg	CurrentSelections = pSel;
215706f2543Smrg    }
216706f2543Smrg    else
217706f2543Smrg	return rc;
218706f2543Smrg
219706f2543Smrg    pSel->lastTimeChanged = time;
220706f2543Smrg    pSel->window = stuff->window;
221706f2543Smrg    pSel->pWin = pWin;
222706f2543Smrg    pSel->client = (pWin ? client : NullClient);
223706f2543Smrg
224706f2543Smrg    CallSelectionCallback(pSel, client, SelectionSetOwner);
225706f2543Smrg    return Success;
226706f2543Smrg}
227706f2543Smrg
228706f2543Smrgint
229706f2543SmrgProcGetSelectionOwner(ClientPtr client)
230706f2543Smrg{
231706f2543Smrg    int rc;
232706f2543Smrg    Selection *pSel;
233706f2543Smrg    xGetSelectionOwnerReply reply;
234706f2543Smrg
235706f2543Smrg    REQUEST(xResourceReq);
236706f2543Smrg    REQUEST_SIZE_MATCH(xResourceReq);
237706f2543Smrg
238706f2543Smrg    if (!ValidAtom(stuff->id)) {
239706f2543Smrg	client->errorValue = stuff->id;
240706f2543Smrg        return BadAtom;
241706f2543Smrg    }
242706f2543Smrg
243706f2543Smrg    memset(&reply, 0, sizeof(xGetSelectionOwnerReply));
244706f2543Smrg    reply.type = X_Reply;
245706f2543Smrg    reply.length = 0;
246706f2543Smrg    reply.sequenceNumber = client->sequence;
247706f2543Smrg
248706f2543Smrg    rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess);
249706f2543Smrg    if (rc == Success)
250706f2543Smrg	reply.owner = pSel->window;
251706f2543Smrg    else if (rc == BadMatch)
252706f2543Smrg	reply.owner = None;
253706f2543Smrg    else
254706f2543Smrg	return rc;
255706f2543Smrg
256706f2543Smrg    WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
257706f2543Smrg    return Success;
258706f2543Smrg}
259706f2543Smrg
260706f2543Smrgint
261706f2543SmrgProcConvertSelection(ClientPtr client)
262706f2543Smrg{
263706f2543Smrg    Bool paramsOkay;
264706f2543Smrg    xEvent event;
265706f2543Smrg    WindowPtr pWin;
266706f2543Smrg    Selection *pSel;
267706f2543Smrg    int rc;
268706f2543Smrg
269706f2543Smrg    REQUEST(xConvertSelectionReq);
270706f2543Smrg    REQUEST_SIZE_MATCH(xConvertSelectionReq);
271706f2543Smrg
272706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess);
273706f2543Smrg    if (rc != Success)
274706f2543Smrg        return rc;
275706f2543Smrg
276706f2543Smrg    paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target);
277706f2543Smrg    paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property);
278706f2543Smrg    if (!paramsOkay) {
279706f2543Smrg	client->errorValue = stuff->property;
280706f2543Smrg        return BadAtom;
281706f2543Smrg    }
282706f2543Smrg
283706f2543Smrg    rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess);
284706f2543Smrg
285706f2543Smrg    memset(&event, 0, sizeof(xEvent));
286706f2543Smrg    if (rc != Success && rc != BadMatch)
287706f2543Smrg	return rc;
288706f2543Smrg    else if (rc == Success && pSel->window != None) {
289706f2543Smrg	event.u.u.type = SelectionRequest;
290706f2543Smrg	event.u.selectionRequest.owner = pSel->window;
291706f2543Smrg	event.u.selectionRequest.time = stuff->time;
292706f2543Smrg	event.u.selectionRequest.requestor = stuff->requestor;
293706f2543Smrg	event.u.selectionRequest.selection = stuff->selection;
294706f2543Smrg	event.u.selectionRequest.target = stuff->target;
295706f2543Smrg	event.u.selectionRequest.property = stuff->property;
296706f2543Smrg	if (pSel->client && pSel->client != serverClient && !pSel->client->clientGone)
297706f2543Smrg	{
298706f2543Smrg	    WriteEventsToClient(pSel->client, 1, &event);
299706f2543Smrg	    return Success;
300706f2543Smrg	}
301706f2543Smrg    }
302706f2543Smrg
303706f2543Smrg    event.u.u.type = SelectionNotify;
304706f2543Smrg    event.u.selectionNotify.time = stuff->time;
305706f2543Smrg    event.u.selectionNotify.requestor = stuff->requestor;
306706f2543Smrg    event.u.selectionNotify.selection = stuff->selection;
307706f2543Smrg    event.u.selectionNotify.target = stuff->target;
308706f2543Smrg    event.u.selectionNotify.property = None;
309706f2543Smrg    WriteEventsToClient(client, 1, &event);
310706f2543Smrg    return Success;
311706f2543Smrg}
312