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