First import
[xorg_rtime.git] / xorg-server-1.4 / randr / rrproperty.c
blob5ac073f812799d8bd6f547bd26fff01a96750d83
1 /*
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
20 * OF THIS SOFTWARE.
23 #include "randrstr.h"
24 #include "propertyst.h"
25 #include "swaprep.h"
27 static void
28 RRDeliverEvent (ScreenPtr pScreen, xEvent *event, CARD32 mask)
33 void
34 RRDeleteAllOutputProperties (RROutputPtr output)
36 RRPropertyPtr prop, next;
37 xRROutputPropertyNotifyEvent event;
39 for (prop = output->properties; prop; prop = next)
41 next = 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);
53 xfree(prop);
57 static void
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;
66 static RRPropertyPtr
67 RRCreateOutputProperty (Atom property)
69 RRPropertyPtr prop;
71 prop = (RRPropertyPtr)xalloc(sizeof(RRPropertyRec));
72 if (!prop)
73 return NULL;
74 prop->next = NULL;
75 prop->propertyName = property;
76 prop->is_pending = FALSE;
77 prop->range = FALSE;
78 prop->immutable = FALSE;
79 prop->num_valid = 0;
80 prop->valid_values = NULL;
81 RRInitOutputPropertyValue (&prop->current);
82 RRInitOutputPropertyValue (&prop->pending);
83 return prop;
86 static void
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);
95 xfree(prop);
98 void
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)
106 break;
107 if (prop)
109 *prev = prop->next;
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)
126 RRPropertyPtr prop;
127 xRROutputPropertyNotifyEvent event;
128 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
129 int size_in_bytes;
130 int total_size;
131 unsigned long total_len;
132 RRPropertyValuePtr prop_value;
133 RRPropertyValueRec new_value;
134 Bool add = FALSE;
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);
143 if (!prop)
144 return(BadAlloc);
145 add = TRUE;
146 mode = PropModeReplace;
148 if (pending && prop->is_pending)
149 prop_value = &prop->pending;
150 else
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))
159 return(BadMatch);
160 if ((prop_value->type != type) && (mode != PropModeReplace))
161 return(BadMatch);
162 new_value = *prop_value;
163 if (mode == PropModeReplace)
164 total_len = len;
165 else
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)
176 if (add)
177 RRDestroyOutputProperty (prop);
178 return BadAlloc;
180 new_value.size = len;
181 new_value.type = type;
182 new_value.format = format;
184 switch (mode) {
185 case PropModeReplace:
186 new_data = new_value.data;
187 old_data = NULL;
188 break;
189 case PropModeAppend:
190 new_data = (pointer) (((char *) new_value.data) +
191 (prop_value->size * size_in_bytes));
192 old_data = new_value.data;
193 break;
194 case PropModePrepend:
195 new_data = new_value.data;
196 old_data = (pointer) (((char *) new_value.data) +
197 (prop_value->size * size_in_bytes));
198 break;
200 if (new_data)
201 memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
202 if (old_data)
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))
210 if (new_value.data)
211 xfree (new_value.data);
212 return (BadValue);
214 if (prop_value->data)
215 xfree (prop_value->data);
216 *prop_value = new_value;
219 else if (len == 0)
221 /* do nothing */
224 if (add)
226 prop->next = output->properties;
227 output->properties = prop;
230 if (pending && prop->is_pending)
231 output->pendingProperties = TRUE;
233 if (sendevent)
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);
243 return(Success);
246 Bool
247 RRPostPendingProperties (RROutputPtr output)
249 RRPropertyValuePtr pending_value;
250 RRPropertyValuePtr current_value;
251 RRPropertyPtr property;
252 Bool ret = TRUE;
254 if (!output->pendingProperties)
255 return TRUE;
257 output->pendingProperties = FALSE;
258 for (property = output->properties; property; property = property->next)
260 /* Skip non-pending properties */
261 if (!property->is_pending)
262 continue;
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))
276 continue;
278 if (RRChangeOutputProperty (output, property->propertyName,
279 pending_value->type, pending_value->format,
280 PropModeReplace, pending_value->size,
281 pending_value->data, TRUE,
282 FALSE) != Success)
283 ret = FALSE;
285 return ret;
288 RRPropertyPtr
289 RRQueryOutputProperty (RROutputPtr output, Atom property)
291 RRPropertyPtr prop;
293 for (prop = output->properties; prop; prop = prop->next)
294 if (prop->propertyName == property)
295 return prop;
296 return NULL;
299 RRPropertyValuePtr
300 RRGetOutputProperty (RROutputPtr output, Atom property, Bool pending)
302 RRPropertyPtr prop = RRQueryOutputProperty (output, property);
304 if (!prop)
305 return NULL;
306 if (pending && prop->is_pending)
307 return &prop->pending;
308 else
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);
318 Bool add = FALSE;
319 INT32 *new_values;
321 if (!prop)
323 prop = RRCreateOutputProperty (property);
324 if (!prop)
325 return(BadAlloc);
326 add = TRUE;
327 } else if (prop->immutable && !immutable)
328 return(BadAccess);
331 * ranges must have even number of values
333 if (range && (num_values & 1))
334 return BadMatch;
336 new_values = xalloc (num_values * sizeof (INT32));
337 if (!new_values && num_values)
338 return BadAlloc;
339 if (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;
354 prop->range = range;
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;
361 if (add) {
362 prop->next = output->properties;
363 output->properties = prop;
366 return Success;
370 ProcRRListOutputProperties (ClientPtr client)
372 REQUEST(xRRListOutputPropertiesReq);
373 Atom *pAtoms = NULL, *temppAtoms;
374 xRRListOutputPropertiesReply rep;
375 int numProps = 0;
376 RROutputPtr output;
377 RRPropertyPtr prop;
379 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
381 output = LookupOutput (client, stuff->output, DixReadAccess);
383 if (!output)
384 return RRErrorBase + BadRROutput;
386 for (prop = output->properties; prop; prop = prop->next)
387 numProps++;
388 if (numProps)
389 if(!(pAtoms = (Atom *)ALLOCATE_LOCAL(numProps * sizeof(Atom))))
390 return(BadAlloc);
392 rep.type = X_Reply;
393 rep.length = (numProps * sizeof(Atom)) >> 2;
394 rep.sequenceNumber = client->sequence;
395 rep.nAtoms = numProps;
396 if (client->swapped)
398 int n;
399 swaps (&rep.sequenceNumber, n);
400 swapl (&rep.length, n);
402 temppAtoms = pAtoms;
403 for (prop = output->properties; prop; prop = prop->next)
404 *temppAtoms++ = prop->propertyName;
406 WriteReplyToClient(client, sizeof(xRRListOutputPropertiesReply), &rep);
407 if (numProps)
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;
421 RROutputPtr output;
422 RRPropertyPtr prop;
424 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
426 output = LookupOutput (client, stuff->output, DixReadAccess);
428 if (!output)
429 return RRErrorBase + BadRROutput;
431 prop = RRQueryOutputProperty (output, stuff->property);
432 if (!prop)
433 return BadName;
435 rep.type = X_Reply;
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;
441 if (client->swapped)
443 int n;
444 swaps (&rep.sequenceNumber, n);
445 swapl (&rep.length, n);
447 WriteReplyToClient (client, sizeof (xRRQueryOutputPropertyReply), &rep);
448 if (prop->num_valid)
450 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
451 WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
452 prop->valid_values);
454 return(client->noClientException);
458 ProcRRConfigureOutputProperty (ClientPtr client)
460 REQUEST(xRRConfigureOutputPropertyReq);
461 RROutputPtr output;
462 int num_valid;
464 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
466 output = LookupOutput (client, stuff->output, DixReadAccess);
468 if (!output)
469 return RRErrorBase + BadRROutput;
471 num_valid = stuff->length - (sizeof (xRRConfigureOutputPropertyReq) >> 2);
472 return RRConfigureOutputProperty (output, stuff->property,
473 stuff->pending, stuff->range,
474 FALSE, num_valid,
475 (INT32 *) (stuff + 1));
479 ProcRRChangeOutputProperty (ClientPtr client)
481 REQUEST(xRRChangeOutputPropertyReq);
482 RROutputPtr output;
483 char format, mode;
484 unsigned long len;
485 int sizeInBytes;
486 int totalSize;
487 int err;
489 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
490 UpdateCurrentTime();
491 format = stuff->format;
492 mode = stuff->mode;
493 if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
494 (mode != PropModePrepend))
496 client->errorValue = mode;
497 return BadValue;
499 if ((format != 8) && (format != 16) && (format != 32))
501 client->errorValue = format;
502 return BadValue;
504 len = stuff->nUnits;
505 if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2))
506 return BadLength;
507 sizeInBytes = format>>3;
508 totalSize = len * sizeInBytes;
509 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
511 output = LookupOutput (client, stuff->output, DixWriteAccess);
512 if (!output)
513 return RRErrorBase + BadRROutput;
515 if (!ValidAtom(stuff->property))
517 client->errorValue = stuff->property;
518 return(BadAtom);
520 if (!ValidAtom(stuff->type))
522 client->errorValue = stuff->type;
523 return(BadAtom);
526 err = RRChangeOutputProperty(output, stuff->property,
527 stuff->type, (int)format,
528 (int)mode, len, (pointer)&stuff[1], TRUE, TRUE);
529 if (err != Success)
530 return err;
531 else
532 return client->noClientException;
536 ProcRRDeleteOutputProperty (ClientPtr client)
538 REQUEST(xRRDeleteOutputPropertyReq);
539 RROutputPtr output;
541 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
542 UpdateCurrentTime();
543 output = LookupOutput (client, stuff->output, DixWriteAccess);
544 if (!output)
545 return RRErrorBase + BadRROutput;
547 if (!ValidAtom(stuff->property))
549 client->errorValue = stuff->property;
550 return (BadAtom);
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;
565 RROutputPtr output;
566 xRRGetOutputPropertyReply reply;
568 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
569 if (stuff->delete)
570 UpdateCurrentTime();
571 output = LookupOutput (client, stuff->output,
572 stuff->delete ? DixWriteAccess :
573 DixReadAccess);
574 if (!output)
575 return RRErrorBase + BadRROutput;
577 if (!ValidAtom(stuff->property))
579 client->errorValue = stuff->property;
580 return(BadAtom);
582 if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
584 client->errorValue = stuff->delete;
585 return(BadValue);
587 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
589 client->errorValue = stuff->type;
590 return(BadAtom);
593 for (prev = &output->properties; (prop = *prev); prev = &prop->next)
594 if (prop->propertyName == stuff->property)
595 break;
597 reply.type = X_Reply;
598 reply.sequenceNumber = client->sequence;
599 if (!prop)
601 reply.nItems = 0;
602 reply.length = 0;
603 reply.bytesAfter = 0;
604 reply.propertyType = None;
605 reply.format = 0;
606 WriteReplyToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
607 return(client->noClientException);
610 if (prop->immutable && stuff->delete)
611 return BadAccess;
613 if (stuff->pending && prop->is_pending)
614 prop_value = &prop->pending;
615 else
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;
627 reply.length = 0;
628 reply.nItems = 0;
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. */
643 if (n < ind)
645 client->errorValue = stuff->longOffset;
646 return BadValue;
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);
656 else
657 reply.nItems = 0;
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);
674 if (len)
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 */
687 *prev = prop->next;
688 RRDestroyOutputProperty (prop);
690 return(client->noClientException);