14642e01fSmrg/************************************************************
24642e01fSmrg
34642e01fSmrgCopyright 1987, 1989, 1998  The Open Group
44642e01fSmrg
54642e01fSmrgPermission to use, copy, modify, distribute, and sell this software and its
64642e01fSmrgdocumentation for any purpose is hereby granted without fee, provided that
74642e01fSmrgthe above copyright notice appear in all copies and that both that
84642e01fSmrgcopyright notice and this permission notice appear in supporting
94642e01fSmrgdocumentation.
104642e01fSmrg
114642e01fSmrgThe above copyright notice and this permission notice shall be included in
124642e01fSmrgall copies or substantial portions of the Software.
134642e01fSmrg
144642e01fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154642e01fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164642e01fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
174642e01fSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
184642e01fSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
194642e01fSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
204642e01fSmrg
214642e01fSmrgExcept as contained in this notice, the name of The Open Group shall not be
224642e01fSmrgused in advertising or otherwise to promote the sale, use or other dealings
234642e01fSmrgin this Software without prior written authorization from The Open Group.
244642e01fSmrg
254642e01fSmrgCopyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
264642e01fSmrg
274642e01fSmrg                        All Rights Reserved
284642e01fSmrg
2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
314642e01fSmrgprovided that the above copyright notice appear in all copies and that
3235c4bbdfSmrgboth that copyright notice and this permission notice appear in
334642e01fSmrgsupporting documentation, and that the name of Digital not be
344642e01fSmrgused in advertising or publicity pertaining to distribution of the
3535c4bbdfSmrgsoftware without specific, written prior permission.
364642e01fSmrg
374642e01fSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
384642e01fSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
394642e01fSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
404642e01fSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
414642e01fSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
424642e01fSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
434642e01fSmrgSOFTWARE.
444642e01fSmrg
454642e01fSmrg********************************************************/
464642e01fSmrg
474642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
484642e01fSmrg#include <dix-config.h>
494642e01fSmrg#endif
504642e01fSmrg
514642e01fSmrg#include "windowstr.h"
524642e01fSmrg#include "dixstruct.h"
534642e01fSmrg#include "dispatch.h"
544642e01fSmrg#include "selection.h"
554642e01fSmrg#include "xace.h"
564642e01fSmrg
574642e01fSmrg/*****************************************************************
584642e01fSmrg * Selection Stuff
594642e01fSmrg *
604642e01fSmrg *    dixLookupSelection
614642e01fSmrg *
624642e01fSmrg *   Selections are global to the server.  The list of selections should
634642e01fSmrg *   not be traversed directly.  Instead, use the functions listed above.
644642e01fSmrg *
654642e01fSmrg *****************************************************************/
664642e01fSmrg
676747b715SmrgSelection *CurrentSelections;
684642e01fSmrgCallbackListPtr SelectionCallback;
694642e01fSmrg
706747b715Smrgint
7135c4bbdfSmrgdixLookupSelection(Selection ** result, Atom selectionName,
7235c4bbdfSmrg                   ClientPtr client, Mask access_mode)
734642e01fSmrg{
744642e01fSmrg    Selection *pSel;
754642e01fSmrg    int rc = BadMatch;
7635c4bbdfSmrg
774642e01fSmrg    client->errorValue = selectionName;
784642e01fSmrg
794642e01fSmrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
8035c4bbdfSmrg        if (pSel->selection == selectionName)
8135c4bbdfSmrg            break;
824642e01fSmrg
834642e01fSmrg    if (pSel)
8435c4bbdfSmrg        rc = XaceHookSelectionAccess(client, &pSel, access_mode);
854642e01fSmrg    *result = pSel;
864642e01fSmrg    return rc;
874642e01fSmrg}
884642e01fSmrg
894642e01fSmrgvoid
904642e01fSmrgInitSelections(void)
914642e01fSmrg{
924642e01fSmrg    Selection *pSel, *pNextSel;
934642e01fSmrg
944642e01fSmrg    pSel = CurrentSelections;
954642e01fSmrg    while (pSel) {
9635c4bbdfSmrg        pNextSel = pSel->next;
9735c4bbdfSmrg        dixFreeObjectWithPrivates(pSel, PRIVATE_SELECTION);
9835c4bbdfSmrg        pSel = pNextSel;
994642e01fSmrg    }
1004642e01fSmrg
1014642e01fSmrg    CurrentSelections = NULL;
1024642e01fSmrg}
1034642e01fSmrg
1044642e01fSmrgstatic _X_INLINE void
10535c4bbdfSmrgCallSelectionCallback(Selection * pSel, ClientPtr client,
10635c4bbdfSmrg                      SelectionCallbackKind kind)
1074642e01fSmrg{
1084642e01fSmrg    SelectionInfoRec info = { pSel, client, kind };
1094642e01fSmrg    CallCallbacks(&SelectionCallback, &info);
1104642e01fSmrg}
1114642e01fSmrg
1124642e01fSmrgvoid
1134642e01fSmrgDeleteWindowFromAnySelections(WindowPtr pWin)
1144642e01fSmrg{
1154642e01fSmrg    Selection *pSel;
1164642e01fSmrg
1174642e01fSmrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
1184642e01fSmrg        if (pSel->pWin == pWin) {
11935c4bbdfSmrg            CallSelectionCallback(pSel, NULL, SelectionWindowDestroy);
1204642e01fSmrg
12135c4bbdfSmrg            pSel->pWin = (WindowPtr) NULL;
1224642e01fSmrg            pSel->window = None;
12335c4bbdfSmrg            pSel->client = NullClient;
12435c4bbdfSmrg        }
1254642e01fSmrg}
1264642e01fSmrg
1274642e01fSmrgvoid
1284642e01fSmrgDeleteClientFromAnySelections(ClientPtr client)
1294642e01fSmrg{
1304642e01fSmrg    Selection *pSel;
1314642e01fSmrg
1324642e01fSmrg    for (pSel = CurrentSelections; pSel; pSel = pSel->next)
1334642e01fSmrg        if (pSel->client == client) {
13435c4bbdfSmrg            CallSelectionCallback(pSel, NULL, SelectionClientClose);
1354642e01fSmrg
13635c4bbdfSmrg            pSel->pWin = (WindowPtr) NULL;
1374642e01fSmrg            pSel->window = None;
13835c4bbdfSmrg            pSel->client = NullClient;
13935c4bbdfSmrg        }
1404642e01fSmrg}
1414642e01fSmrg
1424642e01fSmrgint
1434642e01fSmrgProcSetSelectionOwner(ClientPtr client)
1444642e01fSmrg{
1454642e01fSmrg    WindowPtr pWin = NULL;
1464642e01fSmrg    TimeStamp time;
1474642e01fSmrg    Selection *pSel;
1484642e01fSmrg    int rc;
1494642e01fSmrg
1504642e01fSmrg    REQUEST(xSetSelectionOwnerReq);
1514642e01fSmrg    REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
1524642e01fSmrg
1534642e01fSmrg    UpdateCurrentTime();
1544642e01fSmrg    time = ClientTimeToServerTime(stuff->time);
1554642e01fSmrg
1564642e01fSmrg    /* If the client's time stamp is in the future relative to the server's
15735c4bbdfSmrg       time stamp, do not set the selection, just return success. */
1584642e01fSmrg    if (CompareTimeStamps(time, currentTime) == LATER)
15935c4bbdfSmrg        return Success;
1604642e01fSmrg
1614642e01fSmrg    if (stuff->window != None) {
16235c4bbdfSmrg        rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess);
1634642e01fSmrg        if (rc != Success)
1644642e01fSmrg            return rc;
1654642e01fSmrg    }
1664642e01fSmrg    if (!ValidAtom(stuff->selection)) {
16735c4bbdfSmrg        client->errorValue = stuff->selection;
1684642e01fSmrg        return BadAtom;
1694642e01fSmrg    }
1704642e01fSmrg
1714642e01fSmrg    /*
1724642e01fSmrg     * First, see if the selection is already set...
1734642e01fSmrg     */
1744642e01fSmrg    rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess);
1754642e01fSmrg
1764642e01fSmrg    if (rc == Success) {
17735c4bbdfSmrg        /* If the timestamp in client's request is in the past relative
17835c4bbdfSmrg           to the time stamp indicating the last time the owner of the
17935c4bbdfSmrg           selection was set, do not set the selection, just return
18035c4bbdfSmrg           success. */
18135c4bbdfSmrg        if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER)
18235c4bbdfSmrg            return Success;
18335c4bbdfSmrg        if (pSel->client && (!pWin || (pSel->client != client))) {
18435c4bbdfSmrg            xEvent event = {
18535c4bbdfSmrg                .u.selectionClear.time = time.milliseconds,
18635c4bbdfSmrg                .u.selectionClear.window = pSel->window,
18735c4bbdfSmrg                .u.selectionClear.atom = pSel->selection
18835c4bbdfSmrg            };
18935c4bbdfSmrg            event.u.u.type = SelectionClear;
19035c4bbdfSmrg            WriteEventsToClient(pSel->client, 1, &event);
19135c4bbdfSmrg        }
1924642e01fSmrg    }
19335c4bbdfSmrg    else if (rc == BadMatch) {
19435c4bbdfSmrg        /*
19535c4bbdfSmrg         * It doesn't exist, so add it...
19635c4bbdfSmrg         */
19735c4bbdfSmrg        pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION);
19835c4bbdfSmrg        if (!pSel)
19935c4bbdfSmrg            return BadAlloc;
20035c4bbdfSmrg
20135c4bbdfSmrg        pSel->selection = stuff->selection;
20235c4bbdfSmrg
20335c4bbdfSmrg        /* security creation/labeling check */
20435c4bbdfSmrg        rc = XaceHookSelectionAccess(client, &pSel,
20535c4bbdfSmrg                                     DixCreateAccess | DixSetAttrAccess);
20635c4bbdfSmrg        if (rc != Success) {
20735c4bbdfSmrg            free(pSel);
20835c4bbdfSmrg            return rc;
20935c4bbdfSmrg        }
21035c4bbdfSmrg
21135c4bbdfSmrg        pSel->next = CurrentSelections;
21235c4bbdfSmrg        CurrentSelections = pSel;
2134642e01fSmrg    }
2144642e01fSmrg    else
21535c4bbdfSmrg        return rc;
2164642e01fSmrg
2174642e01fSmrg    pSel->lastTimeChanged = time;
2184642e01fSmrg    pSel->window = stuff->window;
2194642e01fSmrg    pSel->pWin = pWin;
2204642e01fSmrg    pSel->client = (pWin ? client : NullClient);
2214642e01fSmrg
2224642e01fSmrg    CallSelectionCallback(pSel, client, SelectionSetOwner);
2236747b715Smrg    return Success;
2244642e01fSmrg}
2254642e01fSmrg
2264642e01fSmrgint
2274642e01fSmrgProcGetSelectionOwner(ClientPtr client)
2284642e01fSmrg{
2294642e01fSmrg    int rc;
2304642e01fSmrg    Selection *pSel;
2314642e01fSmrg    xGetSelectionOwnerReply reply;
2324642e01fSmrg
2334642e01fSmrg    REQUEST(xResourceReq);
2344642e01fSmrg    REQUEST_SIZE_MATCH(xResourceReq);
2354642e01fSmrg
2364642e01fSmrg    if (!ValidAtom(stuff->id)) {
23735c4bbdfSmrg        client->errorValue = stuff->id;
2384642e01fSmrg        return BadAtom;
2394642e01fSmrg    }
2404642e01fSmrg
24135c4bbdfSmrg    reply = (xGetSelectionOwnerReply) {
24235c4bbdfSmrg        .type = X_Reply,
24335c4bbdfSmrg        .sequenceNumber = client->sequence,
24435c4bbdfSmrg        .length = 0,
24535c4bbdfSmrg    };
2464642e01fSmrg
2474642e01fSmrg    rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess);
2484642e01fSmrg    if (rc == Success)
24935c4bbdfSmrg        reply.owner = pSel->window;
2504642e01fSmrg    else if (rc == BadMatch)
25135c4bbdfSmrg        reply.owner = None;
2524642e01fSmrg    else
25335c4bbdfSmrg        return rc;
2544642e01fSmrg
2554642e01fSmrg    WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply);
2566747b715Smrg    return Success;
2574642e01fSmrg}
2584642e01fSmrg
2594642e01fSmrgint
2604642e01fSmrgProcConvertSelection(ClientPtr client)
2614642e01fSmrg{
2624642e01fSmrg    Bool paramsOkay;
2634642e01fSmrg    xEvent event;
2644642e01fSmrg    WindowPtr pWin;
2654642e01fSmrg    Selection *pSel;
2664642e01fSmrg    int rc;
2674642e01fSmrg
2684642e01fSmrg    REQUEST(xConvertSelectionReq);
2694642e01fSmrg    REQUEST_SIZE_MATCH(xConvertSelectionReq);
2704642e01fSmrg
2714642e01fSmrg    rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess);
2724642e01fSmrg    if (rc != Success)
2734642e01fSmrg        return rc;
2744642e01fSmrg
2754642e01fSmrg    paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target);
2764642e01fSmrg    paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property);
2774642e01fSmrg    if (!paramsOkay) {
27835c4bbdfSmrg        client->errorValue = stuff->property;
2794642e01fSmrg        return BadAtom;
2804642e01fSmrg    }
2814642e01fSmrg
2821b5d61b8Smrg    if (stuff->time == CurrentTime)
2831b5d61b8Smrg        UpdateCurrentTime();
2841b5d61b8Smrg
2854642e01fSmrg    rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess);
2864642e01fSmrg
2876747b715Smrg    memset(&event, 0, sizeof(xEvent));
2884642e01fSmrg    if (rc != Success && rc != BadMatch)
28935c4bbdfSmrg        return rc;
2904642e01fSmrg    else if (rc == Success && pSel->window != None) {
29135c4bbdfSmrg        event.u.u.type = SelectionRequest;
29235c4bbdfSmrg        event.u.selectionRequest.owner = pSel->window;
29335c4bbdfSmrg        event.u.selectionRequest.time = stuff->time;
29435c4bbdfSmrg        event.u.selectionRequest.requestor = stuff->requestor;
29535c4bbdfSmrg        event.u.selectionRequest.selection = stuff->selection;
29635c4bbdfSmrg        event.u.selectionRequest.target = stuff->target;
29735c4bbdfSmrg        event.u.selectionRequest.property = stuff->property;
29835c4bbdfSmrg        if (pSel->client && pSel->client != serverClient &&
29935c4bbdfSmrg            !pSel->client->clientGone) {
30035c4bbdfSmrg            WriteEventsToClient(pSel->client, 1, &event);
30135c4bbdfSmrg            return Success;
30235c4bbdfSmrg        }
3034642e01fSmrg    }
3044642e01fSmrg
3054642e01fSmrg    event.u.u.type = SelectionNotify;
3064642e01fSmrg    event.u.selectionNotify.time = stuff->time;
3074642e01fSmrg    event.u.selectionNotify.requestor = stuff->requestor;
3084642e01fSmrg    event.u.selectionNotify.selection = stuff->selection;
3094642e01fSmrg    event.u.selectionNotify.target = stuff->target;
3104642e01fSmrg    event.u.selectionNotify.property = None;
3116747b715Smrg    WriteEventsToClient(client, 1, &event);
3126747b715Smrg    return Success;
3134642e01fSmrg}
314