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 DeliverPropertyEvent(WindowPtr pWin
, void *value
)
30 xRROutputPropertyNotifyEvent
*event
= value
;
31 RREventPtr
*pHead
, pRREvent
;
33 dixLookupResourceByType((pointer
*) &pHead
, pWin
->drawable
.id
,
34 RREventType
, serverClient
, DixReadAccess
);
36 return WT_WALKCHILDREN
;
38 for (pRREvent
= *pHead
; pRREvent
; pRREvent
= pRREvent
->next
) {
39 if (!(pRREvent
->mask
& RROutputPropertyNotifyMask
))
42 event
->window
= pRREvent
->window
->drawable
.id
;
43 WriteEventsToClient(pRREvent
->client
, 1, (xEvent
*) event
);
46 return WT_WALKCHILDREN
;
50 RRDeliverPropertyEvent(ScreenPtr pScreen
, xEvent
*event
)
52 if (!(dispatchException
& (DE_RESET
| DE_TERMINATE
)))
53 WalkTree(pScreen
, DeliverPropertyEvent
, event
);
57 RRDestroyOutputProperty(RRPropertyPtr prop
)
59 free(prop
->valid_values
);
60 free(prop
->current
.data
);
61 free(prop
->pending
.data
);
66 RRDeleteProperty(RROutputRec
* output
, RRPropertyRec
* prop
)
68 xRROutputPropertyNotifyEvent event
= {
69 .type
= RREventBase
+ RRNotify
,
70 .subCode
= RRNotify_OutputProperty
,
72 .state
= PropertyDelete
,
73 .atom
= prop
->propertyName
,
74 .timestamp
= currentTime
.milliseconds
77 RRDeliverPropertyEvent(output
->pScreen
, (xEvent
*) &event
);
79 RRDestroyOutputProperty(prop
);
83 RRDeleteAllOutputProperties(RROutputPtr output
)
85 RRPropertyPtr prop
, next
;
87 for (prop
= output
->properties
; prop
; prop
= next
) {
89 RRDeleteProperty(output
, prop
);
94 RRInitOutputPropertyValue(RRPropertyValuePtr property_value
)
96 property_value
->type
= None
;
97 property_value
->format
= 0;
98 property_value
->size
= 0;
99 property_value
->data
= NULL
;
103 RRCreateOutputProperty(Atom property
)
107 prop
= (RRPropertyPtr
) malloc(sizeof(RRPropertyRec
));
111 prop
->propertyName
= property
;
112 prop
->is_pending
= FALSE
;
114 prop
->immutable
= FALSE
;
116 prop
->valid_values
= NULL
;
117 RRInitOutputPropertyValue(&prop
->current
);
118 RRInitOutputPropertyValue(&prop
->pending
);
123 RRDeleteOutputProperty(RROutputPtr output
, Atom property
)
125 RRPropertyRec
*prop
, **prev
;
127 for (prev
= &output
->properties
; (prop
= *prev
); prev
= &(prop
->next
))
128 if (prop
->propertyName
== property
) {
130 RRDeleteProperty(output
, prop
);
136 RRChangeOutputProperty(RROutputPtr output
, Atom property
, Atom type
,
137 int format
, int mode
, unsigned long len
,
138 pointer value
, Bool sendevent
, Bool pending
)
141 rrScrPrivPtr pScrPriv
= rrGetScrPriv(output
->pScreen
);
144 unsigned long total_len
;
145 RRPropertyValuePtr prop_value
;
146 RRPropertyValueRec new_value
;
149 size_in_bytes
= format
>> 3;
151 /* first see if property already exists */
152 prop
= RRQueryOutputProperty(output
, property
);
153 if (!prop
) { /* just add to list */
154 prop
= RRCreateOutputProperty(property
);
158 mode
= PropModeReplace
;
160 if (pending
&& prop
->is_pending
)
161 prop_value
= &prop
->pending
;
163 prop_value
= &prop
->current
;
165 /* To append or prepend to a property the request format and type
166 must match those of the already defined property. The
167 existing format and type are irrelevant when using the mode
168 "PropModeReplace" since they will be written over. */
170 if ((format
!= prop_value
->format
) && (mode
!= PropModeReplace
))
172 if ((prop_value
->type
!= type
) && (mode
!= PropModeReplace
))
174 new_value
= *prop_value
;
175 if (mode
== PropModeReplace
)
178 total_len
= prop_value
->size
+ len
;
180 if (mode
== PropModeReplace
|| len
> 0) {
181 pointer new_data
= NULL
, old_data
= NULL
;
183 total_size
= total_len
* size_in_bytes
;
184 new_value
.data
= (pointer
) malloc(total_size
);
185 if (!new_value
.data
&& total_size
) {
187 RRDestroyOutputProperty(prop
);
190 new_value
.size
= len
;
191 new_value
.type
= type
;
192 new_value
.format
= format
;
195 case PropModeReplace
:
196 new_data
= new_value
.data
;
200 new_data
= (pointer
) (((char *) new_value
.data
) +
201 (prop_value
->size
* size_in_bytes
));
202 old_data
= new_value
.data
;
204 case PropModePrepend
:
205 new_data
= new_value
.data
;
206 old_data
= (pointer
) (((char *) new_value
.data
) +
207 (prop_value
->size
* size_in_bytes
));
211 memcpy((char *) new_data
, (char *) value
, len
* size_in_bytes
);
213 memcpy((char *) old_data
, (char *) prop_value
->data
,
214 prop_value
->size
* size_in_bytes
);
216 if (pending
&& pScrPriv
->rrOutputSetProperty
&&
217 !pScrPriv
->rrOutputSetProperty(output
->pScreen
, output
,
218 prop
->propertyName
, &new_value
)) {
219 free(new_value
.data
);
221 RRDestroyOutputProperty(prop
);
224 free(prop_value
->data
);
225 *prop_value
= new_value
;
233 prop
->next
= output
->properties
;
234 output
->properties
= prop
;
237 if (pending
&& prop
->is_pending
)
238 output
->pendingProperties
= TRUE
;
241 xRROutputPropertyNotifyEvent event
= {
242 .type
= RREventBase
+ RRNotify
,
243 .subCode
= RRNotify_OutputProperty
,
244 .output
= output
->id
,
245 .state
= PropertyNewValue
,
246 .atom
= prop
->propertyName
,
247 .timestamp
= currentTime
.milliseconds
249 RRDeliverPropertyEvent(output
->pScreen
, (xEvent
*) &event
);
255 RRPostPendingProperties(RROutputPtr output
)
257 RRPropertyValuePtr pending_value
;
258 RRPropertyValuePtr current_value
;
259 RRPropertyPtr property
;
262 if (!output
->pendingProperties
)
265 output
->pendingProperties
= FALSE
;
266 for (property
= output
->properties
; property
; property
= property
->next
) {
267 /* Skip non-pending properties */
268 if (!property
->is_pending
)
271 pending_value
= &property
->pending
;
272 current_value
= &property
->current
;
275 * If the pending and current values are equal, don't mark it
276 * as changed (which would deliver an event)
278 if (pending_value
->type
== current_value
->type
&&
279 pending_value
->format
== current_value
->format
&&
280 pending_value
->size
== current_value
->size
&&
281 !memcmp(pending_value
->data
, current_value
->data
,
282 pending_value
->size
* (pending_value
->format
/ 8)))
285 if (RRChangeOutputProperty(output
, property
->propertyName
,
286 pending_value
->type
, pending_value
->format
,
287 PropModeReplace
, pending_value
->size
,
288 pending_value
->data
, TRUE
, FALSE
) != Success
)
295 RRQueryOutputProperty(RROutputPtr output
, Atom property
)
299 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
300 if (prop
->propertyName
== property
)
306 RRGetOutputProperty(RROutputPtr output
, Atom property
, Bool pending
)
308 RRPropertyPtr prop
= RRQueryOutputProperty(output
, property
);
309 rrScrPrivPtr pScrPriv
= rrGetScrPriv(output
->pScreen
);
313 if (pending
&& prop
->is_pending
)
314 return &prop
->pending
;
316 #if RANDR_13_INTERFACE
317 /* If we can, try to update the property value first */
318 if (pScrPriv
->rrOutputGetProperty
)
319 pScrPriv
->rrOutputGetProperty(output
->pScreen
, output
,
322 return &prop
->current
;
327 RRConfigureOutputProperty(RROutputPtr output
, Atom property
,
328 Bool pending
, Bool range
, Bool immutable
,
329 int num_values
, INT32
*values
)
331 RRPropertyPtr prop
= RRQueryOutputProperty(output
, property
);
336 prop
= RRCreateOutputProperty(property
);
341 else if (prop
->immutable
&& !immutable
)
345 * ranges must have even number of values
347 if (range
&& (num_values
& 1)) {
349 RRDestroyOutputProperty(prop
);
353 new_values
= malloc(num_values
* sizeof(INT32
));
354 if (!new_values
&& num_values
) {
356 RRDestroyOutputProperty(prop
);
360 memcpy(new_values
, values
, num_values
* sizeof(INT32
));
363 * Property moving from pending to non-pending
364 * loses any pending values
366 if (prop
->is_pending
&& !pending
) {
367 free(prop
->pending
.data
);
368 RRInitOutputPropertyValue(&prop
->pending
);
371 prop
->is_pending
= pending
;
373 prop
->immutable
= immutable
;
374 prop
->num_valid
= num_values
;
375 free(prop
->valid_values
);
376 prop
->valid_values
= new_values
;
379 prop
->next
= output
->properties
;
380 output
->properties
= prop
;
387 ProcRRListOutputProperties(ClientPtr client
)
389 REQUEST(xRRListOutputPropertiesReq
);
391 xRRListOutputPropertiesReply rep
;
396 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq
);
398 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
400 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
403 if (!(pAtoms
= (Atom
*) malloc(numProps
* sizeof(Atom
))))
406 rep
= (xRRListOutputPropertiesReply
) {
408 .sequenceNumber
= client
->sequence
,
409 .length
= bytes_to_int32(numProps
* sizeof(Atom
)),
412 if (client
->swapped
) {
413 swaps(&rep
.sequenceNumber
);
417 WriteToClient(client
, sizeof(xRRListOutputPropertiesReply
), &rep
);
420 /* Copy property name atoms to reply buffer */
421 Atom
*temppAtoms
= pAtoms
;
422 for (prop
= output
->properties
; prop
; prop
= prop
->next
)
423 *temppAtoms
++ = prop
->propertyName
;
425 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
426 WriteSwappedDataToClient(client
, numProps
* sizeof(Atom
), pAtoms
);
433 ProcRRQueryOutputProperty(ClientPtr client
)
435 REQUEST(xRRQueryOutputPropertyReq
);
436 xRRQueryOutputPropertyReply rep
;
441 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq
);
443 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
445 prop
= RRQueryOutputProperty(output
, stuff
->property
);
449 if (prop
->num_valid
) {
450 extra
= malloc(prop
->num_valid
* sizeof(INT32
));
455 rep
= (xRRQueryOutputPropertyReply
) {
457 .sequenceNumber
= client
->sequence
,
458 .length
= prop
->num_valid
,
459 .pending
= prop
->is_pending
,
460 .range
= prop
->range
,
461 .immutable
= prop
->immutable
464 if (client
->swapped
) {
465 swaps(&rep
.sequenceNumber
);
468 WriteToClient(client
, sizeof(xRRQueryOutputPropertyReply
), &rep
);
469 if (prop
->num_valid
) {
470 memcpy(extra
, prop
->valid_values
, prop
->num_valid
* sizeof(INT32
));
471 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
472 WriteSwappedDataToClient(client
, prop
->num_valid
* sizeof(INT32
),
480 ProcRRConfigureOutputProperty(ClientPtr client
)
482 REQUEST(xRRConfigureOutputPropertyReq
);
486 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq
);
488 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
491 stuff
->length
- bytes_to_int32(sizeof(xRRConfigureOutputPropertyReq
));
492 return RRConfigureOutputProperty(output
, stuff
->property
, stuff
->pending
,
493 stuff
->range
, FALSE
, num_valid
,
494 (INT32
*) (stuff
+ 1));
498 ProcRRChangeOutputProperty(ClientPtr client
)
500 REQUEST(xRRChangeOutputPropertyReq
);
508 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq
);
510 format
= stuff
->format
;
512 if ((mode
!= PropModeReplace
) && (mode
!= PropModeAppend
) &&
513 (mode
!= PropModePrepend
)) {
514 client
->errorValue
= mode
;
517 if ((format
!= 8) && (format
!= 16) && (format
!= 32)) {
518 client
->errorValue
= format
;
522 if (len
> bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq
))))
524 sizeInBytes
= format
>> 3;
525 totalSize
= len
* sizeInBytes
;
526 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq
, totalSize
);
528 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
530 if (!ValidAtom(stuff
->property
)) {
531 client
->errorValue
= stuff
->property
;
534 if (!ValidAtom(stuff
->type
)) {
535 client
->errorValue
= stuff
->type
;
539 err
= RRChangeOutputProperty(output
, stuff
->property
,
540 stuff
->type
, (int) format
,
541 (int) mode
, len
, (pointer
) &stuff
[1], TRUE
,
550 ProcRRDeleteOutputProperty(ClientPtr client
)
552 REQUEST(xRRDeleteOutputPropertyReq
);
556 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq
);
558 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
560 if (!ValidAtom(stuff
->property
)) {
561 client
->errorValue
= stuff
->property
;
565 prop
= RRQueryOutputProperty(output
, stuff
->property
);
567 client
->errorValue
= stuff
->property
;
571 if (prop
->immutable
) {
572 client
->errorValue
= stuff
->property
;
576 RRDeleteOutputProperty(output
, stuff
->property
);
581 ProcRRGetOutputProperty(ClientPtr client
)
583 REQUEST(xRRGetOutputPropertyReq
);
584 RRPropertyPtr prop
, *prev
;
585 RRPropertyValuePtr prop_value
;
586 unsigned long n
, len
, ind
;
588 xRRGetOutputPropertyReply reply
;
591 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq
);
594 VERIFY_RR_OUTPUT(stuff
->output
, output
,
595 stuff
->delete ? DixWriteAccess
: DixReadAccess
);
597 if (!ValidAtom(stuff
->property
)) {
598 client
->errorValue
= stuff
->property
;
601 if ((stuff
->delete != xTrue
) && (stuff
->delete != xFalse
)) {
602 client
->errorValue
= stuff
->delete;
605 if ((stuff
->type
!= AnyPropertyType
) && !ValidAtom(stuff
->type
)) {
606 client
->errorValue
= stuff
->type
;
610 for (prev
= &output
->properties
; (prop
= *prev
); prev
= &prop
->next
)
611 if (prop
->propertyName
== stuff
->property
)
614 reply
= (xRRGetOutputPropertyReply
) {
616 .sequenceNumber
= client
->sequence
621 reply
.bytesAfter
= 0;
622 reply
.propertyType
= None
;
624 if (client
->swapped
) {
625 swaps(&reply
.sequenceNumber
);
626 swapl(&reply
.length
);
627 swapl(&reply
.propertyType
);
628 swapl(&reply
.bytesAfter
);
629 swapl(&reply
.nItems
);
631 WriteToClient(client
, sizeof(xRRGetOutputPropertyReply
), &reply
);
635 if (prop
->immutable
&& stuff
->delete)
638 prop_value
= RRGetOutputProperty(output
, stuff
->property
, stuff
->pending
);
642 /* If the request type and actual type don't match. Return the
643 property information, but not the data. */
645 if (((stuff
->type
!= prop_value
->type
) && (stuff
->type
!= AnyPropertyType
))
647 reply
.bytesAfter
= prop_value
->size
;
648 reply
.format
= prop_value
->format
;
651 reply
.propertyType
= prop_value
->type
;
652 if (client
->swapped
) {
653 swaps(&reply
.sequenceNumber
);
654 swapl(&reply
.length
);
655 swapl(&reply
.propertyType
);
656 swapl(&reply
.bytesAfter
);
657 swapl(&reply
.nItems
);
659 WriteToClient(client
, sizeof(xRRGetOutputPropertyReply
), &reply
);
664 * Return type, format, value to client
666 n
= (prop_value
->format
/ 8) * prop_value
->size
; /* size (bytes) of prop */
667 ind
= stuff
->longOffset
<< 2;
669 /* If longOffset is invalid such that it causes "len" to
670 be negative, it's a value error. */
673 client
->errorValue
= stuff
->longOffset
;
677 len
= min(n
- ind
, 4 * stuff
->longLength
);
684 reply
.bytesAfter
= n
- (ind
+ len
);
685 reply
.format
= prop_value
->format
;
686 reply
.length
= bytes_to_int32(len
);
687 if (prop_value
->format
)
688 reply
.nItems
= len
/ (prop_value
->format
/ 8);
691 reply
.propertyType
= prop_value
->type
;
693 if (stuff
->delete && (reply
.bytesAfter
== 0)) {
694 xRROutputPropertyNotifyEvent event
= {
695 .type
= RREventBase
+ RRNotify
,
696 .subCode
= RRNotify_OutputProperty
,
697 .output
= output
->id
,
698 .state
= PropertyDelete
,
699 .atom
= prop
->propertyName
,
700 .timestamp
= currentTime
.milliseconds
702 RRDeliverPropertyEvent(output
->pScreen
, (xEvent
*) &event
);
705 if (client
->swapped
) {
706 swaps(&reply
.sequenceNumber
);
707 swapl(&reply
.length
);
708 swapl(&reply
.propertyType
);
709 swapl(&reply
.bytesAfter
);
710 swapl(&reply
.nItems
);
712 WriteToClient(client
, sizeof(xGenericReply
), &reply
);
714 memcpy(extra
, (char *) prop_value
->data
+ ind
, len
);
715 switch (reply
.format
) {
717 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap32Write
;
720 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap16Write
;
723 client
->pSwapReplyFunc
= (ReplySwapPtr
) WriteToClient
;
726 WriteSwappedDataToClient(client
, len
, extra
);
730 if (stuff
->delete && (reply
.bytesAfter
== 0)) { /* delete the Property */
732 RRDestroyOutputProperty(prop
);