2 * Copyright © 2006 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 #include "propertyst.h"
28 RRDeliverEvent (ScreenPtr pScreen
, xEvent
*event
, CARD32 mask
)
34 RRDeleteAllOutputProperties (RROutputPtr output
)
36 RRPropertyPtr prop
, next
;
37 xRROutputPropertyNotifyEvent event
;
39 for (prop
= output
->properties
; prop
; prop
= next
)
42 event
.type
= RREventBase
+ RRNotify
;
43 event
.subCode
= RRNotify_OutputProperty
;
44 event
.output
= output
->id
;
45 event
.state
= PropertyDelete
;
46 event
.atom
= prop
->propertyName
;
47 event
.timestamp
= currentTime
.milliseconds
;
48 RRDeliverEvent (output
->pScreen
, (xEvent
*) &event
, RROutputPropertyNotifyMask
);
49 if (prop
->current
.data
)
50 xfree(prop
->current
.data
);
51 if (prop
->pending
.data
)
52 xfree(prop
->pending
.data
);
58 RRInitOutputPropertyValue (RRPropertyValuePtr property_value
)
60 property_value
->type
= None
;
61 property_value
->format
= 0;
62 property_value
->size
= 0;
63 property_value
->data
= NULL
;
67 RRCreateOutputProperty (Atom property
)
71 prop
= (RRPropertyPtr
)xalloc(sizeof(RRPropertyRec
));
75 prop
->propertyName
= property
;
76 prop
->is_pending
= FALSE
;
78 prop
->immutable
= FALSE
;
80 prop
->valid_values
= NULL
;
81 RRInitOutputPropertyValue (&prop
->current
);
82 RRInitOutputPropertyValue (&prop
->pending
);
87 RRDestroyOutputProperty (RRPropertyPtr prop
)
89 if (prop
->valid_values
)
90 xfree (prop
->valid_values
);
91 if (prop
->current
.data
)
92 xfree(prop
->current
.data
);
93 if (prop
->pending
.data
)
94 xfree(prop
->pending
.data
);
99 RRDeleteOutputProperty (RROutputPtr output
, Atom property
)
101 RRPropertyPtr prop
, *prev
;
102 xRROutputPropertyNotifyEvent event
;
104 for (prev
= &output
->properties
; (prop
= *prev
); prev
= &(prop
->next
))
105 if (prop
->propertyName
== property
)
110 event
.type
= RREventBase
+ RRNotify
;
111 event
.subCode
= RRNotify_OutputProperty
;
112 event
.output
= output
->id
;
113 event
.state
= PropertyDelete
;
114 event
.atom
= prop
->propertyName
;
115 event
.timestamp
= currentTime
.milliseconds
;
116 RRDeliverEvent (output
->pScreen
, (xEvent
*) &event
, RROutputPropertyNotifyMask
);
117 RRDestroyOutputProperty (prop
);
122 RRChangeOutputProperty (RROutputPtr output
, Atom property
, Atom type
,
123 int format
, int mode
, unsigned long len
,
124 pointer value
, Bool sendevent
, Bool pending
)
127 xRROutputPropertyNotifyEvent event
;
128 rrScrPrivPtr pScrPriv
= rrGetScrPriv(output
->pScreen
);
131 unsigned long total_len
;
132 RRPropertyValuePtr prop_value
;
133 RRPropertyValueRec new_value
;
136 size_in_bytes
= format
>> 3;
138 /* first see if property already exists */
139 prop
= RRQueryOutputProperty (output
, property
);
140 if (!prop
) /* just add to list */
142 prop
= RRCreateOutputProperty (property
);
146 mode
= PropModeReplace
;
148 if (pending
&& prop
->is_pending
)
149 prop_value
= &prop
->pending
;
151 prop_value
= &prop
->current
;
153 /* To append or prepend to a property the request format and type
154 must match those of the already defined property. The
155 existing format and type are irrelevant when using the mode
156 "PropModeReplace" since they will be written over. */
158 if ((format
!= prop_value
->format
) && (mode
!= PropModeReplace
))
160 if ((prop_value
->type
!= type
) && (mode
!= PropModeReplace
))
162 new_value
= *prop_value
;
163 if (mode
== PropModeReplace
)
166 total_len
= prop_value
->size
+ len
;
168 if (mode
== PropModeReplace
|| len
> 0)
170 pointer new_data
= NULL
, old_data
= NULL
;
172 total_size
= total_len
* size_in_bytes
;
173 new_value
.data
= (pointer
)xalloc (total_size
);
174 if (!new_value
.data
&& total_size
)
177 RRDestroyOutputProperty (prop
);
180 new_value
.size
= len
;
181 new_value
.type
= type
;
182 new_value
.format
= format
;
185 case PropModeReplace
:
186 new_data
= new_value
.data
;
190 new_data
= (pointer
) (((char *) new_value
.data
) +
191 (prop_value
->size
* size_in_bytes
));
192 old_data
= new_value
.data
;
194 case PropModePrepend
:
195 new_data
= new_value
.data
;
196 old_data
= (pointer
) (((char *) new_value
.data
) +
197 (prop_value
->size
* size_in_bytes
));
201 memcpy ((char *) new_data
, (char *) value
, len
* size_in_bytes
);
203 memcpy ((char *) old_data
, (char *) prop_value
->data
,
204 prop_value
->size
* size_in_bytes
);
206 if (pending
&& pScrPriv
->rrOutputSetProperty
&&
207 !pScrPriv
->rrOutputSetProperty(output
->pScreen
, output
,
208 prop
->propertyName
, &new_value
))
211 xfree (new_value
.data
);
214 if (prop_value
->data
)
215 xfree (prop_value
->data
);
216 *prop_value
= new_value
;
226 prop
->next
= output
->properties
;
227 output
->properties
= prop
;
230 if (pending
&& prop
->is_pending
)
231 output
->pendingProperties
= TRUE
;
235 event
.type
= RREventBase
+ RRNotify
;
236 event
.subCode
= RRNotify_OutputProperty
;
237 event
.output
= output
->id
;
238 event
.state
= PropertyNewValue
;
239 event
.atom
= prop
->propertyName
;
240 event
.timestamp
= currentTime
.milliseconds
;
241 RRDeliverEvent (output
->pScreen
, (xEvent
*) &event
, RROutputPropertyNotifyMask
);
247 RRPostPendingProperties (RROutputPtr output
)
249 RRPropertyValuePtr pending_value
;
250 RRPropertyValuePtr current_value
;
251 RRPropertyPtr property
;
254 if (!output
->pendingProperties
)
257 output
->pendingProperties
= FALSE
;
258 for (property
= output
->properties
; property
; property
= property
->next
)
260 /* Skip non-pending properties */
261 if (!property
->is_pending
)
264 pending_value
= &property
->pending
;
265 current_value
= &property
->current
;
268 * If the pending and current values are equal, don't mark it
269 * as changed (which would deliver an event)
271 if (pending_value
->type
== current_value
->type
&&
272 pending_value
->format
== current_value
->format
&&
273 pending_value
->size
== current_value
->size
&&
274 !memcmp (pending_value
->data
, current_value
->data
,
275 pending_value
->size
))
278 if (RRChangeOutputProperty (output
, property
->propertyName
,
279 pending_value
->type
, pending_value
->format
,
280 PropModeReplace
, pending_value
->size
,
281 pending_value
->data
, TRUE
,
289 RRQueryOutputProperty (RROutputPtr output
, Atom property
)
293 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
294 if (prop
->propertyName
== property
)
300 RRGetOutputProperty (RROutputPtr output
, Atom property
, Bool pending
)
302 RRPropertyPtr prop
= RRQueryOutputProperty (output
, property
);
306 if (pending
&& prop
->is_pending
)
307 return &prop
->pending
;
309 return &prop
->current
;
313 RRConfigureOutputProperty (RROutputPtr output
, Atom property
,
314 Bool pending
, Bool range
, Bool immutable
,
315 int num_values
, INT32
*values
)
317 RRPropertyPtr prop
= RRQueryOutputProperty (output
, property
);
323 prop
= RRCreateOutputProperty (property
);
327 } else if (prop
->immutable
&& !immutable
)
331 * ranges must have even number of values
333 if (range
&& (num_values
& 1))
336 new_values
= xalloc (num_values
* sizeof (INT32
));
337 if (!new_values
&& num_values
)
340 memcpy (new_values
, values
, num_values
* sizeof (INT32
));
343 * Property moving from pending to non-pending
344 * loses any pending values
346 if (prop
->is_pending
&& !pending
)
348 if (prop
->pending
.data
)
349 xfree (prop
->pending
.data
);
350 RRInitOutputPropertyValue (&prop
->pending
);
353 prop
->is_pending
= pending
;
355 prop
->immutable
= immutable
;
356 prop
->num_valid
= num_values
;
357 if (prop
->valid_values
)
358 xfree (prop
->valid_values
);
359 prop
->valid_values
= new_values
;
362 prop
->next
= output
->properties
;
363 output
->properties
= prop
;
370 ProcRRListOutputProperties (ClientPtr client
)
372 REQUEST(xRRListOutputPropertiesReq
);
373 Atom
*pAtoms
= NULL
, *temppAtoms
;
374 xRRListOutputPropertiesReply rep
;
379 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq
);
381 output
= LookupOutput (client
, stuff
->output
, DixReadAccess
);
384 return RRErrorBase
+ BadRROutput
;
386 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
389 if(!(pAtoms
= (Atom
*)ALLOCATE_LOCAL(numProps
* sizeof(Atom
))))
393 rep
.length
= (numProps
* sizeof(Atom
)) >> 2;
394 rep
.sequenceNumber
= client
->sequence
;
395 rep
.nAtoms
= numProps
;
399 swaps (&rep
.sequenceNumber
, n
);
400 swapl (&rep
.length
, n
);
403 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
404 *temppAtoms
++ = prop
->propertyName
;
406 WriteReplyToClient(client
, sizeof(xRRListOutputPropertiesReply
), &rep
);
409 client
->pSwapReplyFunc
= (ReplySwapPtr
)Swap32Write
;
410 WriteSwappedDataToClient(client
, numProps
* sizeof(Atom
), pAtoms
);
411 DEALLOCATE_LOCAL(pAtoms
);
413 return(client
->noClientException
);
417 ProcRRQueryOutputProperty (ClientPtr client
)
419 REQUEST(xRRQueryOutputPropertyReq
);
420 xRRQueryOutputPropertyReply rep
;
424 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq
);
426 output
= LookupOutput (client
, stuff
->output
, DixReadAccess
);
429 return RRErrorBase
+ BadRROutput
;
431 prop
= RRQueryOutputProperty (output
, stuff
->property
);
436 rep
.length
= prop
->num_valid
;
437 rep
.sequenceNumber
= client
->sequence
;
438 rep
.pending
= prop
->is_pending
;
439 rep
.range
= prop
->range
;
440 rep
.immutable
= prop
->immutable
;
444 swaps (&rep
.sequenceNumber
, n
);
445 swapl (&rep
.length
, n
);
447 WriteReplyToClient (client
, sizeof (xRRQueryOutputPropertyReply
), &rep
);
450 client
->pSwapReplyFunc
= (ReplySwapPtr
)Swap32Write
;
451 WriteSwappedDataToClient(client
, prop
->num_valid
* sizeof(INT32
),
454 return(client
->noClientException
);
458 ProcRRConfigureOutputProperty (ClientPtr client
)
460 REQUEST(xRRConfigureOutputPropertyReq
);
464 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq
);
466 output
= LookupOutput (client
, stuff
->output
, DixReadAccess
);
469 return RRErrorBase
+ BadRROutput
;
471 num_valid
= stuff
->length
- (sizeof (xRRConfigureOutputPropertyReq
) >> 2);
472 return RRConfigureOutputProperty (output
, stuff
->property
,
473 stuff
->pending
, stuff
->range
,
475 (INT32
*) (stuff
+ 1));
479 ProcRRChangeOutputProperty (ClientPtr client
)
481 REQUEST(xRRChangeOutputPropertyReq
);
489 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq
);
491 format
= stuff
->format
;
493 if ((mode
!= PropModeReplace
) && (mode
!= PropModeAppend
) &&
494 (mode
!= PropModePrepend
))
496 client
->errorValue
= mode
;
499 if ((format
!= 8) && (format
!= 16) && (format
!= 32))
501 client
->errorValue
= format
;
505 if (len
> ((0xffffffff - sizeof(xChangePropertyReq
)) >> 2))
507 sizeInBytes
= format
>>3;
508 totalSize
= len
* sizeInBytes
;
509 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq
, totalSize
);
511 output
= LookupOutput (client
, stuff
->output
, DixWriteAccess
);
513 return RRErrorBase
+ BadRROutput
;
515 if (!ValidAtom(stuff
->property
))
517 client
->errorValue
= stuff
->property
;
520 if (!ValidAtom(stuff
->type
))
522 client
->errorValue
= stuff
->type
;
526 err
= RRChangeOutputProperty(output
, stuff
->property
,
527 stuff
->type
, (int)format
,
528 (int)mode
, len
, (pointer
)&stuff
[1], TRUE
, TRUE
);
532 return client
->noClientException
;
536 ProcRRDeleteOutputProperty (ClientPtr client
)
538 REQUEST(xRRDeleteOutputPropertyReq
);
541 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq
);
543 output
= LookupOutput (client
, stuff
->output
, DixWriteAccess
);
545 return RRErrorBase
+ BadRROutput
;
547 if (!ValidAtom(stuff
->property
))
549 client
->errorValue
= stuff
->property
;
554 RRDeleteOutputProperty(output
, stuff
->property
);
555 return client
->noClientException
;
559 ProcRRGetOutputProperty (ClientPtr client
)
561 REQUEST(xRRGetOutputPropertyReq
);
562 RRPropertyPtr prop
, *prev
;
563 RRPropertyValuePtr prop_value
;
564 unsigned long n
, len
, ind
;
566 xRRGetOutputPropertyReply reply
;
568 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq
);
571 output
= LookupOutput (client
, stuff
->output
,
572 stuff
->delete ? DixWriteAccess
:
575 return RRErrorBase
+ BadRROutput
;
577 if (!ValidAtom(stuff
->property
))
579 client
->errorValue
= stuff
->property
;
582 if ((stuff
->delete != xTrue
) && (stuff
->delete != xFalse
))
584 client
->errorValue
= stuff
->delete;
587 if ((stuff
->type
!= AnyPropertyType
) && !ValidAtom(stuff
->type
))
589 client
->errorValue
= stuff
->type
;
593 for (prev
= &output
->properties
; (prop
= *prev
); prev
= &prop
->next
)
594 if (prop
->propertyName
== stuff
->property
)
597 reply
.type
= X_Reply
;
598 reply
.sequenceNumber
= client
->sequence
;
603 reply
.bytesAfter
= 0;
604 reply
.propertyType
= None
;
606 WriteReplyToClient(client
, sizeof(xRRGetOutputPropertyReply
), &reply
);
607 return(client
->noClientException
);
610 if (prop
->immutable
&& stuff
->delete)
613 if (stuff
->pending
&& prop
->is_pending
)
614 prop_value
= &prop
->pending
;
616 prop_value
= &prop
->current
;
618 /* If the request type and actual type don't match. Return the
619 property information, but not the data. */
621 if (((stuff
->type
!= prop_value
->type
) &&
622 (stuff
->type
!= AnyPropertyType
))
625 reply
.bytesAfter
= prop_value
->size
;
626 reply
.format
= prop_value
->format
;
629 reply
.propertyType
= prop_value
->type
;
630 WriteReplyToClient(client
, sizeof(xRRGetOutputPropertyReply
), &reply
);
631 return(client
->noClientException
);
635 * Return type, format, value to client
637 n
= (prop_value
->format
/8) * prop_value
->size
; /* size (bytes) of prop */
638 ind
= stuff
->longOffset
<< 2;
640 /* If longOffset is invalid such that it causes "len" to
641 be negative, it's a value error. */
645 client
->errorValue
= stuff
->longOffset
;
649 len
= min(n
- ind
, 4 * stuff
->longLength
);
651 reply
.bytesAfter
= n
- (ind
+ len
);
652 reply
.format
= prop_value
->format
;
653 reply
.length
= (len
+ 3) >> 2;
654 if (prop_value
->format
)
655 reply
.nItems
= len
/ (prop_value
->format
/ 8);
658 reply
.propertyType
= prop_value
->type
;
660 if (stuff
->delete && (reply
.bytesAfter
== 0))
662 xRROutputPropertyNotifyEvent event
;
664 event
.type
= RREventBase
+ RRNotify
;
665 event
.subCode
= RRNotify_OutputProperty
;
666 event
.output
= output
->id
;
667 event
.state
= PropertyDelete
;
668 event
.atom
= prop
->propertyName
;
669 event
.timestamp
= currentTime
.milliseconds
;
670 RRDeliverEvent (output
->pScreen
, (xEvent
*) &event
, RROutputPropertyNotifyMask
);
673 WriteReplyToClient(client
, sizeof(xGenericReply
), &reply
);
676 switch (reply
.format
) {
677 case 32: client
->pSwapReplyFunc
= (ReplySwapPtr
)CopySwap32Write
; break;
678 case 16: client
->pSwapReplyFunc
= (ReplySwapPtr
)CopySwap16Write
; break;
679 default: client
->pSwapReplyFunc
= (ReplySwapPtr
)WriteToClient
; break;
681 WriteSwappedDataToClient(client
, len
,
682 (char *)prop_value
->data
+ ind
);
685 if (stuff
->delete && (reply
.bytesAfter
== 0))
686 { /* delete the Property */
688 RRDestroyOutputProperty (prop
);
690 return(client
->noClientException
);