Imported Upstream version 1.15.1
[deb_xorg-server.git] / randr / rrproviderproperty.c
... / ...
CommitLineData
1/*
2 * Copyright © 2006 Keith Packard
3 *
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.
13 *
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
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "propertyst.h"
25#include "swaprep.h"
26
27static int
28DeliverPropertyEvent(WindowPtr pWin, void *value)
29{
30 xRRProviderPropertyNotifyEvent *event = value;
31 RREventPtr *pHead, pRREvent;
32
33 dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
34 RREventType, serverClient, DixReadAccess);
35 if (!pHead)
36 return WT_WALKCHILDREN;
37
38 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
39 if (!(pRREvent->mask & RRProviderPropertyNotifyMask))
40 continue;
41
42 event->window = pRREvent->window->drawable.id;
43 WriteEventsToClient(pRREvent->client, 1, (xEvent *) event);
44 }
45
46 return WT_WALKCHILDREN;
47}
48
49static void
50RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
51{
52 if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
53 WalkTree(pScreen, DeliverPropertyEvent, event);
54}
55
56static void
57RRDestroyProviderProperty(RRPropertyPtr prop)
58{
59 free(prop->valid_values);
60 free(prop->current.data);
61 free(prop->pending.data);
62 free(prop);
63}
64
65static void
66RRDeleteProperty(RRProviderRec * provider, RRPropertyRec * prop)
67{
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
75 };
76
77 RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
78
79 RRDestroyProviderProperty(prop);
80}
81
82void
83RRDeleteAllProviderProperties(RRProviderPtr provider)
84{
85 RRPropertyPtr prop, next;
86
87 for (prop = provider->properties; prop; prop = next) {
88 next = prop->next;
89 RRDeleteProperty(provider, prop);
90 }
91}
92
93static void
94RRInitProviderPropertyValue(RRPropertyValuePtr property_value)
95{
96 property_value->type = None;
97 property_value->format = 0;
98 property_value->size = 0;
99 property_value->data = NULL;
100}
101
102static RRPropertyPtr
103RRCreateProviderProperty(Atom property)
104{
105 RRPropertyPtr prop;
106
107 prop = (RRPropertyPtr) malloc(sizeof(RRPropertyRec));
108 if (!prop)
109 return NULL;
110 prop->next = NULL;
111 prop->propertyName = property;
112 prop->is_pending = FALSE;
113 prop->range = FALSE;
114 prop->immutable = FALSE;
115 prop->num_valid = 0;
116 prop->valid_values = NULL;
117 RRInitProviderPropertyValue(&prop->current);
118 RRInitProviderPropertyValue(&prop->pending);
119 return prop;
120}
121
122void
123RRDeleteProviderProperty(RRProviderPtr provider, Atom property)
124{
125 RRPropertyRec *prop, **prev;
126
127 for (prev = &provider->properties; (prop = *prev); prev = &(prop->next))
128 if (prop->propertyName == property) {
129 *prev = prop->next;
130 RRDeleteProperty(provider, prop);
131 return;
132 }
133}
134
135int
136RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type,
137 int format, int mode, unsigned long len,
138 pointer value, Bool sendevent, Bool pending)
139{
140 RRPropertyPtr prop;
141 rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen);
142 int size_in_bytes;
143 int total_size;
144 unsigned long total_len;
145 RRPropertyValuePtr prop_value;
146 RRPropertyValueRec new_value;
147 Bool add = FALSE;
148
149 size_in_bytes = format >> 3;
150
151 /* first see if property already exists */
152 prop = RRQueryProviderProperty(provider, property);
153 if (!prop) { /* just add to list */
154 prop = RRCreateProviderProperty(property);
155 if (!prop)
156 return BadAlloc;
157 add = TRUE;
158 mode = PropModeReplace;
159 }
160 if (pending && prop->is_pending)
161 prop_value = &prop->pending;
162 else
163 prop_value = &prop->current;
164
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. */
169
170 if ((format != prop_value->format) && (mode != PropModeReplace))
171 return BadMatch;
172 if ((prop_value->type != type) && (mode != PropModeReplace))
173 return BadMatch;
174 new_value = *prop_value;
175 if (mode == PropModeReplace)
176 total_len = len;
177 else
178 total_len = prop_value->size + len;
179
180 if (mode == PropModeReplace || len > 0) {
181 pointer new_data = NULL, old_data = NULL;
182
183 total_size = total_len * size_in_bytes;
184 new_value.data = (pointer) malloc(total_size);
185 if (!new_value.data && total_size) {
186 if (add)
187 RRDestroyProviderProperty(prop);
188 return BadAlloc;
189 }
190 new_value.size = len;
191 new_value.type = type;
192 new_value.format = format;
193
194 switch (mode) {
195 case PropModeReplace:
196 new_data = new_value.data;
197 old_data = NULL;
198 break;
199 case PropModeAppend:
200 new_data = (pointer) (((char *) new_value.data) +
201 (prop_value->size * size_in_bytes));
202 old_data = new_value.data;
203 break;
204 case PropModePrepend:
205 new_data = new_value.data;
206 old_data = (pointer) (((char *) new_value.data) +
207 (prop_value->size * size_in_bytes));
208 break;
209 }
210 if (new_data)
211 memcpy((char *) new_data, (char *) value, len * size_in_bytes);
212 if (old_data)
213 memcpy((char *) old_data, (char *) prop_value->data,
214 prop_value->size * size_in_bytes);
215
216 if (pending && pScrPriv->rrProviderSetProperty &&
217 !pScrPriv->rrProviderSetProperty(provider->pScreen, provider,
218 prop->propertyName, &new_value)) {
219 if (add)
220 RRDestroyProviderProperty(prop);
221 free(new_value.data);
222 return BadValue;
223 }
224 free(prop_value->data);
225 *prop_value = new_value;
226 }
227
228 else if (len == 0) {
229 /* do nothing */
230 }
231
232 if (add) {
233 prop->next = provider->properties;
234 provider->properties = prop;
235 }
236
237 if (pending && prop->is_pending)
238 provider->pendingProperties = TRUE;
239
240 if (sendevent) {
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
248 };
249 RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
250 }
251 return Success;
252}
253
254Bool
255RRPostProviderPendingProperties(RRProviderPtr provider)
256{
257 RRPropertyValuePtr pending_value;
258 RRPropertyValuePtr current_value;
259 RRPropertyPtr property;
260 Bool ret = TRUE;
261
262 if (!provider->pendingProperties)
263 return TRUE;
264
265 provider->pendingProperties = FALSE;
266 for (property = provider->properties; property; property = property->next) {
267 /* Skip non-pending properties */
268 if (!property->is_pending)
269 continue;
270
271 pending_value = &property->pending;
272 current_value = &property->current;
273
274 /*
275 * If the pending and current values are equal, don't mark it
276 * as changed (which would deliver an event)
277 */
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)))
283 continue;
284
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)
289 ret = FALSE;
290 }
291 return ret;
292}
293
294RRPropertyPtr
295RRQueryProviderProperty(RRProviderPtr provider, Atom property)
296{
297 RRPropertyPtr prop;
298
299 for (prop = provider->properties; prop; prop = prop->next)
300 if (prop->propertyName == property)
301 return prop;
302 return NULL;
303}
304
305RRPropertyValuePtr
306RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending)
307{
308 RRPropertyPtr prop = RRQueryProviderProperty(provider, property);
309 rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen);
310
311 if (!prop)
312 return NULL;
313 if (pending && prop->is_pending)
314 return &prop->pending;
315 else {
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,
320 prop->propertyName);
321#endif
322 return &prop->current;
323 }
324}
325
326int
327RRConfigureProviderProperty(RRProviderPtr provider, Atom property,
328 Bool pending, Bool range, Bool immutable,
329 int num_values, INT32 *values)
330{
331 RRPropertyPtr prop = RRQueryProviderProperty(provider, property);
332 Bool add = FALSE;
333 INT32 *new_values;
334
335 if (!prop) {
336 prop = RRCreateProviderProperty(property);
337 if (!prop)
338 return BadAlloc;
339 add = TRUE;
340 }
341 else if (prop->immutable && !immutable)
342 return BadAccess;
343
344 /*
345 * ranges must have even number of values
346 */
347 if (range && (num_values & 1)) {
348 if (add)
349 RRDestroyProviderProperty(prop);
350 return BadMatch;
351 }
352
353 new_values = malloc(num_values * sizeof(INT32));
354 if (!new_values && num_values) {
355 if (add)
356 RRDestroyProviderProperty(prop);
357 return BadAlloc;
358 }
359 if (num_values)
360 memcpy(new_values, values, num_values * sizeof(INT32));
361
362 /*
363 * Property moving from pending to non-pending
364 * loses any pending values
365 */
366 if (prop->is_pending && !pending) {
367 free(prop->pending.data);
368 RRInitProviderPropertyValue(&prop->pending);
369 }
370
371 prop->is_pending = pending;
372 prop->range = range;
373 prop->immutable = immutable;
374 prop->num_valid = num_values;
375 free(prop->valid_values);
376 prop->valid_values = new_values;
377
378 if (add) {
379 prop->next = provider->properties;
380 provider->properties = prop;
381 }
382
383 return Success;
384}
385
386int
387ProcRRListProviderProperties(ClientPtr client)
388{
389 REQUEST(xRRListProviderPropertiesReq);
390 Atom *pAtoms = NULL, *temppAtoms;
391 xRRListProviderPropertiesReply rep;
392 int numProps = 0;
393 RRProviderPtr provider;
394 RRPropertyPtr prop;
395
396 REQUEST_SIZE_MATCH(xRRListProviderPropertiesReq);
397
398 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
399
400 for (prop = provider->properties; prop; prop = prop->next)
401 numProps++;
402 if (numProps)
403 if (!(pAtoms = (Atom *) malloc(numProps * sizeof(Atom))))
404 return BadAlloc;
405
406 rep = (xRRListProviderPropertiesReply) {
407 .type = X_Reply,
408 .sequenceNumber = client->sequence,
409 .length = bytes_to_int32(numProps * sizeof(Atom)),
410 .nAtoms = numProps
411 };
412 if (client->swapped) {
413 swaps(&rep.sequenceNumber);
414 swapl(&rep.length);
415 swaps(&rep.nAtoms);
416 }
417 temppAtoms = pAtoms;
418 for (prop = provider->properties; prop; prop = prop->next)
419 *temppAtoms++ = prop->propertyName;
420
421 WriteToClient(client, sizeof(xRRListProviderPropertiesReply), (char *) &rep);
422 if (numProps) {
423 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
424 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
425 free(pAtoms);
426 }
427 return Success;
428}
429
430int
431ProcRRQueryProviderProperty(ClientPtr client)
432{
433 REQUEST(xRRQueryProviderPropertyReq);
434 xRRQueryProviderPropertyReply rep;
435 RRProviderPtr provider;
436 RRPropertyPtr prop;
437 char *extra = NULL;
438
439 REQUEST_SIZE_MATCH(xRRQueryProviderPropertyReq);
440
441 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
442
443 prop = RRQueryProviderProperty(provider, stuff->property);
444 if (!prop)
445 return BadName;
446
447 if (prop->num_valid) {
448 extra = malloc(prop->num_valid * sizeof(INT32));
449 if (!extra)
450 return BadAlloc;
451 }
452 rep = (xRRQueryProviderPropertyReply) {
453 .type = X_Reply,
454 .sequenceNumber = client->sequence,
455 .length = prop->num_valid,
456 .pending = prop->is_pending,
457 .range = prop->range,
458 .immutable = prop->immutable
459 };
460 if (client->swapped) {
461 swaps(&rep.sequenceNumber);
462 swapl(&rep.length);
463 }
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),
469 extra);
470 free(extra);
471 }
472 return Success;
473}
474
475int
476ProcRRConfigureProviderProperty(ClientPtr client)
477{
478 REQUEST(xRRConfigureProviderPropertyReq);
479 RRProviderPtr provider;
480 int num_valid;
481
482 REQUEST_AT_LEAST_SIZE(xRRConfigureProviderPropertyReq);
483
484 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
485
486 num_valid =
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));
491}
492
493int
494ProcRRChangeProviderProperty(ClientPtr client)
495{
496 REQUEST(xRRChangeProviderPropertyReq);
497 RRProviderPtr provider;
498 char format, mode;
499 unsigned long len;
500 int sizeInBytes;
501 int totalSize;
502 int err;
503
504 REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq);
505 UpdateCurrentTime();
506 format = stuff->format;
507 mode = stuff->mode;
508 if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
509 (mode != PropModePrepend)) {
510 client->errorValue = mode;
511 return BadValue;
512 }
513 if ((format != 8) && (format != 16) && (format != 32)) {
514 client->errorValue = format;
515 return BadValue;
516 }
517 len = stuff->nUnits;
518 if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
519 return BadLength;
520 sizeInBytes = format >> 3;
521 totalSize = len * sizeInBytes;
522 REQUEST_FIXED_SIZE(xRRChangeProviderPropertyReq, totalSize);
523
524 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
525
526 if (!ValidAtom(stuff->property)) {
527 client->errorValue = stuff->property;
528 return BadAtom;
529 }
530 if (!ValidAtom(stuff->type)) {
531 client->errorValue = stuff->type;
532 return BadAtom;
533 }
534
535 err = RRChangeProviderProperty(provider, stuff->property,
536 stuff->type, (int) format,
537 (int) mode, len, (pointer) &stuff[1], TRUE,
538 TRUE);
539 if (err != Success)
540 return err;
541 else
542 return Success;
543}
544
545int
546ProcRRDeleteProviderProperty(ClientPtr client)
547{
548 REQUEST(xRRDeleteProviderPropertyReq);
549 RRProviderPtr provider;
550 RRPropertyPtr prop;
551
552 REQUEST_SIZE_MATCH(xRRDeleteProviderPropertyReq);
553 UpdateCurrentTime();
554 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
555
556 if (!ValidAtom(stuff->property)) {
557 client->errorValue = stuff->property;
558 return BadAtom;
559 }
560
561 prop = RRQueryProviderProperty(provider, stuff->property);
562 if (!prop) {
563 client->errorValue = stuff->property;
564 return BadName;
565 }
566
567 if (prop->immutable) {
568 client->errorValue = stuff->property;
569 return BadAccess;
570 }
571
572 RRDeleteProviderProperty(provider, stuff->property);
573 return Success;
574}
575
576int
577ProcRRGetProviderProperty(ClientPtr client)
578{
579 REQUEST(xRRGetProviderPropertyReq);
580 RRPropertyPtr prop, *prev;
581 RRPropertyValuePtr prop_value;
582 unsigned long n, len, ind;
583 RRProviderPtr provider;
584 xRRGetProviderPropertyReply reply = {
585 .type = X_Reply,
586 .sequenceNumber = client->sequence
587 };
588 char *extra = NULL;
589
590 REQUEST_SIZE_MATCH(xRRGetProviderPropertyReq);
591 if (stuff->delete)
592 UpdateCurrentTime();
593 VERIFY_RR_PROVIDER(stuff->provider, provider,
594 stuff->delete ? DixWriteAccess : DixReadAccess);
595
596 if (!ValidAtom(stuff->property)) {
597 client->errorValue = stuff->property;
598 return BadAtom;
599 }
600 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
601 client->errorValue = stuff->delete;
602 return BadValue;
603 }
604 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
605 client->errorValue = stuff->type;
606 return BadAtom;
607 }
608
609 for (prev = &provider->properties; (prop = *prev); prev = &prop->next)
610 if (prop->propertyName == stuff->property)
611 break;
612
613 if (!prop) {
614 reply.nItems = 0;
615 reply.length = 0;
616 reply.bytesAfter = 0;
617 reply.propertyType = None;
618 reply.format = 0;
619 if (client->swapped) {
620 swaps(&reply.sequenceNumber);
621 swapl(&reply.length);
622 swapl(&reply.propertyType);
623 swapl(&reply.bytesAfter);
624 swapl(&reply.nItems);
625 }
626 WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply);
627 return Success;
628 }
629
630 if (prop->immutable && stuff->delete)
631 return BadAccess;
632
633 prop_value = RRGetProviderProperty(provider, stuff->property, stuff->pending);
634 if (!prop_value)
635 return BadAtom;
636
637 /* If the request type and actual type don't match. Return the
638 property information, but not the data. */
639
640 if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType))
641 ) {
642 reply.bytesAfter = prop_value->size;
643 reply.format = prop_value->format;
644 reply.length = 0;
645 reply.nItems = 0;
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);
653 }
654 WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply);
655 return Success;
656 }
657
658/*
659 * Return type, format, value to client
660 */
661 n = (prop_value->format / 8) * prop_value->size; /* size (bytes) of prop */
662 ind = stuff->longOffset << 2;
663
664 /* If longOffset is invalid such that it causes "len" to
665 be negative, it's a value error. */
666
667 if (n < ind) {
668 client->errorValue = stuff->longOffset;
669 return BadValue;
670 }
671
672 len = min(n - ind, 4 * stuff->longLength);
673
674 if (len) {
675 extra = malloc(len);
676 if (!extra)
677 return BadAlloc;
678 }
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);
684 else
685 reply.nItems = 0;
686 reply.propertyType = prop_value->type;
687
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
696 };
697 RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
698 }
699
700 if (client->swapped) {
701 swaps(&reply.sequenceNumber);
702 swapl(&reply.length);
703 swapl(&reply.propertyType);
704 swapl(&reply.bytesAfter);
705 swapl(&reply.nItems);
706 }
707 WriteToClient(client, sizeof(xGenericReply), &reply);
708 if (len) {
709 memcpy(extra, (char *) prop_value->data + ind, len);
710 switch (reply.format) {
711 case 32:
712 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
713 break;
714 case 16:
715 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
716 break;
717 default:
718 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
719 break;
720 }
721 WriteSwappedDataToClient(client, len, extra);
722 free(extra);
723 }
724
725 if (stuff->delete && (reply.bytesAfter == 0)) { /* delete the Property */
726 *prev = prop->next;
727 RRDestroyProviderProperty(prop);
728 }
729 return Success;
730}