Add patch that contain Mali fixes.
[deb_xorg-server.git] / randr / rrproperty.c
CommitLineData
a09e091a
JB
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 xRROutputPropertyNotifyEvent *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 & RROutputPropertyNotifyMask))
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
57RRDestroyOutputProperty(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(RROutputRec * output, RRPropertyRec * prop)
67{
68 xRROutputPropertyNotifyEvent event = {
69 .type = RREventBase + RRNotify,
70 .subCode = RRNotify_OutputProperty,
71 .output = output->id,
72 .state = PropertyDelete,
73 .atom = prop->propertyName,
74 .timestamp = currentTime.milliseconds
75 };
76
77 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
78
79 RRDestroyOutputProperty(prop);
80}
81
82void
83RRDeleteAllOutputProperties(RROutputPtr output)
84{
85 RRPropertyPtr prop, next;
86
87 for (prop = output->properties; prop; prop = next) {
88 next = prop->next;
89 RRDeleteProperty(output, prop);
90 }
91}
92
93static void
94RRInitOutputPropertyValue(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
103RRCreateOutputProperty(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 RRInitOutputPropertyValue(&prop->current);
118 RRInitOutputPropertyValue(&prop->pending);
119 return prop;
120}
121
122void
123RRDeleteOutputProperty(RROutputPtr output, Atom property)
124{
125 RRPropertyRec *prop, **prev;
126
127 for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
128 if (prop->propertyName == property) {
129 *prev = prop->next;
130 RRDeleteProperty(output, prop);
131 return;
132 }
133}
134
135int
136RRChangeOutputProperty(RROutputPtr output, 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(output->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 = RRQueryOutputProperty(output, property);
153 if (!prop) { /* just add to list */
154 prop = RRCreateOutputProperty(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 RRDestroyOutputProperty(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->rrOutputSetProperty &&
217 !pScrPriv->rrOutputSetProperty(output->pScreen, output,
218 prop->propertyName, &new_value)) {
219 free(new_value.data);
220 if (add)
221 RRDestroyOutputProperty(prop);
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 = output->properties;
234 output->properties = prop;
235 }
236
237 if (pending && prop->is_pending)
238 output->pendingProperties = TRUE;
239
240 if (sendevent) {
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
248 };
249 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
250 }
251 return Success;
252}
253
254Bool
255RRPostPendingProperties(RROutputPtr output)
256{
257 RRPropertyValuePtr pending_value;
258 RRPropertyValuePtr current_value;
259 RRPropertyPtr property;
260 Bool ret = TRUE;
261
262 if (!output->pendingProperties)
263 return TRUE;
264
265 output->pendingProperties = FALSE;
266 for (property = output->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 (RRChangeOutputProperty(output, 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
295RRQueryOutputProperty(RROutputPtr output, Atom property)
296{
297 RRPropertyPtr prop;
298
299 for (prop = output->properties; prop; prop = prop->next)
300 if (prop->propertyName == property)
301 return prop;
302 return NULL;
303}
304
305RRPropertyValuePtr
306RRGetOutputProperty(RROutputPtr output, Atom property, Bool pending)
307{
308 RRPropertyPtr prop = RRQueryOutputProperty(output, property);
309 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->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->rrOutputGetProperty)
319 pScrPriv->rrOutputGetProperty(output->pScreen, output,
320 prop->propertyName);
321#endif
322 return &prop->current;
323 }
324}
325
326int
327RRConfigureOutputProperty(RROutputPtr output, Atom property,
328 Bool pending, Bool range, Bool immutable,
329 int num_values, INT32 *values)
330{
331 RRPropertyPtr prop = RRQueryOutputProperty(output, property);
332 Bool add = FALSE;
333 INT32 *new_values;
334
335 if (!prop) {
336 prop = RRCreateOutputProperty(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 RRDestroyOutputProperty(prop);
350 return BadMatch;
351 }
352
353 new_values = malloc(num_values * sizeof(INT32));
354 if (!new_values && num_values) {
355 if (add)
356 RRDestroyOutputProperty(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 RRInitOutputPropertyValue(&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 = output->properties;
380 output->properties = prop;
381 }
382
383 return Success;
384}
385
386int
387ProcRRListOutputProperties(ClientPtr client)
388{
389 REQUEST(xRRListOutputPropertiesReq);
390 Atom *pAtoms = NULL;
391 xRRListOutputPropertiesReply rep;
392 int numProps = 0;
393 RROutputPtr output;
394 RRPropertyPtr prop;
395
396 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
397
398 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
399
400 for (prop = output->properties; prop; prop = prop->next)
401 numProps++;
402 if (numProps)
403 if (!(pAtoms = (Atom *) malloc(numProps * sizeof(Atom))))
404 return BadAlloc;
405
406 rep = (xRRListOutputPropertiesReply) {
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 WriteToClient(client, sizeof(xRRListOutputPropertiesReply), &rep);
418
419 if (numProps) {
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;
424
425 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
426 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
427 free(pAtoms);
428 }
429 return Success;
430}
431
432int
433ProcRRQueryOutputProperty(ClientPtr client)
434{
435 REQUEST(xRRQueryOutputPropertyReq);
436 xRRQueryOutputPropertyReply rep;
437 RROutputPtr output;
438 RRPropertyPtr prop;
439 char *extra = NULL;
440
441 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
442
443 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
444
445 prop = RRQueryOutputProperty(output, stuff->property);
446 if (!prop)
447 return BadName;
448
449 if (prop->num_valid) {
450 extra = malloc(prop->num_valid * sizeof(INT32));
451 if (!extra)
452 return BadAlloc;
453 }
454
455 rep = (xRRQueryOutputPropertyReply) {
456 .type = X_Reply,
457 .sequenceNumber = client->sequence,
458 .length = prop->num_valid,
459 .pending = prop->is_pending,
460 .range = prop->range,
461 .immutable = prop->immutable
462 };
463
464 if (client->swapped) {
465 swaps(&rep.sequenceNumber);
466 swapl(&rep.length);
467 }
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),
473 extra);
474 free(extra);
475 }
476 return Success;
477}
478
479int
480ProcRRConfigureOutputProperty(ClientPtr client)
481{
482 REQUEST(xRRConfigureOutputPropertyReq);
483 RROutputPtr output;
484 int num_valid;
485
486 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
487
488 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
489
490 num_valid =
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));
495}
496
497int
498ProcRRChangeOutputProperty(ClientPtr client)
499{
500 REQUEST(xRRChangeOutputPropertyReq);
501 RROutputPtr output;
502 char format, mode;
503 unsigned long len;
504 int sizeInBytes;
505 int totalSize;
506 int err;
507
508 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
509 UpdateCurrentTime();
510 format = stuff->format;
511 mode = stuff->mode;
512 if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
513 (mode != PropModePrepend)) {
514 client->errorValue = mode;
515 return BadValue;
516 }
517 if ((format != 8) && (format != 16) && (format != 32)) {
518 client->errorValue = format;
519 return BadValue;
520 }
521 len = stuff->nUnits;
522 if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
523 return BadLength;
524 sizeInBytes = format >> 3;
525 totalSize = len * sizeInBytes;
526 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
527
528 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
529
530 if (!ValidAtom(stuff->property)) {
531 client->errorValue = stuff->property;
532 return BadAtom;
533 }
534 if (!ValidAtom(stuff->type)) {
535 client->errorValue = stuff->type;
536 return BadAtom;
537 }
538
539 err = RRChangeOutputProperty(output, stuff->property,
540 stuff->type, (int) format,
541 (int) mode, len, (pointer) &stuff[1], TRUE,
542 TRUE);
543 if (err != Success)
544 return err;
545 else
546 return Success;
547}
548
549int
550ProcRRDeleteOutputProperty(ClientPtr client)
551{
552 REQUEST(xRRDeleteOutputPropertyReq);
553 RROutputPtr output;
554 RRPropertyPtr prop;
555
556 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
557 UpdateCurrentTime();
558 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
559
560 if (!ValidAtom(stuff->property)) {
561 client->errorValue = stuff->property;
562 return BadAtom;
563 }
564
565 prop = RRQueryOutputProperty(output, stuff->property);
566 if (!prop) {
567 client->errorValue = stuff->property;
568 return BadName;
569 }
570
571 if (prop->immutable) {
572 client->errorValue = stuff->property;
573 return BadAccess;
574 }
575
576 RRDeleteOutputProperty(output, stuff->property);
577 return Success;
578}
579
580int
581ProcRRGetOutputProperty(ClientPtr client)
582{
583 REQUEST(xRRGetOutputPropertyReq);
584 RRPropertyPtr prop, *prev;
585 RRPropertyValuePtr prop_value;
586 unsigned long n, len, ind;
587 RROutputPtr output;
588 xRRGetOutputPropertyReply reply;
589 char *extra = NULL;
590
591 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
592 if (stuff->delete)
593 UpdateCurrentTime();
594 VERIFY_RR_OUTPUT(stuff->output, output,
595 stuff->delete ? DixWriteAccess : DixReadAccess);
596
597 if (!ValidAtom(stuff->property)) {
598 client->errorValue = stuff->property;
599 return BadAtom;
600 }
601 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
602 client->errorValue = stuff->delete;
603 return BadValue;
604 }
605 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
606 client->errorValue = stuff->type;
607 return BadAtom;
608 }
609
610 for (prev = &output->properties; (prop = *prev); prev = &prop->next)
611 if (prop->propertyName == stuff->property)
612 break;
613
614 reply = (xRRGetOutputPropertyReply) {
615 .type = X_Reply,
616 .sequenceNumber = client->sequence
617 };
618 if (!prop) {
619 reply.nItems = 0;
620 reply.length = 0;
621 reply.bytesAfter = 0;
622 reply.propertyType = None;
623 reply.format = 0;
624 if (client->swapped) {
625 swaps(&reply.sequenceNumber);
626 swapl(&reply.length);
627 swapl(&reply.propertyType);
628 swapl(&reply.bytesAfter);
629 swapl(&reply.nItems);
630 }
631 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
632 return Success;
633 }
634
635 if (prop->immutable && stuff->delete)
636 return BadAccess;
637
638 prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
639 if (!prop_value)
640 return BadAtom;
641
642 /* If the request type and actual type don't match. Return the
643 property information, but not the data. */
644
645 if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType))
646 ) {
647 reply.bytesAfter = prop_value->size;
648 reply.format = prop_value->format;
649 reply.length = 0;
650 reply.nItems = 0;
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);
658 }
659 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
660 return Success;
661 }
662
663/*
664 * Return type, format, value to client
665 */
666 n = (prop_value->format / 8) * prop_value->size; /* size (bytes) of prop */
667 ind = stuff->longOffset << 2;
668
669 /* If longOffset is invalid such that it causes "len" to
670 be negative, it's a value error. */
671
672 if (n < ind) {
673 client->errorValue = stuff->longOffset;
674 return BadValue;
675 }
676
677 len = min(n - ind, 4 * stuff->longLength);
678
679 if (len) {
680 extra = malloc(len);
681 if (!extra)
682 return BadAlloc;
683 }
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);
689 else
690 reply.nItems = 0;
691 reply.propertyType = prop_value->type;
692
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
701 };
702 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
703 }
704
705 if (client->swapped) {
706 swaps(&reply.sequenceNumber);
707 swapl(&reply.length);
708 swapl(&reply.propertyType);
709 swapl(&reply.bytesAfter);
710 swapl(&reply.nItems);
711 }
712 WriteToClient(client, sizeof(xGenericReply), &reply);
713 if (len) {
714 memcpy(extra, (char *) prop_value->data + ind, len);
715 switch (reply.format) {
716 case 32:
717 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
718 break;
719 case 16:
720 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
721 break;
722 default:
723 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
724 break;
725 }
726 WriteSwappedDataToClient(client, len, extra);
727 free(extra);
728 }
729
730 if (stuff->delete && (reply.bytesAfter == 0)) { /* delete the Property */
731 *prev = prop->next;
732 RRDestroyOutputProperty(prop);
733 }
734 return Success;
735}