1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include "randrstr.h"
24706f2543Smrg#include "propertyst.h"
25706f2543Smrg#include "swaprep.h"
26706f2543Smrg
27706f2543Smrgstatic int
28706f2543SmrgDeliverPropertyEvent(WindowPtr pWin, void *value)
29706f2543Smrg{
30706f2543Smrg    xRROutputPropertyNotifyEvent *event = value;
31706f2543Smrg    RREventPtr *pHead, pRREvent;
32706f2543Smrg
33706f2543Smrg    dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
34706f2543Smrg			    RREventType, serverClient, DixReadAccess);
35706f2543Smrg    if (!pHead)
36706f2543Smrg	return WT_WALKCHILDREN;
37706f2543Smrg
38706f2543Smrg    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
39706f2543Smrg    {
40706f2543Smrg	if (!(pRREvent->mask & RROutputPropertyNotifyMask))
41706f2543Smrg	    continue;
42706f2543Smrg
43706f2543Smrg	event->window = pRREvent->window->drawable.id;
44706f2543Smrg	WriteEventsToClient(pRREvent->client, 1, (xEvent *)event);
45706f2543Smrg    }
46706f2543Smrg
47706f2543Smrg    return WT_WALKCHILDREN;
48706f2543Smrg}
49706f2543Smrg
50706f2543Smrgstatic void RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
51706f2543Smrg{
52706f2543Smrg    if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
53706f2543Smrg	WalkTree(pScreen, DeliverPropertyEvent, event);
54706f2543Smrg}
55706f2543Smrg
56706f2543Smrgstatic void
57706f2543SmrgRRDestroyOutputProperty (RRPropertyPtr prop)
58706f2543Smrg{
59706f2543Smrg    free(prop->valid_values);
60706f2543Smrg    free(prop->current.data);
61706f2543Smrg    free(prop->pending.data);
62706f2543Smrg    free(prop);
63706f2543Smrg}
64706f2543Smrg
65706f2543Smrgstatic void
66706f2543SmrgRRDeleteProperty(RROutputRec *output, RRPropertyRec *prop)
67706f2543Smrg{
68706f2543Smrg    xRROutputPropertyNotifyEvent event;
69706f2543Smrg    event.type = RREventBase + RRNotify;
70706f2543Smrg    event.subCode = RRNotify_OutputProperty;
71706f2543Smrg    event.output = output->id;
72706f2543Smrg    event.state = PropertyDelete;
73706f2543Smrg    event.atom = prop->propertyName;
74706f2543Smrg    event.timestamp = currentTime.milliseconds;
75706f2543Smrg
76706f2543Smrg    RRDeliverPropertyEvent(output->pScreen, (xEvent *)&event);
77706f2543Smrg
78706f2543Smrg    RRDestroyOutputProperty(prop);
79706f2543Smrg}
80706f2543Smrg
81706f2543Smrgvoid
82706f2543SmrgRRDeleteAllOutputProperties(RROutputPtr output)
83706f2543Smrg{
84706f2543Smrg    RRPropertyPtr prop, next;
85706f2543Smrg
86706f2543Smrg    for (prop = output->properties; prop; prop = next) {
87706f2543Smrg	next = prop->next;
88706f2543Smrg        RRDeleteProperty(output, prop);
89706f2543Smrg    }
90706f2543Smrg}
91706f2543Smrg
92706f2543Smrgstatic void
93706f2543SmrgRRInitOutputPropertyValue (RRPropertyValuePtr property_value)
94706f2543Smrg{
95706f2543Smrg    property_value->type = None;
96706f2543Smrg    property_value->format = 0;
97706f2543Smrg    property_value->size = 0;
98706f2543Smrg    property_value->data = NULL;
99706f2543Smrg}
100706f2543Smrg
101706f2543Smrgstatic RRPropertyPtr
102706f2543SmrgRRCreateOutputProperty (Atom property)
103706f2543Smrg{
104706f2543Smrg    RRPropertyPtr   prop;
105706f2543Smrg
106706f2543Smrg    prop = (RRPropertyPtr)malloc(sizeof(RRPropertyRec));
107706f2543Smrg    if (!prop)
108706f2543Smrg	return NULL;
109706f2543Smrg    prop->next = NULL;
110706f2543Smrg    prop->propertyName = property;
111706f2543Smrg    prop->is_pending = FALSE;
112706f2543Smrg    prop->range = FALSE;
113706f2543Smrg    prop->immutable = FALSE;
114706f2543Smrg    prop->num_valid = 0;
115706f2543Smrg    prop->valid_values = NULL;
116706f2543Smrg    RRInitOutputPropertyValue (&prop->current);
117706f2543Smrg    RRInitOutputPropertyValue (&prop->pending);
118706f2543Smrg    return prop;
119706f2543Smrg}
120706f2543Smrg
121706f2543Smrgvoid
122706f2543SmrgRRDeleteOutputProperty(RROutputPtr output, Atom property)
123706f2543Smrg{
124706f2543Smrg    RRPropertyRec *prop, **prev;
125706f2543Smrg
126706f2543Smrg    for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
127706f2543Smrg	if (prop->propertyName == property) {
128706f2543Smrg            *prev = prop->next;
129706f2543Smrg            RRDeleteProperty(output, prop);
130706f2543Smrg            return;
131706f2543Smrg        }
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrgint
135706f2543SmrgRRChangeOutputProperty (RROutputPtr output, Atom property, Atom type,
136706f2543Smrg			int format, int mode, unsigned long len,
137706f2543Smrg			pointer value, Bool sendevent, Bool pending)
138706f2543Smrg{
139706f2543Smrg    RRPropertyPtr		    prop;
140706f2543Smrg    xRROutputPropertyNotifyEvent    event;
141706f2543Smrg    rrScrPrivPtr		    pScrPriv = rrGetScrPriv(output->pScreen);
142706f2543Smrg    int				    size_in_bytes;
143706f2543Smrg    int				    total_size;
144706f2543Smrg    unsigned long		    total_len;
145706f2543Smrg    RRPropertyValuePtr		    prop_value;
146706f2543Smrg    RRPropertyValueRec		    new_value;
147706f2543Smrg    Bool			    add = FALSE;
148706f2543Smrg
149706f2543Smrg    size_in_bytes = format >> 3;
150706f2543Smrg
151706f2543Smrg    /* first see if property already exists */
152706f2543Smrg    prop = RRQueryOutputProperty (output, property);
153706f2543Smrg    if (!prop)   /* just add to list */
154706f2543Smrg    {
155706f2543Smrg	prop = RRCreateOutputProperty (property);
156706f2543Smrg	if (!prop)
157706f2543Smrg	    return BadAlloc;
158706f2543Smrg	add = TRUE;
159706f2543Smrg	mode = PropModeReplace;
160706f2543Smrg    }
161706f2543Smrg    if (pending && prop->is_pending)
162706f2543Smrg	prop_value = &prop->pending;
163706f2543Smrg    else
164706f2543Smrg	prop_value = &prop->current;
165706f2543Smrg
166706f2543Smrg    /* To append or prepend to a property the request format and type
167706f2543Smrg     must match those of the already defined property.  The
168706f2543Smrg     existing format and type are irrelevant when using the mode
169706f2543Smrg     "PropModeReplace" since they will be written over. */
170706f2543Smrg
171706f2543Smrg    if ((format != prop_value->format) && (mode != PropModeReplace))
172706f2543Smrg	return BadMatch;
173706f2543Smrg    if ((prop_value->type != type) && (mode != PropModeReplace))
174706f2543Smrg	return BadMatch;
175706f2543Smrg    new_value = *prop_value;
176706f2543Smrg    if (mode == PropModeReplace)
177706f2543Smrg	total_len = len;
178706f2543Smrg    else
179706f2543Smrg	total_len = prop_value->size + len;
180706f2543Smrg
181706f2543Smrg    if (mode == PropModeReplace || len > 0)
182706f2543Smrg    {
183706f2543Smrg	pointer	    new_data = NULL, old_data = NULL;
184706f2543Smrg
185706f2543Smrg	total_size = total_len * size_in_bytes;
186706f2543Smrg	new_value.data = (pointer)malloc(total_size);
187706f2543Smrg	if (!new_value.data && total_size)
188706f2543Smrg	{
189706f2543Smrg	    if (add)
190706f2543Smrg		RRDestroyOutputProperty (prop);
191706f2543Smrg	    return BadAlloc;
192706f2543Smrg	}
193bc1411c9Smrg	new_value.size = total_len;
194706f2543Smrg	new_value.type = type;
195706f2543Smrg	new_value.format = format;
196706f2543Smrg
197706f2543Smrg	switch (mode) {
198706f2543Smrg	case PropModeReplace:
199706f2543Smrg	    new_data = new_value.data;
200706f2543Smrg	    old_data = NULL;
201706f2543Smrg	    break;
202706f2543Smrg	case PropModeAppend:
203706f2543Smrg	    new_data = (pointer) (((char *) new_value.data) +
204706f2543Smrg				  (prop_value->size * size_in_bytes));
205706f2543Smrg	    old_data = new_value.data;
206706f2543Smrg	    break;
207706f2543Smrg	case PropModePrepend:
208706f2543Smrg	    new_data = new_value.data;
209706f2543Smrg	    old_data = (pointer) (((char *) new_value.data) +
210bc1411c9Smrg				  (len * size_in_bytes));
211706f2543Smrg	    break;
212706f2543Smrg	}
213706f2543Smrg	if (new_data)
214706f2543Smrg	    memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
215706f2543Smrg	if (old_data)
216706f2543Smrg	    memcpy ((char *) old_data, (char *) prop_value->data,
217706f2543Smrg		    prop_value->size * size_in_bytes);
218706f2543Smrg
219706f2543Smrg	if (pending && pScrPriv->rrOutputSetProperty &&
220706f2543Smrg	    !pScrPriv->rrOutputSetProperty(output->pScreen, output,
221706f2543Smrg					   prop->propertyName, &new_value))
222706f2543Smrg	{
223706f2543Smrg	    free(new_value.data);
224706f2543Smrg	    return BadValue;
225706f2543Smrg	}
226706f2543Smrg	free(prop_value->data);
227706f2543Smrg	*prop_value = new_value;
228706f2543Smrg    }
229706f2543Smrg
230706f2543Smrg    else if (len == 0)
231706f2543Smrg    {
232706f2543Smrg	/* do nothing */
233706f2543Smrg    }
234706f2543Smrg
235706f2543Smrg    if (add)
236706f2543Smrg    {
237706f2543Smrg	prop->next = output->properties;
238706f2543Smrg	output->properties = prop;
239706f2543Smrg    }
240706f2543Smrg
241706f2543Smrg    if (pending && prop->is_pending)
242706f2543Smrg	output->pendingProperties = TRUE;
243706f2543Smrg
244706f2543Smrg    if (sendevent)
245706f2543Smrg    {
246706f2543Smrg	event.type = RREventBase + RRNotify;
247706f2543Smrg	event.subCode = RRNotify_OutputProperty;
248706f2543Smrg	event.output = output->id;
249706f2543Smrg	event.state = PropertyNewValue;
250706f2543Smrg	event.atom = prop->propertyName;
251706f2543Smrg	event.timestamp = currentTime.milliseconds;
252706f2543Smrg	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
253706f2543Smrg    }
254706f2543Smrg    return Success;
255706f2543Smrg}
256706f2543Smrg
257706f2543SmrgBool
258706f2543SmrgRRPostPendingProperties (RROutputPtr output)
259706f2543Smrg{
260706f2543Smrg    RRPropertyValuePtr	pending_value;
261706f2543Smrg    RRPropertyValuePtr	current_value;
262706f2543Smrg    RRPropertyPtr	property;
263706f2543Smrg    Bool		ret = TRUE;
264706f2543Smrg
265706f2543Smrg    if (!output->pendingProperties)
266706f2543Smrg	return TRUE;
267706f2543Smrg
268706f2543Smrg    output->pendingProperties = FALSE;
269706f2543Smrg    for (property = output->properties; property; property = property->next)
270706f2543Smrg    {
271706f2543Smrg	/* Skip non-pending properties */
272706f2543Smrg	if (!property->is_pending)
273706f2543Smrg	    continue;
274706f2543Smrg
275706f2543Smrg	pending_value = &property->pending;
276706f2543Smrg	current_value = &property->current;
277706f2543Smrg
278706f2543Smrg	/*
279706f2543Smrg	 * If the pending and current values are equal, don't mark it
280706f2543Smrg	 * as changed (which would deliver an event)
281706f2543Smrg	 */
282706f2543Smrg	if (pending_value->type == current_value->type &&
283706f2543Smrg	    pending_value->format == current_value->format &&
284706f2543Smrg	    pending_value->size == current_value->size &&
285706f2543Smrg	    !memcmp (pending_value->data, current_value->data,
286706f2543Smrg		     pending_value->size * (pending_value->format / 8)))
287706f2543Smrg	    continue;
288706f2543Smrg
289706f2543Smrg	if (RRChangeOutputProperty (output, property->propertyName,
290706f2543Smrg				    pending_value->type, pending_value->format,
291706f2543Smrg				    PropModeReplace, pending_value->size,
292706f2543Smrg				    pending_value->data, TRUE,
293706f2543Smrg				    FALSE) != Success)
294706f2543Smrg	    ret = FALSE;
295706f2543Smrg    }
296706f2543Smrg    return ret;
297706f2543Smrg}
298706f2543Smrg
299706f2543SmrgRRPropertyPtr
300706f2543SmrgRRQueryOutputProperty (RROutputPtr output, Atom property)
301706f2543Smrg{
302706f2543Smrg    RRPropertyPtr   prop;
303706f2543Smrg
304706f2543Smrg    for (prop = output->properties; prop; prop = prop->next)
305706f2543Smrg	if (prop->propertyName == property)
306706f2543Smrg	    return prop;
307706f2543Smrg    return NULL;
308706f2543Smrg}
309706f2543Smrg
310706f2543SmrgRRPropertyValuePtr
311706f2543SmrgRRGetOutputProperty (RROutputPtr output, Atom property, Bool pending)
312706f2543Smrg{
313706f2543Smrg    RRPropertyPtr   prop = RRQueryOutputProperty (output, property);
314706f2543Smrg    rrScrPrivPtr    pScrPriv = rrGetScrPriv(output->pScreen);
315706f2543Smrg
316706f2543Smrg    if (!prop)
317706f2543Smrg	return NULL;
318706f2543Smrg    if (pending && prop->is_pending)
319706f2543Smrg	return &prop->pending;
320706f2543Smrg    else {
321706f2543Smrg#if RANDR_13_INTERFACE
322706f2543Smrg	/* If we can, try to update the property value first */
323706f2543Smrg	if (pScrPriv->rrOutputGetProperty)
324706f2543Smrg	    pScrPriv->rrOutputGetProperty(output->pScreen, output,
325706f2543Smrg					  prop->propertyName);
326706f2543Smrg#endif
327706f2543Smrg	return &prop->current;
328706f2543Smrg    }
329706f2543Smrg}
330706f2543Smrg
331706f2543Smrgint
332706f2543SmrgRRConfigureOutputProperty (RROutputPtr output, Atom property,
333706f2543Smrg			   Bool pending, Bool range, Bool immutable,
334706f2543Smrg			   int num_values, INT32 *values)
335706f2543Smrg{
336706f2543Smrg    RRPropertyPtr   prop = RRQueryOutputProperty (output, property);
337706f2543Smrg    Bool	    add = FALSE;
338706f2543Smrg    INT32	    *new_values;
339706f2543Smrg
340706f2543Smrg    if (!prop)
341706f2543Smrg    {
342706f2543Smrg        prop = RRCreateOutputProperty (property);
343706f2543Smrg	if (!prop)
344706f2543Smrg	    return BadAlloc;
345706f2543Smrg	add = TRUE;
346706f2543Smrg    } else if (prop->immutable && !immutable)
347706f2543Smrg	return BadAccess;
348706f2543Smrg
349706f2543Smrg    /*
350706f2543Smrg     * ranges must have even number of values
351706f2543Smrg     */
352706f2543Smrg    if (range && (num_values & 1))
353706f2543Smrg	return BadMatch;
354706f2543Smrg
355706f2543Smrg    new_values = malloc(num_values * sizeof (INT32));
356706f2543Smrg    if (!new_values && num_values)
357706f2543Smrg	return BadAlloc;
358706f2543Smrg    if (num_values)
359706f2543Smrg	memcpy (new_values, values, num_values * sizeof (INT32));
360706f2543Smrg
361706f2543Smrg    /*
362706f2543Smrg     * Property moving from pending to non-pending
363706f2543Smrg     * loses any pending values
364706f2543Smrg     */
365706f2543Smrg    if (prop->is_pending && !pending)
366706f2543Smrg    {
367706f2543Smrg	free(prop->pending.data);
368706f2543Smrg	RRInitOutputPropertyValue (&prop->pending);
369706f2543Smrg    }
370706f2543Smrg
371706f2543Smrg    prop->is_pending = pending;
372706f2543Smrg    prop->range = range;
373706f2543Smrg    prop->immutable = immutable;
374706f2543Smrg    prop->num_valid = num_values;
375706f2543Smrg    free(prop->valid_values);
376706f2543Smrg    prop->valid_values = new_values;
377706f2543Smrg
378706f2543Smrg    if (add) {
379706f2543Smrg	prop->next = output->properties;
380706f2543Smrg	output->properties = prop;
381706f2543Smrg    }
382706f2543Smrg
383706f2543Smrg    return Success;
384706f2543Smrg}
385706f2543Smrg
386706f2543Smrgint
387706f2543SmrgProcRRListOutputProperties (ClientPtr client)
388706f2543Smrg{
389706f2543Smrg    REQUEST(xRRListOutputPropertiesReq);
390706f2543Smrg    Atom			    *pAtoms = NULL, *temppAtoms;
391706f2543Smrg    xRRListOutputPropertiesReply    rep;
392706f2543Smrg    int				    numProps = 0;
393706f2543Smrg    RROutputPtr			    output;
394706f2543Smrg    RRPropertyPtr			    prop;
395706f2543Smrg
396706f2543Smrg    REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
397706f2543Smrg
398706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
399706f2543Smrg
400706f2543Smrg    for (prop = output->properties; prop; prop = prop->next)
401706f2543Smrg	numProps++;
402706f2543Smrg    if (numProps)
403706f2543Smrg        if(!(pAtoms = (Atom *)malloc(numProps * sizeof(Atom))))
404706f2543Smrg            return BadAlloc;
405706f2543Smrg
406706f2543Smrg    rep.type = X_Reply;
407706f2543Smrg    rep.length = bytes_to_int32(numProps * sizeof(Atom));
408706f2543Smrg    rep.sequenceNumber = client->sequence;
409706f2543Smrg    rep.nAtoms = numProps;
410706f2543Smrg    if (client->swapped)
411706f2543Smrg    {
412706f2543Smrg	int n;
413706f2543Smrg	swaps (&rep.sequenceNumber, n);
414706f2543Smrg	swapl (&rep.length, n);
415706f2543Smrg	swaps (&rep.nAtoms, n);
416706f2543Smrg    }
417706f2543Smrg    temppAtoms = pAtoms;
418706f2543Smrg    for (prop = output->properties; prop; prop = prop->next)
419706f2543Smrg	*temppAtoms++ = prop->propertyName;
420706f2543Smrg
421706f2543Smrg    WriteToClient(client, sizeof(xRRListOutputPropertiesReply), (char*)&rep);
422706f2543Smrg    if (numProps)
423706f2543Smrg    {
424706f2543Smrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
425706f2543Smrg        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
426706f2543Smrg        free(pAtoms);
427706f2543Smrg    }
428706f2543Smrg    return Success;
429706f2543Smrg}
430706f2543Smrg
431706f2543Smrgint
432706f2543SmrgProcRRQueryOutputProperty (ClientPtr client)
433706f2543Smrg{
434706f2543Smrg    REQUEST(xRRQueryOutputPropertyReq);
435706f2543Smrg    xRRQueryOutputPropertyReply	    rep;
436706f2543Smrg    RROutputPtr			    output;
437706f2543Smrg    RRPropertyPtr		    prop;
438706f2543Smrg    char *extra = NULL;
439706f2543Smrg
440706f2543Smrg    REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
441706f2543Smrg
442706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
443706f2543Smrg
444706f2543Smrg    prop = RRQueryOutputProperty (output, stuff->property);
445706f2543Smrg    if (!prop)
446706f2543Smrg	return BadName;
447706f2543Smrg
448706f2543Smrg    if (prop->num_valid) {
449706f2543Smrg	extra = malloc(prop->num_valid * sizeof(INT32));
450706f2543Smrg	if (!extra)
451706f2543Smrg	    return BadAlloc;
452706f2543Smrg    }
453706f2543Smrg    rep.type = X_Reply;
454706f2543Smrg    rep.length = prop->num_valid;
455706f2543Smrg    rep.sequenceNumber = client->sequence;
456706f2543Smrg    rep.pending = prop->is_pending;
457706f2543Smrg    rep.range = prop->range;
458706f2543Smrg    rep.immutable = prop->immutable;
459706f2543Smrg    if (client->swapped)
460706f2543Smrg    {
461706f2543Smrg	int n;
462706f2543Smrg	swaps (&rep.sequenceNumber, n);
463706f2543Smrg	swapl (&rep.length, n);
464706f2543Smrg    }
465706f2543Smrg    WriteToClient (client, sizeof (xRRQueryOutputPropertyReply), (char*)&rep);
466706f2543Smrg    if (prop->num_valid)
467706f2543Smrg    {
468706f2543Smrg        memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
469706f2543Smrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
470706f2543Smrg        WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
471706f2543Smrg				 extra);
472706f2543Smrg        free(extra);
473706f2543Smrg    }
474706f2543Smrg    return Success;
475706f2543Smrg}
476706f2543Smrg
477706f2543Smrgint
478706f2543SmrgProcRRConfigureOutputProperty (ClientPtr client)
479706f2543Smrg{
480706f2543Smrg    REQUEST(xRRConfigureOutputPropertyReq);
481706f2543Smrg    RROutputPtr				output;
482706f2543Smrg    int					num_valid;
483706f2543Smrg
484706f2543Smrg    REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
485706f2543Smrg
486706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
487706f2543Smrg
488706f2543Smrg    num_valid = stuff->length - bytes_to_int32(sizeof (xRRConfigureOutputPropertyReq));
489706f2543Smrg    return RRConfigureOutputProperty (output, stuff->property,
490706f2543Smrg				      stuff->pending, stuff->range,
491706f2543Smrg				      FALSE, num_valid,
492706f2543Smrg				      (INT32 *) (stuff + 1));
493706f2543Smrg}
494706f2543Smrg
495706f2543Smrgint
496706f2543SmrgProcRRChangeOutputProperty (ClientPtr client)
497706f2543Smrg{
498706f2543Smrg    REQUEST(xRRChangeOutputPropertyReq);
499706f2543Smrg    RROutputPtr	    output;
500706f2543Smrg    char	    format, mode;
501706f2543Smrg    unsigned long   len;
502706f2543Smrg    int		    sizeInBytes;
50364af8facSmrg    uint64_t	    totalSize;
504706f2543Smrg    int		    err;
505706f2543Smrg
506706f2543Smrg    REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
507706f2543Smrg    UpdateCurrentTime();
508706f2543Smrg    format = stuff->format;
509706f2543Smrg    mode = stuff->mode;
510706f2543Smrg    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
511706f2543Smrg	(mode != PropModePrepend))
512706f2543Smrg    {
513706f2543Smrg	client->errorValue = mode;
514706f2543Smrg	return BadValue;
515706f2543Smrg    }
516706f2543Smrg    if ((format != 8) && (format != 16) && (format != 32))
517706f2543Smrg    {
518706f2543Smrg	client->errorValue = format;
519706f2543Smrg        return BadValue;
520706f2543Smrg    }
521706f2543Smrg    len = stuff->nUnits;
522706f2543Smrg    if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
523706f2543Smrg	return BadLength;
524706f2543Smrg    sizeInBytes = format>>3;
525706f2543Smrg    totalSize = len * sizeInBytes;
526706f2543Smrg    REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
527706f2543Smrg
528706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
529706f2543Smrg
530706f2543Smrg    if (!ValidAtom(stuff->property))
531706f2543Smrg    {
532706f2543Smrg	client->errorValue = stuff->property;
533706f2543Smrg	return BadAtom;
534706f2543Smrg    }
535706f2543Smrg    if (!ValidAtom(stuff->type))
536706f2543Smrg    {
537706f2543Smrg	client->errorValue = stuff->type;
538706f2543Smrg	return BadAtom;
539706f2543Smrg    }
540706f2543Smrg
541706f2543Smrg    err = RRChangeOutputProperty(output, stuff->property,
542706f2543Smrg				 stuff->type, (int)format,
543706f2543Smrg				 (int)mode, len, (pointer)&stuff[1], TRUE, TRUE);
544706f2543Smrg    if (err != Success)
545706f2543Smrg	return err;
546706f2543Smrg    else
547706f2543Smrg	return Success;
548706f2543Smrg}
549706f2543Smrg
550706f2543Smrgint
551706f2543SmrgProcRRDeleteOutputProperty (ClientPtr client)
552706f2543Smrg{
553706f2543Smrg    REQUEST(xRRDeleteOutputPropertyReq);
554706f2543Smrg    RROutputPtr	output;
555706f2543Smrg
556706f2543Smrg    REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
557706f2543Smrg    UpdateCurrentTime();
558706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
559706f2543Smrg
560706f2543Smrg    if (!ValidAtom(stuff->property))
561706f2543Smrg    {
562706f2543Smrg	client->errorValue = stuff->property;
563706f2543Smrg	return BadAtom;
564706f2543Smrg    }
565706f2543Smrg
566706f2543Smrg
567706f2543Smrg    RRDeleteOutputProperty(output, stuff->property);
568706f2543Smrg    return Success;
569706f2543Smrg}
570706f2543Smrg
571706f2543Smrgint
572706f2543SmrgProcRRGetOutputProperty (ClientPtr client)
573706f2543Smrg{
574706f2543Smrg    REQUEST(xRRGetOutputPropertyReq);
575706f2543Smrg    RRPropertyPtr		prop, *prev;
576706f2543Smrg    RRPropertyValuePtr		prop_value;
577706f2543Smrg    unsigned long		n, len, ind;
578706f2543Smrg    RROutputPtr			output;
579706f2543Smrg    xRRGetOutputPropertyReply	reply;
580706f2543Smrg    char			*extra = NULL;
581706f2543Smrg
582706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
583706f2543Smrg    if (stuff->delete)
584706f2543Smrg	UpdateCurrentTime();
585706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output,
586706f2543Smrg		     stuff->delete ? DixWriteAccess : DixReadAccess);
587706f2543Smrg
588706f2543Smrg    if (!ValidAtom(stuff->property))
589706f2543Smrg    {
590706f2543Smrg	client->errorValue = stuff->property;
591706f2543Smrg	return BadAtom;
592706f2543Smrg    }
593706f2543Smrg    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
594706f2543Smrg    {
595706f2543Smrg	client->errorValue = stuff->delete;
596706f2543Smrg	return BadValue;
597706f2543Smrg    }
598706f2543Smrg    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
599706f2543Smrg    {
600706f2543Smrg	client->errorValue = stuff->type;
601706f2543Smrg	return BadAtom;
602706f2543Smrg    }
603706f2543Smrg
604706f2543Smrg    for (prev = &output->properties; (prop = *prev); prev = &prop->next)
605706f2543Smrg	if (prop->propertyName == stuff->property)
606706f2543Smrg	    break;
607706f2543Smrg
608706f2543Smrg    reply.type = X_Reply;
609706f2543Smrg    reply.sequenceNumber = client->sequence;
610706f2543Smrg    if (!prop)
611706f2543Smrg    {
612706f2543Smrg	reply.nItems = 0;
613706f2543Smrg	reply.length = 0;
614706f2543Smrg	reply.bytesAfter = 0;
615706f2543Smrg	reply.propertyType = None;
616706f2543Smrg	reply.format = 0;
617706f2543Smrg	if (client->swapped) {
618706f2543Smrg	    int n;
619706f2543Smrg
620706f2543Smrg	    swaps(&reply.sequenceNumber, n);
621706f2543Smrg	    swapl(&reply.length, n);
622706f2543Smrg	    swapl(&reply.propertyType, n);
623706f2543Smrg	    swapl(&reply.bytesAfter, n);
624706f2543Smrg	    swapl(&reply.nItems, n);
625706f2543Smrg	}
626706f2543Smrg	WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
627706f2543Smrg	return Success;
628706f2543Smrg    }
629706f2543Smrg
630706f2543Smrg    if (prop->immutable && stuff->delete)
631706f2543Smrg	return BadAccess;
632706f2543Smrg
633706f2543Smrg    prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
634706f2543Smrg    if (!prop_value)
635706f2543Smrg	return BadAtom;
636706f2543Smrg
637706f2543Smrg    /* If the request type and actual type don't match. Return the
638706f2543Smrg    property information, but not the data. */
639706f2543Smrg
640706f2543Smrg    if (((stuff->type != prop_value->type) &&
641706f2543Smrg	 (stuff->type != AnyPropertyType))
642706f2543Smrg       )
643706f2543Smrg    {
644706f2543Smrg	reply.bytesAfter = prop_value->size;
645706f2543Smrg	reply.format = prop_value->format;
646706f2543Smrg	reply.length = 0;
647706f2543Smrg	reply.nItems = 0;
648706f2543Smrg	reply.propertyType = prop_value->type;
649706f2543Smrg	if (client->swapped) {
650706f2543Smrg	    int n;
651706f2543Smrg
652706f2543Smrg	    swaps(&reply.sequenceNumber, n);
653706f2543Smrg	    swapl(&reply.length, n);
654706f2543Smrg	    swapl(&reply.propertyType, n);
655706f2543Smrg	    swapl(&reply.bytesAfter, n);
656706f2543Smrg	    swapl(&reply.nItems, n);
657706f2543Smrg	}
658706f2543Smrg	WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
659706f2543Smrg	return Success;
660706f2543Smrg    }
661706f2543Smrg
662706f2543Smrg/*
663706f2543Smrg *  Return type, format, value to client
664706f2543Smrg */
665706f2543Smrg    n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
666706f2543Smrg    ind = stuff->longOffset << 2;
667706f2543Smrg
668706f2543Smrg   /* If longOffset is invalid such that it causes "len" to
669706f2543Smrg	    be negative, it's a value error. */
670706f2543Smrg
671706f2543Smrg    if (n < ind)
672706f2543Smrg    {
673706f2543Smrg	client->errorValue = stuff->longOffset;
674706f2543Smrg	return BadValue;
675706f2543Smrg    }
676706f2543Smrg
677706f2543Smrg    len = min(n - ind, 4 * stuff->longLength);
678706f2543Smrg
679706f2543Smrg    if (len) {
680706f2543Smrg	extra = malloc(len);
681706f2543Smrg	if (!extra)
682706f2543Smrg	    return BadAlloc;
683706f2543Smrg    }
684706f2543Smrg    reply.bytesAfter = n - (ind + len);
685706f2543Smrg    reply.format = prop_value->format;
686706f2543Smrg    reply.length = bytes_to_int32(len);
687706f2543Smrg    if (prop_value->format)
688706f2543Smrg	reply.nItems = len / (prop_value->format / 8);
689706f2543Smrg    else
690706f2543Smrg	reply.nItems = 0;
691706f2543Smrg    reply.propertyType = prop_value->type;
692706f2543Smrg
693706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0))
694706f2543Smrg    {
695706f2543Smrg	xRROutputPropertyNotifyEvent    event;
696706f2543Smrg
697706f2543Smrg	event.type = RREventBase + RRNotify;
698706f2543Smrg	event.subCode = RRNotify_OutputProperty;
699706f2543Smrg	event.output = output->id;
700706f2543Smrg	event.state = PropertyDelete;
701706f2543Smrg	event.atom = prop->propertyName;
702706f2543Smrg	event.timestamp = currentTime.milliseconds;
703706f2543Smrg	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
704706f2543Smrg    }
705706f2543Smrg
706706f2543Smrg    if (client->swapped) {
707706f2543Smrg	int n;
708706f2543Smrg
709706f2543Smrg	swaps(&reply.sequenceNumber, n);
710706f2543Smrg	swapl(&reply.length, n);
711706f2543Smrg	swapl(&reply.propertyType, n);
712706f2543Smrg	swapl(&reply.bytesAfter, n);
713706f2543Smrg	swapl(&reply.nItems, n);
714706f2543Smrg    }
715706f2543Smrg    WriteToClient(client, sizeof(xGenericReply), &reply);
716706f2543Smrg    if (len)
717706f2543Smrg    {
718706f2543Smrg	memcpy(extra, (char *)prop_value->data + ind, len);
719706f2543Smrg	switch (reply.format) {
720706f2543Smrg	case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
721706f2543Smrg	case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
722706f2543Smrg	default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
723706f2543Smrg	}
724706f2543Smrg	WriteSwappedDataToClient(client, len,
725706f2543Smrg				 extra);
726706f2543Smrg	free(extra);
727706f2543Smrg    }
728706f2543Smrg
729706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0))
730706f2543Smrg    { /* delete the Property */
731706f2543Smrg	*prev = prop->next;
732706f2543Smrg	RRDestroyOutputProperty (prop);
733706f2543Smrg    }
734706f2543Smrg    return Success;
735706f2543Smrg}
736706f2543Smrg
737