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 #include <X11/Xatom.h>
27
28 static int
DeliverPropertyEvent(WindowPtr pWin,void * value)29 DeliverPropertyEvent(WindowPtr pWin, void *value)
30 {
31 xRROutputPropertyNotifyEvent *event = value;
32 RREventPtr *pHead, pRREvent;
33
34 dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
35 RREventType, serverClient, DixReadAccess);
36 if (!pHead)
37 return WT_WALKCHILDREN;
38
39 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
40 if (!(pRREvent->mask & RROutputPropertyNotifyMask))
41 continue;
42
43 event->window = pRREvent->window->drawable.id;
44 WriteEventsToClient(pRREvent->client, 1, (xEvent *) event);
45 }
46
47 return WT_WALKCHILDREN;
48 }
49
50 static void
RRDeliverPropertyEvent(ScreenPtr pScreen,xEvent * event)51 RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
52 {
53 if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
54 WalkTree(pScreen, DeliverPropertyEvent, event);
55 }
56
57 static void
RRDestroyOutputProperty(RRPropertyPtr prop)58 RRDestroyOutputProperty(RRPropertyPtr prop)
59 {
60 free(prop->valid_values);
61 free(prop->current.data);
62 free(prop->pending.data);
63 free(prop);
64 }
65
66 static void
RRDeleteProperty(RROutputRec * output,RRPropertyRec * prop)67 RRDeleteProperty(RROutputRec * output, RRPropertyRec * prop)
68 {
69 xRROutputPropertyNotifyEvent event = {
70 .type = RREventBase + RRNotify,
71 .subCode = RRNotify_OutputProperty,
72 .output = output->id,
73 .state = PropertyDelete,
74 .atom = prop->propertyName,
75 .timestamp = currentTime.milliseconds
76 };
77
78 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
79
80 RRDestroyOutputProperty(prop);
81 }
82
83 void
RRDeleteAllOutputProperties(RROutputPtr output)84 RRDeleteAllOutputProperties(RROutputPtr output)
85 {
86 RRPropertyPtr prop, next;
87
88 for (prop = output->properties; prop; prop = next) {
89 next = prop->next;
90 RRDeleteProperty(output, prop);
91 }
92 }
93
94 static void
RRInitOutputPropertyValue(RRPropertyValuePtr property_value)95 RRInitOutputPropertyValue(RRPropertyValuePtr property_value)
96 {
97 property_value->type = None;
98 property_value->format = 0;
99 property_value->size = 0;
100 property_value->data = NULL;
101 }
102
103 static RRPropertyPtr
RRCreateOutputProperty(Atom property)104 RRCreateOutputProperty(Atom property)
105 {
106 RRPropertyPtr prop;
107
108 prop = (RRPropertyPtr) malloc(sizeof(RRPropertyRec));
109 if (!prop)
110 return NULL;
111 prop->next = NULL;
112 prop->propertyName = property;
113 prop->is_pending = FALSE;
114 prop->range = FALSE;
115 prop->immutable = FALSE;
116 prop->num_valid = 0;
117 prop->valid_values = NULL;
118 RRInitOutputPropertyValue(&prop->current);
119 RRInitOutputPropertyValue(&prop->pending);
120 return prop;
121 }
122
123 void
RRDeleteOutputProperty(RROutputPtr output,Atom property)124 RRDeleteOutputProperty(RROutputPtr output, Atom property)
125 {
126 RRPropertyRec *prop, **prev;
127
128 for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
129 if (prop->propertyName == property) {
130 *prev = prop->next;
131 RRDeleteProperty(output, prop);
132 return;
133 }
134 }
135
136 static void
RRNoticePropertyChange(RROutputPtr output,Atom property,RRPropertyValuePtr value)137 RRNoticePropertyChange(RROutputPtr output, Atom property, RRPropertyValuePtr value)
138 {
139 const char *non_desktop_str = RR_PROPERTY_NON_DESKTOP;
140 Atom non_desktop_prop = MakeAtom(non_desktop_str, strlen(non_desktop_str), FALSE);
141
142 if (property == non_desktop_prop) {
143 if (value->type == XA_INTEGER && value->format == 32 && value->size >= 1) {
144 uint32_t nonDesktopData;
145 Bool nonDesktop;
146
147 memcpy(&nonDesktopData, value->data, sizeof (nonDesktopData));
148 nonDesktop = nonDesktopData != 0;
149
150 if (nonDesktop != output->nonDesktop) {
151 output->nonDesktop = nonDesktop;
152 RROutputChanged(output, 0);
153 RRTellChanged(output->pScreen);
154 }
155 }
156 }
157 }
158
159 int
RRChangeOutputProperty(RROutputPtr output,Atom property,Atom type,int format,int mode,unsigned long len,const void * value,Bool sendevent,Bool pending)160 RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type,
161 int format, int mode, unsigned long len,
162 const void *value, Bool sendevent, Bool pending)
163 {
164 RRPropertyPtr prop;
165 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
166 int size_in_bytes;
167 unsigned long total_len;
168 RRPropertyValuePtr prop_value;
169 RRPropertyValueRec new_value;
170 Bool add = FALSE;
171
172 size_in_bytes = format >> 3;
173
174 /* first see if property already exists */
175 prop = RRQueryOutputProperty(output, property);
176 if (!prop) { /* just add to list */
177 prop = RRCreateOutputProperty(property);
178 if (!prop)
179 return BadAlloc;
180 add = TRUE;
181 mode = PropModeReplace;
182 }
183 if (pending && prop->is_pending)
184 prop_value = &prop->pending;
185 else
186 prop_value = &prop->current;
187
188 /* To append or prepend to a property the request format and type
189 must match those of the already defined property. The
190 existing format and type are irrelevant when using the mode
191 "PropModeReplace" since they will be written over. */
192
193 if ((format != prop_value->format) && (mode != PropModeReplace))
194 return BadMatch;
195 if ((prop_value->type != type) && (mode != PropModeReplace))
196 return BadMatch;
197 new_value = *prop_value;
198 if (mode == PropModeReplace)
199 total_len = len;
200 else
201 total_len = prop_value->size + len;
202
203 if (mode == PropModeReplace || len > 0) {
204 void *new_data = NULL, *old_data = NULL;
205
206 new_value.data = xallocarray(total_len, size_in_bytes);
207 if (!new_value.data && total_len && size_in_bytes) {
208 if (add)
209 RRDestroyOutputProperty(prop);
210 return BadAlloc;
211 }
212 new_value.size = len;
213 new_value.type = type;
214 new_value.format = format;
215
216 switch (mode) {
217 case PropModeReplace:
218 new_data = new_value.data;
219 old_data = NULL;
220 break;
221 case PropModeAppend:
222 new_data = (void *) (((char *) new_value.data) +
223 (prop_value->size * size_in_bytes));
224 old_data = new_value.data;
225 break;
226 case PropModePrepend:
227 new_data = new_value.data;
228 old_data = (void *) (((char *) new_value.data) +
229 (prop_value->size * size_in_bytes));
230 break;
231 }
232 if (new_data)
233 memcpy((char *) new_data, (char *) value, len * size_in_bytes);
234 if (old_data)
235 memcpy((char *) old_data, (char *) prop_value->data,
236 prop_value->size * size_in_bytes);
237
238 if (pending && pScrPriv->rrOutputSetProperty &&
239 !pScrPriv->rrOutputSetProperty(output->pScreen, output,
240 prop->propertyName, &new_value)) {
241 free(new_value.data);
242 if (add)
243 RRDestroyOutputProperty(prop);
244 return BadValue;
245 }
246 free(prop_value->data);
247 *prop_value = new_value;
248 }
249
250 else if (len == 0) {
251 /* do nothing */
252 }
253
254 if (add) {
255 prop->next = output->properties;
256 output->properties = prop;
257 }
258
259 if (pending && prop->is_pending)
260 output->pendingProperties = TRUE;
261
262 if (!(pending && prop->is_pending))
263 RRNoticePropertyChange(output, prop->propertyName, prop_value);
264
265 if (sendevent) {
266 xRROutputPropertyNotifyEvent event = {
267 .type = RREventBase + RRNotify,
268 .subCode = RRNotify_OutputProperty,
269 .output = output->id,
270 .state = PropertyNewValue,
271 .atom = prop->propertyName,
272 .timestamp = currentTime.milliseconds
273 };
274 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
275 }
276 return Success;
277 }
278
279 Bool
RRPostPendingProperties(RROutputPtr output)280 RRPostPendingProperties(RROutputPtr output)
281 {
282 RRPropertyValuePtr pending_value;
283 RRPropertyValuePtr current_value;
284 RRPropertyPtr property;
285 Bool ret = TRUE;
286
287 if (!output->pendingProperties)
288 return TRUE;
289
290 output->pendingProperties = FALSE;
291 for (property = output->properties; property; property = property->next) {
292 /* Skip non-pending properties */
293 if (!property->is_pending)
294 continue;
295
296 pending_value = &property->pending;
297 current_value = &property->current;
298
299 /*
300 * If the pending and current values are equal, don't mark it
301 * as changed (which would deliver an event)
302 */
303 if (pending_value->type == current_value->type &&
304 pending_value->format == current_value->format &&
305 pending_value->size == current_value->size &&
306 !memcmp(pending_value->data, current_value->data,
307 pending_value->size * (pending_value->format / 8)))
308 continue;
309
310 if (RRChangeOutputProperty(output, property->propertyName,
311 pending_value->type, pending_value->format,
312 PropModeReplace, pending_value->size,
313 pending_value->data, TRUE, FALSE) != Success)
314 ret = FALSE;
315 }
316 return ret;
317 }
318
319 RRPropertyPtr
RRQueryOutputProperty(RROutputPtr output,Atom property)320 RRQueryOutputProperty(RROutputPtr output, Atom property)
321 {
322 RRPropertyPtr prop;
323
324 for (prop = output->properties; prop; prop = prop->next)
325 if (prop->propertyName == property)
326 return prop;
327 return NULL;
328 }
329
330 RRPropertyValuePtr
RRGetOutputProperty(RROutputPtr output,Atom property,Bool pending)331 RRGetOutputProperty(RROutputPtr output, Atom property, Bool pending)
332 {
333 RRPropertyPtr prop = RRQueryOutputProperty(output, property);
334 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
335
336 if (!prop)
337 return NULL;
338 if (pending && prop->is_pending)
339 return &prop->pending;
340 else {
341 #if RANDR_13_INTERFACE
342 /* If we can, try to update the property value first */
343 if (pScrPriv->rrOutputGetProperty)
344 pScrPriv->rrOutputGetProperty(output->pScreen, output,
345 prop->propertyName);
346 #endif
347 return &prop->current;
348 }
349 }
350
351 int
RRConfigureOutputProperty(RROutputPtr output,Atom property,Bool pending,Bool range,Bool immutable,int num_values,const INT32 * values)352 RRConfigureOutputProperty(RROutputPtr output, Atom property,
353 Bool pending, Bool range, Bool immutable,
354 int num_values, const INT32 *values)
355 {
356 RRPropertyPtr prop = RRQueryOutputProperty(output, property);
357 Bool add = FALSE;
358 INT32 *new_values;
359
360 if (!prop) {
361 prop = RRCreateOutputProperty(property);
362 if (!prop)
363 return BadAlloc;
364 add = TRUE;
365 }
366 else if (prop->immutable && !immutable)
367 return BadAccess;
368
369 /*
370 * ranges must have even number of values
371 */
372 if (range && (num_values & 1)) {
373 if (add)
374 RRDestroyOutputProperty(prop);
375 return BadMatch;
376 }
377
378 new_values = xallocarray(num_values, sizeof(INT32));
379 if (!new_values && num_values) {
380 if (add)
381 RRDestroyOutputProperty(prop);
382 return BadAlloc;
383 }
384 if (num_values)
385 memcpy(new_values, values, num_values * sizeof(INT32));
386
387 /*
388 * Property moving from pending to non-pending
389 * loses any pending values
390 */
391 if (prop->is_pending && !pending) {
392 free(prop->pending.data);
393 RRInitOutputPropertyValue(&prop->pending);
394 }
395
396 prop->is_pending = pending;
397 prop->range = range;
398 prop->immutable = immutable;
399 prop->num_valid = num_values;
400 free(prop->valid_values);
401 prop->valid_values = new_values;
402
403 if (add) {
404 prop->next = output->properties;
405 output->properties = prop;
406 }
407
408 return Success;
409 }
410
411 int
ProcRRListOutputProperties(ClientPtr client)412 ProcRRListOutputProperties(ClientPtr client)
413 {
414 REQUEST(xRRListOutputPropertiesReq);
415 Atom *pAtoms = NULL;
416 xRRListOutputPropertiesReply rep;
417 int numProps = 0;
418 RROutputPtr output;
419 RRPropertyPtr prop;
420
421 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
422
423 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
424
425 for (prop = output->properties; prop; prop = prop->next)
426 numProps++;
427 if (numProps)
428 if (!(pAtoms = xallocarray(numProps, sizeof(Atom))))
429 return BadAlloc;
430
431 rep = (xRRListOutputPropertiesReply) {
432 .type = X_Reply,
433 .sequenceNumber = client->sequence,
434 .length = bytes_to_int32(numProps * sizeof(Atom)),
435 .nAtoms = numProps
436 };
437 if (client->swapped) {
438 swaps(&rep.sequenceNumber);
439 swapl(&rep.length);
440 swaps(&rep.nAtoms);
441 }
442 WriteToClient(client, sizeof(xRRListOutputPropertiesReply), &rep);
443
444 if (numProps) {
445 /* Copy property name atoms to reply buffer */
446 Atom *temppAtoms = pAtoms;
447 for (prop = output->properties; prop; prop = prop->next)
448 *temppAtoms++ = prop->propertyName;
449
450 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
451 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
452 free(pAtoms);
453 }
454 return Success;
455 }
456
457 int
ProcRRQueryOutputProperty(ClientPtr client)458 ProcRRQueryOutputProperty(ClientPtr client)
459 {
460 REQUEST(xRRQueryOutputPropertyReq);
461 xRRQueryOutputPropertyReply rep;
462 RROutputPtr output;
463 RRPropertyPtr prop;
464 char *extra = NULL;
465
466 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
467
468 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
469
470 prop = RRQueryOutputProperty(output, stuff->property);
471 if (!prop)
472 return BadName;
473
474 if (prop->num_valid) {
475 extra = xallocarray(prop->num_valid, sizeof(INT32));
476 if (!extra)
477 return BadAlloc;
478 }
479
480 rep = (xRRQueryOutputPropertyReply) {
481 .type = X_Reply,
482 .sequenceNumber = client->sequence,
483 .length = prop->num_valid,
484 .pending = prop->is_pending,
485 .range = prop->range,
486 .immutable = prop->immutable
487 };
488
489 if (client->swapped) {
490 swaps(&rep.sequenceNumber);
491 swapl(&rep.length);
492 }
493 WriteToClient(client, sizeof(xRRQueryOutputPropertyReply), &rep);
494 if (prop->num_valid) {
495 memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
496 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
497 WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
498 extra);
499 free(extra);
500 }
501 return Success;
502 }
503
504 int
ProcRRConfigureOutputProperty(ClientPtr client)505 ProcRRConfigureOutputProperty(ClientPtr client)
506 {
507 REQUEST(xRRConfigureOutputPropertyReq);
508 RROutputPtr output;
509 int num_valid;
510
511 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
512
513 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
514
515 if (RROutputIsLeased(output))
516 return BadAccess;
517
518 num_valid =
519 stuff->length - bytes_to_int32(sizeof(xRRConfigureOutputPropertyReq));
520 return RRConfigureOutputProperty(output, stuff->property, stuff->pending,
521 stuff->range, FALSE, num_valid,
522 (INT32 *) (stuff + 1));
523 }
524
525 int
ProcRRChangeOutputProperty(ClientPtr client)526 ProcRRChangeOutputProperty(ClientPtr client)
527 {
528 REQUEST(xRRChangeOutputPropertyReq);
529 RROutputPtr output;
530 char format, mode;
531 unsigned long len;
532 int sizeInBytes;
533 int totalSize;
534 int err;
535
536 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
537 UpdateCurrentTime();
538 format = stuff->format;
539 mode = stuff->mode;
540 if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
541 (mode != PropModePrepend)) {
542 client->errorValue = mode;
543 return BadValue;
544 }
545 if ((format != 8) && (format != 16) && (format != 32)) {
546 client->errorValue = format;
547 return BadValue;
548 }
549 len = stuff->nUnits;
550 if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
551 return BadLength;
552 sizeInBytes = format >> 3;
553 totalSize = len * sizeInBytes;
554 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
555
556 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
557
558 if (!ValidAtom(stuff->property)) {
559 client->errorValue = stuff->property;
560 return BadAtom;
561 }
562 if (!ValidAtom(stuff->type)) {
563 client->errorValue = stuff->type;
564 return BadAtom;
565 }
566
567 err = RRChangeOutputProperty(output, stuff->property,
568 stuff->type, (int) format,
569 (int) mode, len, (void *) &stuff[1], TRUE,
570 TRUE);
571 if (err != Success)
572 return err;
573 else
574 return Success;
575 }
576
577 int
ProcRRDeleteOutputProperty(ClientPtr client)578 ProcRRDeleteOutputProperty(ClientPtr client)
579 {
580 REQUEST(xRRDeleteOutputPropertyReq);
581 RROutputPtr output;
582 RRPropertyPtr prop;
583
584 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
585 UpdateCurrentTime();
586 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
587
588 if (RROutputIsLeased(output))
589 return BadAccess;
590
591 if (!ValidAtom(stuff->property)) {
592 client->errorValue = stuff->property;
593 return BadAtom;
594 }
595
596 prop = RRQueryOutputProperty(output, stuff->property);
597 if (!prop) {
598 client->errorValue = stuff->property;
599 return BadName;
600 }
601
602 if (prop->immutable) {
603 client->errorValue = stuff->property;
604 return BadAccess;
605 }
606
607 RRDeleteOutputProperty(output, stuff->property);
608 return Success;
609 }
610
611 int
ProcRRGetOutputProperty(ClientPtr client)612 ProcRRGetOutputProperty(ClientPtr client)
613 {
614 REQUEST(xRRGetOutputPropertyReq);
615 RRPropertyPtr prop, *prev;
616 RRPropertyValuePtr prop_value;
617 unsigned long n, len, ind;
618 RROutputPtr output;
619 xRRGetOutputPropertyReply reply;
620 char *extra = NULL;
621
622 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
623 if (stuff->delete)
624 UpdateCurrentTime();
625 VERIFY_RR_OUTPUT(stuff->output, output,
626 stuff->delete ? DixWriteAccess : DixReadAccess);
627
628 if (!ValidAtom(stuff->property)) {
629 client->errorValue = stuff->property;
630 return BadAtom;
631 }
632 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
633 client->errorValue = stuff->delete;
634 return BadValue;
635 }
636 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
637 client->errorValue = stuff->type;
638 return BadAtom;
639 }
640
641 for (prev = &output->properties; (prop = *prev); prev = &prop->next)
642 if (prop->propertyName == stuff->property)
643 break;
644
645 reply = (xRRGetOutputPropertyReply) {
646 .type = X_Reply,
647 .sequenceNumber = client->sequence
648 };
649 if (!prop) {
650 reply.nItems = 0;
651 reply.length = 0;
652 reply.bytesAfter = 0;
653 reply.propertyType = None;
654 reply.format = 0;
655 if (client->swapped) {
656 swaps(&reply.sequenceNumber);
657 swapl(&reply.length);
658 swapl(&reply.propertyType);
659 swapl(&reply.bytesAfter);
660 swapl(&reply.nItems);
661 }
662 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
663 return Success;
664 }
665
666 if (prop->immutable && stuff->delete)
667 return BadAccess;
668
669 prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
670 if (!prop_value)
671 return BadAtom;
672
673 /* If the request type and actual type don't match. Return the
674 property information, but not the data. */
675
676 if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType))
677 ) {
678 reply.bytesAfter = prop_value->size;
679 reply.format = prop_value->format;
680 reply.length = 0;
681 reply.nItems = 0;
682 reply.propertyType = prop_value->type;
683 if (client->swapped) {
684 swaps(&reply.sequenceNumber);
685 swapl(&reply.length);
686 swapl(&reply.propertyType);
687 swapl(&reply.bytesAfter);
688 swapl(&reply.nItems);
689 }
690 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
691 return Success;
692 }
693
694 /*
695 * Return type, format, value to client
696 */
697 n = (prop_value->format / 8) * prop_value->size; /* size (bytes) of prop */
698 ind = stuff->longOffset << 2;
699
700 /* If longOffset is invalid such that it causes "len" to
701 be negative, it's a value error. */
702
703 if (n < ind) {
704 client->errorValue = stuff->longOffset;
705 return BadValue;
706 }
707
708 len = min(n - ind, 4 * stuff->longLength);
709
710 if (len) {
711 extra = malloc(len);
712 if (!extra)
713 return BadAlloc;
714 }
715 reply.bytesAfter = n - (ind + len);
716 reply.format = prop_value->format;
717 reply.length = bytes_to_int32(len);
718 if (prop_value->format)
719 reply.nItems = len / (prop_value->format / 8);
720 else
721 reply.nItems = 0;
722 reply.propertyType = prop_value->type;
723
724 if (stuff->delete && (reply.bytesAfter == 0)) {
725 xRROutputPropertyNotifyEvent event = {
726 .type = RREventBase + RRNotify,
727 .subCode = RRNotify_OutputProperty,
728 .output = output->id,
729 .state = PropertyDelete,
730 .atom = prop->propertyName,
731 .timestamp = currentTime.milliseconds
732 };
733 RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
734 }
735
736 if (client->swapped) {
737 swaps(&reply.sequenceNumber);
738 swapl(&reply.length);
739 swapl(&reply.propertyType);
740 swapl(&reply.bytesAfter);
741 swapl(&reply.nItems);
742 }
743 WriteToClient(client, sizeof(xGenericReply), &reply);
744 if (len) {
745 memcpy(extra, (char *) prop_value->data + ind, len);
746 switch (reply.format) {
747 case 32:
748 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
749 break;
750 case 16:
751 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
752 break;
753 default:
754 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
755 break;
756 }
757 WriteSwappedDataToClient(client, len, extra);
758 free(extra);
759 }
760
761 if (stuff->delete && (reply.bytesAfter == 0)) { /* delete the Property */
762 *prev = prop->next;
763 RRDestroyOutputProperty(prop);
764 }
765 return Success;
766 }
767