property.c 19.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/***********************************************************

Copyright 1987, 1998  The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.

Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.

                        All Rights Reserved

Peter Hutterer's avatar
Peter Hutterer committed
29
30
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
31
provided that the above copyright notice appear in all copies and that
Peter Hutterer's avatar
Peter Hutterer committed
32
both that copyright notice and this permission notice appear in
33
34
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
Peter Hutterer's avatar
Peter Hutterer committed
35
software without specific, written prior permission.
36
37
38
39
40
41
42
43
44
45
46

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

******************************************************************/

47
48
49
50
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

51
52
#include <X11/X.h>
#include <X11/Xproto.h>
53
54
55
#include "windowstr.h"
#include "propertyst.h"
#include "dixstruct.h"
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
56
57
#include "dispatch.h"
#include "swaprep.h"
58
#include "xace.h"
59
60
61
62

/*****************************************************************
 * Property Stuff
 *
63
 *    dixLookupProperty, dixChangeProperty, DeleteProperty
64
 *
65
66
 *   Properties belong to windows.  The list of properties should not be
 *   traversed directly.  Instead, use the three functions listed above.
67
68
69
70
71
 *
 *****************************************************************/

#ifdef notdef
static void
Roland Mainz's avatar
Roland Mainz committed
72
PrintPropertys(WindowPtr pWin)
73
74
{
    PropertyPtr pProp;
75
    int j;
76
77

    pProp = pWin->userProps;
78
    while (pProp) {
79
80
81
        ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type);
        ErrorF("[dix] property format: %d\n", pProp->format);
        ErrorF("[dix] property data: \n");
82
83
        for (j = 0; j < (pProp->format / 8) * pProp->size; j++)
            ErrorF("[dix] %c\n", pProp->data[j]);
84
85
86
87
88
        pProp = pProp->next;
    }
}
#endif

89
int
90
dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
91
                  ClientPtr client, Mask access_mode)
92
{
93
94
    PropertyPtr pProp;
    int rc = BadMatch;
95

96
97
98
    client->errorValue = propertyName;

    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
99
100
        if (pProp->propertyName == propertyName)
            break;
101
102

    if (pProp)
103
        rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode);
104
105
    *result = pProp;
    return rc;
106
107
}

108
109
CallbackListPtr PropertyStateCallback;

110
static void
111
deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp)
112
{
113
    xEvent event;
114
115
116
117
118
    PropertyStateRec rec = {
        .win = pWin,
        .prop = pProp,
        .state = state
    };
119
    UpdateCurrentTimeIf();
120
121
122
    event = (xEvent) {
        .u.property.window = pWin->drawable.id,
        .u.property.state = state,
123
        .u.property.atom = pProp->propertyName,
124
125
        .u.property.time = currentTime.milliseconds,
    };
126
    event.u.u.type = PropertyNotify;
127
128

    CallCallbacks(&PropertyStateCallback, &rec);
129
    DeliverEvents(pWin, &event, 1, (WindowPtr) NULL);
130
131
}

132
int
Roland Mainz's avatar
Roland Mainz committed
133
ProcRotateProperties(ClientPtr client)
134
{
135
136
    int i, j, delta, rc;

137
138
    REQUEST(xRotatePropertiesReq);
    WindowPtr pWin;
139
140
    Atom *atoms;
    PropertyPtr *props;         /* array of pointer */
141
    PropertyPtr pProp, saved;
142
143
144

    REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
    UpdateCurrentTime();
145
    rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
146
    if (rc != Success || stuff->nAtoms <= 0)
147
        return rc;
148

149
    atoms = (Atom *) &stuff[1];
150
151
    props = xallocarray(stuff->nAtoms, sizeof(PropertyPtr));
    saved = xallocarray(stuff->nAtoms, sizeof(PropertyRec));
152
    if (!props || !saved) {
153
154
        rc = BadAlloc;
        goto out;
155
156
    }

157
    for (i = 0; i < stuff->nAtoms; i++) {
158
        if (!ValidAtom(atoms[i])) {
159
160
161
            rc = BadAtom;
            client->errorValue = atoms[i];
            goto out;
162
163
        }
        for (j = i + 1; j < stuff->nAtoms; j++)
164
165
166
            if (atoms[j] == atoms[i]) {
                rc = BadMatch;
                goto out;
167
            }
168

169
170
171
172
        rc = dixLookupProperty(&pProp, pWin, atoms[i], client,
                               DixReadAccess | DixWriteAccess);
        if (rc != Success)
            goto out;
173

174
        props[i] = pProp;
175
        saved[i] = *pProp;
176
177
178
179
    }
    delta = stuff->nPositions;

    /* If the rotation is a complete 360 degrees, then moving the properties
180
       around and generating PropertyNotify events should be skipped. */
181

182
183
    if (abs(delta) % stuff->nAtoms) {
        while (delta < 0)       /* faster if abs value is small */
184
            delta += stuff->nAtoms;
185
186
        for (i = 0; i < stuff->nAtoms; i++) {
            j = (i + delta) % stuff->nAtoms;
187
            deliverPropertyNotifyEvent(pWin, PropertyNewValue, props[i]);
188
189
190
191
192
193
194

            /* Preserve name and devPrivates */
            props[j]->type = saved[i].type;
            props[j]->format = saved[i].format;
            props[j]->size = saved[i].size;
            props[j]->data = saved[i].data;
        }
195
    }
196
 out:
197
198
    free(saved);
    free(props);
199
    return rc;
200
201
}

202
int
Roland Mainz's avatar
Roland Mainz committed
203
ProcChangeProperty(ClientPtr client)
204
{
205
206
207
    WindowPtr pWin;
    char format, mode;
    unsigned long len;
208
    int sizeInBytes, totalSize, err;
209

210
211
212
213
214
215
216
    REQUEST(xChangePropertyReq);

    REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
    UpdateCurrentTime();
    format = stuff->format;
    mode = stuff->mode;
    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
217
218
219
        (mode != PropModePrepend)) {
        client->errorValue = mode;
        return BadValue;
220
    }
221
222
    if ((format != 8) && (format != 16) && (format != 32)) {
        client->errorValue = format;
223
224
225
        return BadValue;
    }
    len = stuff->nUnits;
226
    if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq)))
227
228
        return BadLength;
    sizeInBytes = format >> 3;
229
230
231
    totalSize = len * sizeInBytes;
    REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);

232
    err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
233
    if (err != Success)
234
235
236
237
        return err;
    if (!ValidAtom(stuff->property)) {
        client->errorValue = stuff->property;
        return BadAtom;
238
    }
239
240
241
    if (!ValidAtom(stuff->type)) {
        client->errorValue = stuff->type;
        return BadAtom;
242
243
    }

244
    err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type,
245
246
                                  (int) format, (int) mode, len, &stuff[1],
                                  TRUE);
247
    if (err != Success)
248
        return err;
249
    else
250
        return Success;
251
252
}

253
int
254
dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
255
                        Atom type, int format, int mode, unsigned long len,
256
                        const void *value, Bool sendevent)
257
258
{
    PropertyPtr pProp;
259
    PropertyRec savedProp;
260
    int sizeInBytes, totalSize, rc;
261
    unsigned char *data;
262
    Mask access_mode;
263

264
    sizeInBytes = format >> 3;
265
    totalSize = len * sizeInBytes;
266
    access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess;
267
268

    /* first see if property already exists */
269
    rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode);
270

271
272
273
274
275
276
    if (rc == BadMatch) {       /* just add to list */
        if (!pWin->optional && !MakeWindowOptional(pWin))
            return BadAlloc;
        pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY);
        if (!pProp)
            return BadAlloc;
277
        data = malloc(totalSize);
278
279
280
281
        if (!data && len) {
            dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
            return BadAlloc;
        }
282
        memcpy(data, value, totalSize);
283
284
285
286
        pProp->propertyName = property;
        pProp->type = type;
        pProp->format = format;
        pProp->data = data;
287
288
289
290
291
292
293
294
295
        pProp->size = len;
        rc = XaceHookPropertyAccess(pClient, pWin, &pProp,
                                    DixCreateAccess | DixWriteAccess);
        if (rc != Success) {
            free(data);
            dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
            pClient->errorValue = property;
            return rc;
        }
296
297
298
        pProp->next = pWin->optional->userProps;
        pWin->optional->userProps = pProp;
    }
299
300
301
302
303
    else if (rc == Success) {
        /* To append or prepend to a property the request format and type
           must match those of the already defined property.  The
           existing format and type are irrelevant when using the mode
           "PropModeReplace" since they will be written over. */
304
305

        if ((format != pProp->format) && (mode != PropModeReplace))
306
            return BadMatch;
307
        if ((pProp->type != type) && (mode != PropModeReplace))
308
            return BadMatch;
309

310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
        /* save the old values for later */
        savedProp = *pProp;

        if (mode == PropModeReplace) {
            data = malloc(totalSize);
            if (!data && len)
                return BadAlloc;
            memcpy(data, value, totalSize);
            pProp->data = data;
            pProp->size = len;
            pProp->type = type;
            pProp->format = format;
        }
        else if (len == 0) {
            /* do nothing */
        }
        else if (mode == PropModeAppend) {
327
            data = xallocarray(pProp->size + len, sizeInBytes);
328
329
330
331
            if (!data)
                return BadAlloc;
            memcpy(data, pProp->data, pProp->size * sizeInBytes);
            memcpy(data + pProp->size * sizeInBytes, value, totalSize);
332
333
            pProp->data = data;
            pProp->size += len;
334
335
        }
        else if (mode == PropModePrepend) {
336
            data = xallocarray(len + pProp->size, sizeInBytes);
337
338
            if (!data)
                return BadAlloc;
339
340
            memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes);
            memcpy(data, value, totalSize);
341
342
            pProp->data = data;
            pProp->size += len;
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
        }

        /* Allow security modules to check the new content */
        access_mode |= DixPostAccess;
        rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode);
        if (rc == Success) {
            if (savedProp.data != pProp->data)
                free(savedProp.data);
        }
        else {
            if (savedProp.data != pProp->data)
                free(pProp->data);
            *pProp = savedProp;
            return rc;
        }
358
    }
359
    else
360
        return rc;
361

362
    if (sendevent)
363
        deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp);
364

365
    return Success;
366
367
}

368
int
369
DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
370
371
{
    PropertyPtr pProp, prevProp;
372
    int rc;
373

374
375
    rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess);
    if (rc == BadMatch)
376
        return Success;         /* Succeed if property does not exist */
377

378
    if (rc == Success) {
379
380
        if (pWin->optional->userProps == pProp) {
            /* Takes care of head */
381
            if (!(pWin->optional->userProps = pProp->next))
382
383
384
385
386
387
388
389
390
391
                CheckWindowOptionalNeed(pWin);
        }
        else {
            /* Need to traverse to find the previous element */
            prevProp = pWin->optional->userProps;
            while (prevProp->next != pProp)
                prevProp = prevProp->next;
            prevProp->next = pProp->next;
        }

392
        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
393
394
        free(pProp->data);
        dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
395
    }
396
    return rc;
397
398
}

399
void
Roland Mainz's avatar
Roland Mainz committed
400
DeleteAllWindowProperties(WindowPtr pWin)
401
402
403
{
    PropertyPtr pProp, pNextProp;

404
405
    pProp = wUserProps(pWin);
    while (pProp) {
406
        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
407
        pNextProp = pProp->next;
408
        free(pProp->data);
409
410
        dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
        pProp = pNextProp;
411
    }
412
413
414

    if (pWin->optional)
        pWin->optional->userProps = NULL;
415
416
417
}

static int
418
NullPropertyReply(ClientPtr client, ATOM propertyType, int format)
419
{
420
421
422
423
424
425
426
427
428
    xGetPropertyReply reply = {
        .type = X_Reply,
        .format = format,
        .sequenceNumber = client->sequence,
        .length = 0,
        .propertyType = propertyType,
        .bytesAfter = 0,
        .nItems = 0
    };
429
    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
430
    return Success;
431
432
433
434
435
436
437
438
439
440
441
442
443
}

/*****************
 * GetProperty
 *    If type Any is specified, returns the property from the specified
 *    window regardless of its type.  If a type is specified, returns the
 *    property only if its type equals the specified type.
 *    If delete is True and a property is returned, the property is also
 *    deleted from the window and a PropertyNotify event is generated on the
 *    window.
 *****************/

int
Roland Mainz's avatar
Roland Mainz committed
444
ProcGetProperty(ClientPtr client)
445
446
{
    PropertyPtr pProp, prevProp;
447
448
    unsigned long n, len, ind;
    int rc;
449
450
    WindowPtr pWin;
    xGetPropertyReply reply;
451
    Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
452

453
454
455
    REQUEST(xGetPropertyReq);

    REQUEST_SIZE_MATCH(xGetPropertyReq);
456
    if (stuff->delete) {
457
458
459
        UpdateCurrentTime();
        win_mode |= DixSetPropAccess;
        prop_mode |= DixDestroyAccess;
460
    }
461
    rc = dixLookupWindow(&pWin, stuff->window, client, win_mode);
462
    if (rc != Success)
463
        return rc;
464

465
466
467
    if (!ValidAtom(stuff->property)) {
        client->errorValue = stuff->property;
        return BadAtom;
468
    }
469
470
471
    if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
        client->errorValue = stuff->delete;
        return BadValue;
472
    }
473
474
475
    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
        client->errorValue = stuff->type;
        return BadAtom;
476
477
    }

478
479
    rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode);
    if (rc == BadMatch)
480
        return NullPropertyReply(client, None, 0);
481
    else if (rc != Success)
482
        return rc;
483

484
    /* If the request type and actual type don't match. Return the
485
486
487
488
       property information, but not the data. */

    if (((stuff->type != pProp->type) && (stuff->type != AnyPropertyType))
        ) {
489
490
491
492
493
494
495
496
497
        reply = (xGetPropertyReply) {
            .type = X_Reply,
            .sequenceNumber = client->sequence,
            .bytesAfter = pProp->size,
            .format = pProp->format,
            .length = 0,
            .nItems = 0,
            .propertyType = pProp->type
        };
498
499
        WriteReplyToClient(client, sizeof(xGenericReply), &reply);
        return Success;
500
501
502
503
504
    }

/*
 *  Return type, format, value to client
 */
505
506
    n = (pProp->format / 8) * pProp->size;      /* size (bytes) of prop */
    ind = stuff->longOffset << 2;
507

508
509
    /* If longOffset is invalid such that it causes "len" to
       be negative, it's a value error. */
510

511
512
513
    if (n < ind) {
        client->errorValue = stuff->longOffset;
        return BadValue;
514
515
516
517
    }

    len = min(n - ind, 4 * stuff->longLength);

518
519
520
521
522
523
524
525
526
    reply = (xGetPropertyReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .bytesAfter = n - (ind + len),
        .format = pProp->format,
        .length = bytes_to_int32(len),
        .nItems = len / (pProp->format / 8),
        .propertyType = pProp->type
    };
527
528

    if (stuff->delete && (reply.bytesAfter == 0))
529
        deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp);
530
531

    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
532
533
534
535
536
537
538
539
540
541
542
543
544
    if (len) {
        switch (reply.format) {
        case 32:
            client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
            break;
        case 16:
            client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
            break;
        default:
            client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
            break;
        }
        WriteSwappedDataToClient(client, len, (char *) pProp->data + ind);
545
546
    }

547
    if (stuff->delete && (reply.bytesAfter == 0)) {
548
549
550
        /* Delete the Property */
        if (pWin->optional->userProps == pProp) {
            /* Takes care of head */
551
            if (!(pWin->optional->userProps = pProp->next))
552
553
554
555
556
557
558
559
560
561
562
563
                CheckWindowOptionalNeed(pWin);
        }
        else {
            /* Need to traverse to find the previous element */
            prevProp = pWin->optional->userProps;
            while (prevProp->next != pProp)
                prevProp = prevProp->next;
            prevProp->next = pProp->next;
        }

        free(pProp->data);
        dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
564
    }
565
    return Success;
566
567
568
}

int
Roland Mainz's avatar
Roland Mainz committed
569
ProcListProperties(ClientPtr client)
570
{
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
571
    Atom *pAtoms = NULL, *temppAtoms;
572
    xListPropertiesReply xlpr;
573
    int rc, numProps = 0;
574
    WindowPtr pWin;
575
    PropertyPtr pProp, realProp;
576

577
578
579
    REQUEST(xResourceReq);

    REQUEST_SIZE_MATCH(xResourceReq);
580
    rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess);
581
582
    if (rc != Success)
        return rc;
583

584
    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
585
        numProps++;
586

587
    if (numProps && !(pAtoms = xallocarray(numProps, sizeof(Atom))))
588
        return BadAlloc;
589
590
591
592

    numProps = 0;
    temppAtoms = pAtoms;
    for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
593
594
595
596
597
598
        realProp = pProp;
        rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
        if (rc == Success && realProp == pProp) {
            *temppAtoms++ = pProp->propertyName;
            numProps++;
        }
599
600
    }

601
602
603
604
605
606
    xlpr = (xListPropertiesReply) {
        .type = X_Reply,
        .sequenceNumber = client->sequence,
        .length = bytes_to_int32(numProps * sizeof(Atom)),
        .nProperties = numProps
    };
607
    WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
608
609
    if (numProps) {
        client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
610
611
        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
    }
612
    free(pAtoms);
613
    return Success;
614
615
}

616
int
617
ProcDeleteProperty(ClientPtr client)
618
619
{
    WindowPtr pWin;
620

621
622
    REQUEST(xDeletePropertyReq);
    int result;
623

624
625
    REQUEST_SIZE_MATCH(xDeletePropertyReq);
    UpdateCurrentTime();
626
    result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
627
628
    if (result != Success)
        return result;
629
630
631
    if (!ValidAtom(stuff->property)) {
        client->errorValue = stuff->property;
        return BadAtom;
632
633
    }

634
    return DeleteProperty(client, pWin, stuff->property);
635
}