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