property.c revision 05b261ec
1/***********************************************************
2
3Copyright 1987, 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
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48#ifdef HAVE_DIX_CONFIG_H
49#include <dix-config.h>
50#endif
51
52#include <X11/X.h>
53#define NEED_REPLIES
54#define NEED_EVENTS
55#include <X11/Xproto.h>
56#include "windowstr.h"
57#include "propertyst.h"
58#include "dixstruct.h"
59#include "dispatch.h"
60#include "swaprep.h"
61#include "xace.h"
62
63/*****************************************************************
64 * Property Stuff
65 *
66 *    ChangeProperty, DeleteProperty, GetProperties,
67 *    ListProperties
68 *
69 *   Properties below to windows.  A allocate slots each time
70 *   a property is added.  No fancy searching done.
71 *
72 *****************************************************************/
73
74#ifdef notdef
75static void
76PrintPropertys(WindowPtr pWin)
77{
78    PropertyPtr pProp;
79    int j;
80
81    pProp = pWin->userProps;
82    while (pProp)
83    {
84        ErrorF(  "%x %x\n", pProp->propertyName, pProp->type);
85        ErrorF("property format: %d\n", pProp->format);
86        ErrorF("property data: \n");
87        for (j=0; j<(pProp->format/8)*pProp->size; j++)
88           ErrorF("%c\n", pProp->data[j]);
89        pProp = pProp->next;
90    }
91}
92#endif
93
94static void
95deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom)
96{
97    xEvent event;
98
99    event.u.u.type = PropertyNotify;
100    event.u.property.window = pWin->drawable.id;
101    event.u.property.state = state;
102    event.u.property.atom = atom;
103    event.u.property.time = currentTime.milliseconds;
104    DeliverEvents(pWin, &event, 1, (WindowPtr)NULL);
105}
106
107int
108ProcRotateProperties(ClientPtr client)
109{
110    int     i, j, delta, rc;
111    REQUEST(xRotatePropertiesReq);
112    WindowPtr pWin;
113    Atom * atoms;
114    PropertyPtr * props;               /* array of pointer */
115    PropertyPtr pProp;
116
117    REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
118    UpdateCurrentTime();
119    rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
120    if (rc != Success)
121        return rc;
122    if (!stuff->nAtoms)
123	return(Success);
124    atoms = (Atom *) & stuff[1];
125    props = (PropertyPtr *)ALLOCATE_LOCAL(stuff->nAtoms * sizeof(PropertyPtr));
126    if (!props)
127	return(BadAlloc);
128    for (i = 0; i < stuff->nAtoms; i++)
129    {
130	char action = XaceHook(XACE_PROPERTY_ACCESS, client, pWin, atoms[i],
131				DixReadAccess|DixWriteAccess);
132
133        if (!ValidAtom(atoms[i]) || (XaceErrorOperation == action)) {
134            DEALLOCATE_LOCAL(props);
135	    client->errorValue = atoms[i];
136            return BadAtom;
137        }
138	if (XaceIgnoreOperation == action) {
139            DEALLOCATE_LOCAL(props);
140	    return Success;
141	}
142
143        for (j = i + 1; j < stuff->nAtoms; j++)
144            if (atoms[j] == atoms[i])
145            {
146                DEALLOCATE_LOCAL(props);
147                return BadMatch;
148            }
149        pProp = wUserProps (pWin);
150        while (pProp)
151        {
152            if (pProp->propertyName == atoms[i])
153                goto found;
154	    pProp = pProp->next;
155        }
156        DEALLOCATE_LOCAL(props);
157        return BadMatch;
158found:
159        props[i] = pProp;
160    }
161    delta = stuff->nPositions;
162
163    /* If the rotation is a complete 360 degrees, then moving the properties
164	around and generating PropertyNotify events should be skipped. */
165
166    if ( (stuff->nAtoms != 0) && (abs(delta) % stuff->nAtoms) != 0 )
167    {
168	while (delta < 0)                  /* faster if abs value is small */
169            delta += stuff->nAtoms;
170    	for (i = 0; i < stuff->nAtoms; i++)
171 	{
172	    deliverPropertyNotifyEvent(pWin, PropertyNewValue,
173				       props[i]->propertyName);
174
175            props[i]->propertyName = atoms[(i + delta) % stuff->nAtoms];
176	}
177    }
178    DEALLOCATE_LOCAL(props);
179    return Success;
180}
181
182int
183ProcChangeProperty(ClientPtr client)
184{
185    WindowPtr pWin;
186    char format, mode;
187    unsigned long len;
188    int sizeInBytes, totalSize, err;
189    REQUEST(xChangePropertyReq);
190
191    REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
192    UpdateCurrentTime();
193    format = stuff->format;
194    mode = stuff->mode;
195    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
196	(mode != PropModePrepend))
197    {
198	client->errorValue = mode;
199	return BadValue;
200    }
201    if ((format != 8) && (format != 16) && (format != 32))
202    {
203	client->errorValue = format;
204        return BadValue;
205    }
206    len = stuff->nUnits;
207    if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2))
208	return BadLength;
209    sizeInBytes = format>>3;
210    totalSize = len * sizeInBytes;
211    REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
212
213    err = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
214    if (err != Success)
215	return err;
216    if (!ValidAtom(stuff->property))
217    {
218	client->errorValue = stuff->property;
219	return(BadAtom);
220    }
221    if (!ValidAtom(stuff->type))
222    {
223	client->errorValue = stuff->type;
224	return(BadAtom);
225    }
226
227    switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property,
228		     DixWriteAccess))
229    {
230    case XaceErrorOperation:
231	client->errorValue = stuff->property;
232	return BadAtom;
233    case XaceIgnoreOperation:
234	return Success;
235    }
236
237    err = ChangeWindowProperty(pWin, stuff->property, stuff->type, (int)format,
238			       (int)mode, len, (pointer)&stuff[1], TRUE);
239    if (err != Success)
240	return err;
241    else
242	return client->noClientException;
243}
244
245_X_EXPORT int
246ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format,
247                     int mode, unsigned long len, pointer value,
248                     Bool sendevent)
249{
250    PropertyPtr pProp;
251    int sizeInBytes;
252    int totalSize;
253    pointer data;
254
255    sizeInBytes = format>>3;
256    totalSize = len * sizeInBytes;
257
258    /* first see if property already exists */
259
260    pProp = wUserProps (pWin);
261    while (pProp)
262    {
263	if (pProp->propertyName == property)
264	    break;
265	pProp = pProp->next;
266    }
267    if (!pProp)   /* just add to list */
268    {
269	if (!pWin->optional && !MakeWindowOptional (pWin))
270	    return(BadAlloc);
271        pProp = (PropertyPtr)xalloc(sizeof(PropertyRec));
272	if (!pProp)
273	    return(BadAlloc);
274        data = (pointer)xalloc(totalSize);
275	if (!data && len)
276	{
277	    xfree(pProp);
278	    return(BadAlloc);
279	}
280        pProp->propertyName = property;
281        pProp->type = type;
282        pProp->format = format;
283        pProp->data = data;
284	if (len)
285	    memmove((char *)data, (char *)value, totalSize);
286	pProp->size = len;
287        pProp->next = pWin->optional->userProps;
288        pWin->optional->userProps = pProp;
289    }
290    else
291    {
292	/* To append or prepend to a property the request format and type
293		must match those of the already defined property.  The
294		existing format and type are irrelevant when using the mode
295		"PropModeReplace" since they will be written over. */
296
297        if ((format != pProp->format) && (mode != PropModeReplace))
298	    return(BadMatch);
299        if ((pProp->type != type) && (mode != PropModeReplace))
300            return(BadMatch);
301        if (mode == PropModeReplace)
302        {
303	    if (totalSize != pProp->size * (pProp->format >> 3))
304	    {
305	    	data = (pointer)xrealloc(pProp->data, totalSize);
306	    	if (!data && len)
307		    return(BadAlloc);
308            	pProp->data = data;
309	    }
310	    if (len)
311		memmove((char *)pProp->data, (char *)value, totalSize);
312	    pProp->size = len;
313    	    pProp->type = type;
314	    pProp->format = format;
315	}
316	else if (len == 0)
317	{
318	    /* do nothing */
319	}
320        else if (mode == PropModeAppend)
321        {
322	    data = (pointer)xrealloc(pProp->data,
323				     sizeInBytes * (len + pProp->size));
324	    if (!data)
325		return(BadAlloc);
326            pProp->data = data;
327	    memmove(&((char *)data)[pProp->size * sizeInBytes],
328		    (char *)value,
329		  totalSize);
330            pProp->size += len;
331	}
332        else if (mode == PropModePrepend)
333        {
334            data = (pointer)xalloc(sizeInBytes * (len + pProp->size));
335	    if (!data)
336		return(BadAlloc);
337	    memmove(&((char *)data)[totalSize], (char *)pProp->data,
338		  (int)(pProp->size * sizeInBytes));
339            memmove((char *)data, (char *)value, totalSize);
340	    xfree(pProp->data);
341            pProp->data = data;
342            pProp->size += len;
343	}
344    }
345
346    if (sendevent)
347	deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName);
348
349    return(Success);
350}
351
352int
353DeleteProperty(WindowPtr pWin, Atom propName)
354{
355    PropertyPtr pProp, prevProp;
356
357    if (!(pProp = wUserProps (pWin)))
358	return(Success);
359    prevProp = (PropertyPtr)NULL;
360    while (pProp)
361    {
362	if (pProp->propertyName == propName)
363	    break;
364        prevProp = pProp;
365	pProp = pProp->next;
366    }
367    if (pProp)
368    {
369        if (prevProp == (PropertyPtr)NULL)      /* takes care of head */
370        {
371            if (!(pWin->optional->userProps = pProp->next))
372		CheckWindowOptionalNeed (pWin);
373        }
374	else
375        {
376            prevProp->next = pProp->next;
377        }
378	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
379	xfree(pProp->data);
380        xfree(pProp);
381    }
382    return(Success);
383}
384
385void
386DeleteAllWindowProperties(WindowPtr pWin)
387{
388    PropertyPtr pProp, pNextProp;
389
390    pProp = wUserProps (pWin);
391    while (pProp)
392    {
393	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
394	pNextProp = pProp->next;
395        xfree(pProp->data);
396        xfree(pProp);
397	pProp = pNextProp;
398    }
399}
400
401static int
402NullPropertyReply(
403    ClientPtr client,
404    ATOM propertyType,
405    int format,
406    xGetPropertyReply *reply)
407{
408    reply->nItems = 0;
409    reply->length = 0;
410    reply->bytesAfter = 0;
411    reply->propertyType = propertyType;
412    reply->format = format;
413    WriteReplyToClient(client, sizeof(xGenericReply), reply);
414    return(client->noClientException);
415}
416
417/*****************
418 * GetProperty
419 *    If type Any is specified, returns the property from the specified
420 *    window regardless of its type.  If a type is specified, returns the
421 *    property only if its type equals the specified type.
422 *    If delete is True and a property is returned, the property is also
423 *    deleted from the window and a PropertyNotify event is generated on the
424 *    window.
425 *****************/
426
427int
428ProcGetProperty(ClientPtr client)
429{
430    PropertyPtr pProp, prevProp;
431    unsigned long n, len, ind, rc;
432    WindowPtr pWin;
433    xGetPropertyReply reply;
434    Mask access_mode = DixReadAccess;
435    REQUEST(xGetPropertyReq);
436
437    REQUEST_SIZE_MATCH(xGetPropertyReq);
438    if (stuff->delete)
439	UpdateCurrentTime();
440    rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
441    if (rc != Success)
442	return rc;
443
444    if (!ValidAtom(stuff->property))
445    {
446	client->errorValue = stuff->property;
447	return(BadAtom);
448    }
449    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
450    {
451	client->errorValue = stuff->delete;
452	return(BadValue);
453    }
454    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
455    {
456	client->errorValue = stuff->type;
457	return(BadAtom);
458    }
459
460    pProp = wUserProps (pWin);
461    prevProp = (PropertyPtr)NULL;
462    while (pProp)
463    {
464	if (pProp->propertyName == stuff->property)
465	    break;
466	prevProp = pProp;
467	pProp = pProp->next;
468    }
469
470    reply.type = X_Reply;
471    reply.sequenceNumber = client->sequence;
472    if (!pProp)
473	return NullPropertyReply(client, None, 0, &reply);
474
475    if (stuff->delete)
476	access_mode |= DixDestroyAccess;
477    switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property,
478		     access_mode))
479    {
480    case XaceErrorOperation:
481	client->errorValue = stuff->property;
482	return BadAtom;;
483    case XaceIgnoreOperation:
484	return NullPropertyReply(client, pProp->type, pProp->format, &reply);
485    }
486
487    /* If the request type and actual type don't match. Return the
488    property information, but not the data. */
489
490    if (((stuff->type != pProp->type) &&
491	 (stuff->type != AnyPropertyType))
492       )
493    {
494	reply.bytesAfter = pProp->size;
495	reply.format = pProp->format;
496	reply.length = 0;
497	reply.nItems = 0;
498	reply.propertyType = pProp->type;
499	WriteReplyToClient(client, sizeof(xGenericReply), &reply);
500	return(Success);
501    }
502
503/*
504 *  Return type, format, value to client
505 */
506    n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */
507    ind = stuff->longOffset << 2;
508
509   /* If longOffset is invalid such that it causes "len" to
510	    be negative, it's a value error. */
511
512    if (n < ind)
513    {
514	client->errorValue = stuff->longOffset;
515	return BadValue;
516    }
517
518    len = min(n - ind, 4 * stuff->longLength);
519
520    reply.bytesAfter = n - (ind + len);
521    reply.format = pProp->format;
522    reply.length = (len + 3) >> 2;
523    reply.nItems = len / (pProp->format / 8 );
524    reply.propertyType = pProp->type;
525
526    if (stuff->delete && (reply.bytesAfter == 0))
527	deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
528
529    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
530    if (len)
531    {
532	switch (reply.format) {
533	case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
534	case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
535	default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
536	}
537	WriteSwappedDataToClient(client, len,
538				 (char *)pProp->data + ind);
539    }
540
541    if (stuff->delete && (reply.bytesAfter == 0))
542    { /* delete the Property */
543	if (prevProp == (PropertyPtr)NULL) /* takes care of head */
544	{
545	    if (!(pWin->optional->userProps = pProp->next))
546		CheckWindowOptionalNeed (pWin);
547	}
548	else
549	    prevProp->next = pProp->next;
550	xfree(pProp->data);
551	xfree(pProp);
552    }
553    return(client->noClientException);
554}
555
556int
557ProcListProperties(ClientPtr client)
558{
559    Atom *pAtoms = NULL, *temppAtoms;
560    xListPropertiesReply xlpr;
561    int	rc, numProps = 0;
562    WindowPtr pWin;
563    PropertyPtr pProp;
564    REQUEST(xResourceReq);
565
566    REQUEST_SIZE_MATCH(xResourceReq);
567    rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
568    if (rc != Success)
569        return rc;
570
571    pProp = wUserProps (pWin);
572    while (pProp)
573    {
574        pProp = pProp->next;
575	numProps++;
576    }
577    if (numProps)
578        if(!(pAtoms = (Atom *)ALLOCATE_LOCAL(numProps * sizeof(Atom))))
579            return(BadAlloc);
580
581    xlpr.type = X_Reply;
582    xlpr.nProperties = numProps;
583    xlpr.length = (numProps * sizeof(Atom)) >> 2;
584    xlpr.sequenceNumber = client->sequence;
585    pProp = wUserProps (pWin);
586    temppAtoms = pAtoms;
587    while (pProp)
588    {
589	*temppAtoms++ = pProp->propertyName;
590	pProp = pProp->next;
591    }
592    WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
593    if (numProps)
594    {
595        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
596        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
597        DEALLOCATE_LOCAL(pAtoms);
598    }
599    return(client->noClientException);
600}
601
602int
603ProcDeleteProperty(ClientPtr client)
604{
605    WindowPtr pWin;
606    REQUEST(xDeletePropertyReq);
607    int result;
608
609    REQUEST_SIZE_MATCH(xDeletePropertyReq);
610    UpdateCurrentTime();
611    result = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
612    if (result != Success)
613        return result;
614    if (!ValidAtom(stuff->property))
615    {
616	client->errorValue = stuff->property;
617	return (BadAtom);
618    }
619
620    switch (XaceHook(XACE_PROPERTY_ACCESS, client, pWin, stuff->property,
621		     DixDestroyAccess))
622    {
623    case XaceErrorOperation:
624	client->errorValue = stuff->property;
625	return BadAtom;;
626    case XaceIgnoreOperation:
627	return Success;
628    }
629
630    result = DeleteProperty(pWin, stuff->property);
631    if (client->noClientException != Success)
632	return(client->noClientException);
633    else
634	return(result);
635}
636