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 xRRProviderPropertyNotifyEvent
*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
& RRProviderPropertyNotifyMask
))
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 RRDestroyProviderProperty(RRPropertyPtr prop
)
59 free(prop
->valid_values
);
60 free(prop
->current
.data
);
61 free(prop
->pending
.data
);
66 RRDeleteProperty(RRProviderRec
* provider
, RRPropertyRec
* prop
)
68 xRRProviderPropertyNotifyEvent event
= {
69 .type
= RREventBase
+ RRNotify
,
70 .subCode
= RRNotify_ProviderProperty
,
71 .provider
= provider
->id
,
72 .state
= PropertyDelete
,
73 .atom
= prop
->propertyName
,
74 .timestamp
= currentTime
.milliseconds
77 RRDeliverPropertyEvent(provider
->pScreen
, (xEvent
*) &event
);
79 RRDestroyProviderProperty(prop
);
83 RRDeleteAllProviderProperties(RRProviderPtr provider
)
85 RRPropertyPtr prop
, next
;
87 for (prop
= provider
->properties
; prop
; prop
= next
) {
89 RRDeleteProperty(provider
, prop
);
94 RRInitProviderPropertyValue(RRPropertyValuePtr property_value
)
96 property_value
->type
= None
;
97 property_value
->format
= 0;
98 property_value
->size
= 0;
99 property_value
->data
= NULL
;
103 RRCreateProviderProperty(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 RRInitProviderPropertyValue(&prop
->current
);
118 RRInitProviderPropertyValue(&prop
->pending
);
123 RRDeleteProviderProperty(RRProviderPtr provider
, Atom property
)
125 RRPropertyRec
*prop
, **prev
;
127 for (prev
= &provider
->properties
; (prop
= *prev
); prev
= &(prop
->next
))
128 if (prop
->propertyName
== property
) {
130 RRDeleteProperty(provider
, prop
);
136 RRChangeProviderProperty(RRProviderPtr provider
, Atom property
, Atom type
,
137 int format
, int mode
, unsigned long len
,
138 pointer value
, Bool sendevent
, Bool pending
)
141 rrScrPrivPtr pScrPriv
= rrGetScrPriv(provider
->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
= RRQueryProviderProperty(provider
, property
);
153 if (!prop
) { /* just add to list */
154 prop
= RRCreateProviderProperty(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 RRDestroyProviderProperty(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
->rrProviderSetProperty
&&
217 !pScrPriv
->rrProviderSetProperty(provider
->pScreen
, provider
,
218 prop
->propertyName
, &new_value
)) {
220 RRDestroyProviderProperty(prop
);
221 free(new_value
.data
);
224 free(prop_value
->data
);
225 *prop_value
= new_value
;
233 prop
->next
= provider
->properties
;
234 provider
->properties
= prop
;
237 if (pending
&& prop
->is_pending
)
238 provider
->pendingProperties
= TRUE
;
241 xRRProviderPropertyNotifyEvent event
= {
242 .type
= RREventBase
+ RRNotify
,
243 .subCode
= RRNotify_ProviderProperty
,
244 .provider
= provider
->id
,
245 .state
= PropertyNewValue
,
246 .atom
= prop
->propertyName
,
247 .timestamp
= currentTime
.milliseconds
249 RRDeliverPropertyEvent(provider
->pScreen
, (xEvent
*) &event
);
255 RRPostProviderPendingProperties(RRProviderPtr provider
)
257 RRPropertyValuePtr pending_value
;
258 RRPropertyValuePtr current_value
;
259 RRPropertyPtr property
;
262 if (!provider
->pendingProperties
)
265 provider
->pendingProperties
= FALSE
;
266 for (property
= provider
->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 (RRChangeProviderProperty(provider
, property
->propertyName
,
286 pending_value
->type
, pending_value
->format
,
287 PropModeReplace
, pending_value
->size
,
288 pending_value
->data
, TRUE
, FALSE
) != Success
)
295 RRQueryProviderProperty(RRProviderPtr provider
, Atom property
)
299 for (prop
= provider
->properties
; prop
; prop
= prop
->next
)
300 if (prop
->propertyName
== property
)
306 RRGetProviderProperty(RRProviderPtr provider
, Atom property
, Bool pending
)
308 RRPropertyPtr prop
= RRQueryProviderProperty(provider
, property
);
309 rrScrPrivPtr pScrPriv
= rrGetScrPriv(provider
->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
->rrProviderGetProperty
)
319 pScrPriv
->rrProviderGetProperty(provider
->pScreen
, provider
,
322 return &prop
->current
;
327 RRConfigureProviderProperty(RRProviderPtr provider
, Atom property
,
328 Bool pending
, Bool range
, Bool immutable
,
329 int num_values
, INT32
*values
)
331 RRPropertyPtr prop
= RRQueryProviderProperty(provider
, property
);
336 prop
= RRCreateProviderProperty(property
);
341 else if (prop
->immutable
&& !immutable
)
345 * ranges must have even number of values
347 if (range
&& (num_values
& 1)) {
349 RRDestroyProviderProperty(prop
);
353 new_values
= malloc(num_values
* sizeof(INT32
));
354 if (!new_values
&& num_values
) {
356 RRDestroyProviderProperty(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 RRInitProviderPropertyValue(&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
= provider
->properties
;
380 provider
->properties
= prop
;
387 ProcRRListProviderProperties(ClientPtr client
)
389 REQUEST(xRRListProviderPropertiesReq
);
390 Atom
*pAtoms
= NULL
, *temppAtoms
;
391 xRRListProviderPropertiesReply rep
;
393 RRProviderPtr provider
;
396 REQUEST_SIZE_MATCH(xRRListProviderPropertiesReq
);
398 VERIFY_RR_PROVIDER(stuff
->provider
, provider
, DixReadAccess
);
400 for (prop
= provider
->properties
; prop
; prop
= prop
->next
)
403 if (!(pAtoms
= (Atom
*) malloc(numProps
* sizeof(Atom
))))
406 rep
= (xRRListProviderPropertiesReply
) {
408 .sequenceNumber
= client
->sequence
,
409 .length
= bytes_to_int32(numProps
* sizeof(Atom
)),
412 if (client
->swapped
) {
413 swaps(&rep
.sequenceNumber
);
418 for (prop
= provider
->properties
; prop
; prop
= prop
->next
)
419 *temppAtoms
++ = prop
->propertyName
;
421 WriteToClient(client
, sizeof(xRRListProviderPropertiesReply
), (char *) &rep
);
423 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
424 WriteSwappedDataToClient(client
, numProps
* sizeof(Atom
), pAtoms
);
431 ProcRRQueryProviderProperty(ClientPtr client
)
433 REQUEST(xRRQueryProviderPropertyReq
);
434 xRRQueryProviderPropertyReply rep
;
435 RRProviderPtr provider
;
439 REQUEST_SIZE_MATCH(xRRQueryProviderPropertyReq
);
441 VERIFY_RR_PROVIDER(stuff
->provider
, provider
, DixReadAccess
);
443 prop
= RRQueryProviderProperty(provider
, stuff
->property
);
447 if (prop
->num_valid
) {
448 extra
= malloc(prop
->num_valid
* sizeof(INT32
));
452 rep
= (xRRQueryProviderPropertyReply
) {
454 .sequenceNumber
= client
->sequence
,
455 .length
= prop
->num_valid
,
456 .pending
= prop
->is_pending
,
457 .range
= prop
->range
,
458 .immutable
= prop
->immutable
460 if (client
->swapped
) {
461 swaps(&rep
.sequenceNumber
);
464 WriteToClient(client
, sizeof(xRRQueryProviderPropertyReply
), (char *) &rep
);
465 if (prop
->num_valid
) {
466 memcpy(extra
, prop
->valid_values
, prop
->num_valid
* sizeof(INT32
));
467 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
468 WriteSwappedDataToClient(client
, prop
->num_valid
* sizeof(INT32
),
476 ProcRRConfigureProviderProperty(ClientPtr client
)
478 REQUEST(xRRConfigureProviderPropertyReq
);
479 RRProviderPtr provider
;
482 REQUEST_AT_LEAST_SIZE(xRRConfigureProviderPropertyReq
);
484 VERIFY_RR_PROVIDER(stuff
->provider
, provider
, DixReadAccess
);
487 stuff
->length
- bytes_to_int32(sizeof(xRRConfigureProviderPropertyReq
));
488 return RRConfigureProviderProperty(provider
, stuff
->property
, stuff
->pending
,
489 stuff
->range
, FALSE
, num_valid
,
490 (INT32
*) (stuff
+ 1));
494 ProcRRChangeProviderProperty(ClientPtr client
)
496 REQUEST(xRRChangeProviderPropertyReq
);
497 RRProviderPtr provider
;
504 REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq
);
506 format
= stuff
->format
;
508 if ((mode
!= PropModeReplace
) && (mode
!= PropModeAppend
) &&
509 (mode
!= PropModePrepend
)) {
510 client
->errorValue
= mode
;
513 if ((format
!= 8) && (format
!= 16) && (format
!= 32)) {
514 client
->errorValue
= format
;
518 if (len
> bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq
))))
520 sizeInBytes
= format
>> 3;
521 totalSize
= len
* sizeInBytes
;
522 REQUEST_FIXED_SIZE(xRRChangeProviderPropertyReq
, totalSize
);
524 VERIFY_RR_PROVIDER(stuff
->provider
, provider
, DixReadAccess
);
526 if (!ValidAtom(stuff
->property
)) {
527 client
->errorValue
= stuff
->property
;
530 if (!ValidAtom(stuff
->type
)) {
531 client
->errorValue
= stuff
->type
;
535 err
= RRChangeProviderProperty(provider
, stuff
->property
,
536 stuff
->type
, (int) format
,
537 (int) mode
, len
, (pointer
) &stuff
[1], TRUE
,
546 ProcRRDeleteProviderProperty(ClientPtr client
)
548 REQUEST(xRRDeleteProviderPropertyReq
);
549 RRProviderPtr provider
;
552 REQUEST_SIZE_MATCH(xRRDeleteProviderPropertyReq
);
554 VERIFY_RR_PROVIDER(stuff
->provider
, provider
, DixReadAccess
);
556 if (!ValidAtom(stuff
->property
)) {
557 client
->errorValue
= stuff
->property
;
561 prop
= RRQueryProviderProperty(provider
, stuff
->property
);
563 client
->errorValue
= stuff
->property
;
567 if (prop
->immutable
) {
568 client
->errorValue
= stuff
->property
;
572 RRDeleteProviderProperty(provider
, stuff
->property
);
577 ProcRRGetProviderProperty(ClientPtr client
)
579 REQUEST(xRRGetProviderPropertyReq
);
580 RRPropertyPtr prop
, *prev
;
581 RRPropertyValuePtr prop_value
;
582 unsigned long n
, len
, ind
;
583 RRProviderPtr provider
;
584 xRRGetProviderPropertyReply reply
= {
586 .sequenceNumber
= client
->sequence
590 REQUEST_SIZE_MATCH(xRRGetProviderPropertyReq
);
593 VERIFY_RR_PROVIDER(stuff
->provider
, provider
,
594 stuff
->delete ? DixWriteAccess
: DixReadAccess
);
596 if (!ValidAtom(stuff
->property
)) {
597 client
->errorValue
= stuff
->property
;
600 if ((stuff
->delete != xTrue
) && (stuff
->delete != xFalse
)) {
601 client
->errorValue
= stuff
->delete;
604 if ((stuff
->type
!= AnyPropertyType
) && !ValidAtom(stuff
->type
)) {
605 client
->errorValue
= stuff
->type
;
609 for (prev
= &provider
->properties
; (prop
= *prev
); prev
= &prop
->next
)
610 if (prop
->propertyName
== stuff
->property
)
616 reply
.bytesAfter
= 0;
617 reply
.propertyType
= None
;
619 if (client
->swapped
) {
620 swaps(&reply
.sequenceNumber
);
621 swapl(&reply
.length
);
622 swapl(&reply
.propertyType
);
623 swapl(&reply
.bytesAfter
);
624 swapl(&reply
.nItems
);
626 WriteToClient(client
, sizeof(xRRGetProviderPropertyReply
), &reply
);
630 if (prop
->immutable
&& stuff
->delete)
633 prop_value
= RRGetProviderProperty(provider
, stuff
->property
, stuff
->pending
);
637 /* If the request type and actual type don't match. Return the
638 property information, but not the data. */
640 if (((stuff
->type
!= prop_value
->type
) && (stuff
->type
!= AnyPropertyType
))
642 reply
.bytesAfter
= prop_value
->size
;
643 reply
.format
= prop_value
->format
;
646 reply
.propertyType
= prop_value
->type
;
647 if (client
->swapped
) {
648 swaps(&reply
.sequenceNumber
);
649 swapl(&reply
.length
);
650 swapl(&reply
.propertyType
);
651 swapl(&reply
.bytesAfter
);
652 swapl(&reply
.nItems
);
654 WriteToClient(client
, sizeof(xRRGetProviderPropertyReply
), &reply
);
659 * Return type, format, value to client
661 n
= (prop_value
->format
/ 8) * prop_value
->size
; /* size (bytes) of prop */
662 ind
= stuff
->longOffset
<< 2;
664 /* If longOffset is invalid such that it causes "len" to
665 be negative, it's a value error. */
668 client
->errorValue
= stuff
->longOffset
;
672 len
= min(n
- ind
, 4 * stuff
->longLength
);
679 reply
.bytesAfter
= n
- (ind
+ len
);
680 reply
.format
= prop_value
->format
;
681 reply
.length
= bytes_to_int32(len
);
682 if (prop_value
->format
)
683 reply
.nItems
= len
/ (prop_value
->format
/ 8);
686 reply
.propertyType
= prop_value
->type
;
688 if (stuff
->delete && (reply
.bytesAfter
== 0)) {
689 xRRProviderPropertyNotifyEvent event
= {
690 .type
= RREventBase
+ RRNotify
,
691 .subCode
= RRNotify_ProviderProperty
,
692 .provider
= provider
->id
,
693 .state
= PropertyDelete
,
694 .atom
= prop
->propertyName
,
695 .timestamp
= currentTime
.milliseconds
697 RRDeliverPropertyEvent(provider
->pScreen
, (xEvent
*) &event
);
700 if (client
->swapped
) {
701 swaps(&reply
.sequenceNumber
);
702 swapl(&reply
.length
);
703 swapl(&reply
.propertyType
);
704 swapl(&reply
.bytesAfter
);
705 swapl(&reply
.nItems
);
707 WriteToClient(client
, sizeof(xGenericReply
), &reply
);
709 memcpy(extra
, (char *) prop_value
->data
+ ind
, len
);
710 switch (reply
.format
) {
712 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap32Write
;
715 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap16Write
;
718 client
->pSwapReplyFunc
= (ReplySwapPtr
) WriteToClient
;
721 WriteSwappedDataToClient(client
, len
, extra
);
725 if (stuff
->delete && (reply
.bytesAfter
== 0)) { /* delete the Property */
727 RRDestroyProviderProperty(prop
);