1/************************************************************
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1989 by Hewlett-Packard Company, Palo Alto, California.
26
27			All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Hewlett-Packard not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46
47/********************************************************************
48 *
49 *  Change feedback control attributes for an extension device.
50 *
51 */
52
53#ifdef HAVE_DIX_CONFIG_H
54#include <dix-config.h>
55#endif
56
57#include "inputstr.h"	/* DeviceIntPtr      */
58#include <X11/extensions/XI.h>
59#include <X11/extensions/XIproto.h>	/* control constants */
60
61#include "exglobals.h"
62
63#include "chgfctl.h"
64
65#define DO_ALL    (-1)
66
67/***********************************************************************
68 *
69 * This procedure changes the control attributes for an extension device,
70 * for clients on machines with a different byte ordering than the server.
71 *
72 */
73
74int
75SProcXChangeFeedbackControl(ClientPtr client)
76{
77    char n;
78
79    REQUEST(xChangeFeedbackControlReq);
80    swaps(&stuff->length, n);
81    REQUEST_AT_LEAST_SIZE(xChangeFeedbackControlReq);
82    swapl(&stuff->mask, n);
83    return (ProcXChangeFeedbackControl(client));
84}
85
86/******************************************************************************
87 *
88 * This procedure changes KbdFeedbackClass data.
89 *
90 */
91
92static int
93ChangeKbdFeedback(ClientPtr client, DeviceIntPtr dev, long unsigned int mask,
94		  KbdFeedbackPtr k, xKbdFeedbackCtl * f)
95{
96    char n;
97    KeybdCtrl kctrl;
98    int t;
99    int key = DO_ALL;
100
101    if (client->swapped) {
102	swaps(&f->length, n);
103	swaps(&f->pitch, n);
104	swaps(&f->duration, n);
105	swapl(&f->led_mask, n);
106	swapl(&f->led_values, n);
107    }
108
109    kctrl = k->ctrl;
110    if (mask & DvKeyClickPercent) {
111	t = f->click;
112	if (t == -1)
113	    t = defaultKeyboardControl.click;
114	else if (t < 0 || t > 100) {
115	    client->errorValue = t;
116	    return BadValue;
117	}
118	kctrl.click = t;
119    }
120
121    if (mask & DvPercent) {
122	t = f->percent;
123	if (t == -1)
124	    t = defaultKeyboardControl.bell;
125	else if (t < 0 || t > 100) {
126	    client->errorValue = t;
127	    return BadValue;
128	}
129	kctrl.bell = t;
130    }
131
132    if (mask & DvPitch) {
133	t = f->pitch;
134	if (t == -1)
135	    t = defaultKeyboardControl.bell_pitch;
136	else if (t < 0) {
137	    client->errorValue = t;
138	    return BadValue;
139	}
140	kctrl.bell_pitch = t;
141    }
142
143    if (mask & DvDuration) {
144	t = f->duration;
145	if (t == -1)
146	    t = defaultKeyboardControl.bell_duration;
147	else if (t < 0) {
148	    client->errorValue = t;
149	    return BadValue;
150	}
151	kctrl.bell_duration = t;
152    }
153
154    if (mask & DvLed) {
155	kctrl.leds &= ~(f->led_mask);
156	kctrl.leds |= (f->led_mask & f->led_values);
157    }
158
159    if (mask & DvKey) {
160	key = (KeyCode) f->key;
161	if (key < 8 || key > 255) {
162	    client->errorValue = key;
163	    return BadValue;
164	}
165	if (!(mask & DvAutoRepeatMode))
166	    return BadMatch;
167    }
168
169    if (mask & DvAutoRepeatMode) {
170	int inx = (key >> 3);
171	int kmask = (1 << (key & 7));
172
173	t = (CARD8) f->auto_repeat_mode;
174	if (t == AutoRepeatModeOff) {
175	    if (key == DO_ALL)
176		kctrl.autoRepeat = FALSE;
177	    else
178		kctrl.autoRepeats[inx] &= ~kmask;
179	} else if (t == AutoRepeatModeOn) {
180	    if (key == DO_ALL)
181		kctrl.autoRepeat = TRUE;
182	    else
183		kctrl.autoRepeats[inx] |= kmask;
184	} else if (t == AutoRepeatModeDefault) {
185	    if (key == DO_ALL)
186		kctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
187	    else
188		kctrl.autoRepeats[inx] &= ~kmask;
189	    kctrl.autoRepeats[inx] =
190		(kctrl.autoRepeats[inx] & ~kmask) |
191		(defaultKeyboardControl.autoRepeats[inx] & kmask);
192	} else {
193	    client->errorValue = t;
194	    return BadValue;
195	}
196    }
197
198    k->ctrl = kctrl;
199    (*k->CtrlProc) (dev, &k->ctrl);
200    return Success;
201}
202
203/******************************************************************************
204 *
205 * This procedure changes PtrFeedbackClass data.
206 *
207 */
208
209static int
210ChangePtrFeedback(ClientPtr client, DeviceIntPtr dev, long unsigned int mask,
211		  PtrFeedbackPtr p, xPtrFeedbackCtl * f)
212{
213    char n;
214    PtrCtrl pctrl;	/* might get BadValue part way through */
215
216    if (client->swapped) {
217	swaps(&f->length, n);
218	swaps(&f->num, n);
219	swaps(&f->denom, n);
220	swaps(&f->thresh, n);
221    }
222
223    pctrl = p->ctrl;
224    if (mask & DvAccelNum) {
225	int accelNum;
226
227	accelNum = f->num;
228	if (accelNum == -1)
229	    pctrl.num = defaultPointerControl.num;
230	else if (accelNum < 0) {
231	    client->errorValue = accelNum;
232	    return BadValue;
233	} else
234	    pctrl.num = accelNum;
235    }
236
237    if (mask & DvAccelDenom) {
238	int accelDenom;
239
240	accelDenom = f->denom;
241	if (accelDenom == -1)
242	    pctrl.den = defaultPointerControl.den;
243	else if (accelDenom <= 0) {
244	    client->errorValue = accelDenom;
245	    return BadValue;
246	} else
247	    pctrl.den = accelDenom;
248    }
249
250    if (mask & DvThreshold) {
251	int threshold;
252
253	threshold = f->thresh;
254	if (threshold == -1)
255	    pctrl.threshold = defaultPointerControl.threshold;
256	else if (threshold < 0) {
257	    client->errorValue = threshold;
258	    return BadValue;
259	} else
260	    pctrl.threshold = threshold;
261    }
262
263    p->ctrl = pctrl;
264    (*p->CtrlProc) (dev, &p->ctrl);
265    return Success;
266}
267
268/******************************************************************************
269 *
270 * This procedure changes IntegerFeedbackClass data.
271 *
272 */
273
274static int
275ChangeIntegerFeedback(ClientPtr client, DeviceIntPtr dev,
276		      long unsigned int mask, IntegerFeedbackPtr i,
277		      xIntegerFeedbackCtl * f)
278{
279    char n;
280
281    if (client->swapped) {
282	swaps(&f->length, n);
283	swapl(&f->int_to_display, n);
284    }
285
286    i->ctrl.integer_displayed = f->int_to_display;
287    (*i->CtrlProc) (dev, &i->ctrl);
288    return Success;
289}
290
291/******************************************************************************
292 *
293 * This procedure changes StringFeedbackClass data.
294 *
295 */
296
297static int
298ChangeStringFeedback(ClientPtr client, DeviceIntPtr dev,
299		     long unsigned int mask, StringFeedbackPtr s,
300		     xStringFeedbackCtl * f)
301{
302    char n;
303    int i, j;
304    KeySym *syms, *sup_syms;
305
306    syms = (KeySym *) (f + 1);
307    if (client->swapped) {
308	swaps(&f->length, n);	/* swapped num_keysyms in calling proc */
309	SwapLongs((CARD32 *) syms, f->num_keysyms);
310    }
311
312    if (f->num_keysyms > s->ctrl.max_symbols)
313	return BadValue;
314
315    sup_syms = s->ctrl.symbols_supported;
316    for (i = 0; i < f->num_keysyms; i++) {
317	for (j = 0; j < s->ctrl.num_symbols_supported; j++)
318	    if (*(syms + i) == *(sup_syms + j))
319		break;
320	if (j == s->ctrl.num_symbols_supported)
321	    return BadMatch;
322    }
323
324    s->ctrl.num_symbols_displayed = f->num_keysyms;
325    for (i = 0; i < f->num_keysyms; i++)
326	*(s->ctrl.symbols_displayed + i) = *(syms + i);
327    (*s->CtrlProc) (dev, &s->ctrl);
328    return Success;
329}
330
331/******************************************************************************
332 *
333 * This procedure changes BellFeedbackClass data.
334 *
335 */
336
337static int
338ChangeBellFeedback(ClientPtr client, DeviceIntPtr dev,
339		   long unsigned int mask, BellFeedbackPtr b,
340		   xBellFeedbackCtl * f)
341{
342    char n;
343    int t;
344    BellCtrl bctrl;	/* might get BadValue part way through */
345
346    if (client->swapped) {
347	swaps(&f->length, n);
348	swaps(&f->pitch, n);
349	swaps(&f->duration, n);
350    }
351
352    bctrl = b->ctrl;
353    if (mask & DvPercent) {
354	t = f->percent;
355	if (t == -1)
356	    t = defaultKeyboardControl.bell;
357	else if (t < 0 || t > 100) {
358	    client->errorValue = t;
359	    return BadValue;
360	}
361	bctrl.percent = t;
362    }
363
364    if (mask & DvPitch) {
365	t = f->pitch;
366	if (t == -1)
367	    t = defaultKeyboardControl.bell_pitch;
368	else if (t < 0) {
369	    client->errorValue = t;
370	    return BadValue;
371	}
372	bctrl.pitch = t;
373    }
374
375    if (mask & DvDuration) {
376	t = f->duration;
377	if (t == -1)
378	    t = defaultKeyboardControl.bell_duration;
379	else if (t < 0) {
380	    client->errorValue = t;
381	    return BadValue;
382	}
383	bctrl.duration = t;
384    }
385    b->ctrl = bctrl;
386    (*b->CtrlProc) (dev, &b->ctrl);
387    return Success;
388}
389
390/******************************************************************************
391 *
392 * This procedure changes LedFeedbackClass data.
393 *
394 */
395
396static int
397ChangeLedFeedback(ClientPtr client, DeviceIntPtr dev, long unsigned int mask,
398		  LedFeedbackPtr l, xLedFeedbackCtl * f)
399{
400    char n;
401    LedCtrl lctrl;	/* might get BadValue part way through */
402
403    if (client->swapped) {
404	swaps(&f->length, n);
405	swapl(&f->led_values, n);
406	swapl(&f->led_mask, n);
407    }
408
409    f->led_mask &= l->ctrl.led_mask;	/* set only supported leds */
410    f->led_values &= l->ctrl.led_mask;	/* set only supported leds */
411    if (mask & DvLed) {
412	lctrl.led_mask = f->led_mask;
413	lctrl.led_values = f->led_values;
414	(*l->CtrlProc) (dev, &lctrl);
415	l->ctrl.led_values &= ~(f->led_mask);	/* zero changed leds */
416	l->ctrl.led_values |= (f->led_mask & f->led_values);	/* OR in set leds */
417    }
418
419    return Success;
420}
421
422/***********************************************************************
423 *
424 * Change the control attributes.
425 *
426 */
427
428int
429ProcXChangeFeedbackControl(ClientPtr client)
430{
431    unsigned len;
432    DeviceIntPtr dev;
433    KbdFeedbackPtr k;
434    PtrFeedbackPtr p;
435    IntegerFeedbackPtr i;
436    StringFeedbackPtr s;
437    BellFeedbackPtr b;
438    LedFeedbackPtr l;
439    int rc;
440
441    REQUEST(xChangeFeedbackControlReq);
442    REQUEST_AT_LEAST_SIZE(xChangeFeedbackControlReq);
443
444    len = stuff->length - bytes_to_int32(sizeof(xChangeFeedbackControlReq));
445    rc = dixLookupDevice(&dev, stuff->deviceid, client, DixManageAccess);
446    if (rc != Success)
447	return rc;
448
449    switch (stuff->feedbackid) {
450    case KbdFeedbackClass:
451	if (len != bytes_to_int32(sizeof(xKbdFeedbackCtl)))
452	    return BadLength;
453
454	for (k = dev->kbdfeed; k; k = k->next)
455	    if (k->ctrl.id == ((xKbdFeedbackCtl *) & stuff[1])->id)
456		return ChangeKbdFeedback(client, dev, stuff->mask, k,
457					 (xKbdFeedbackCtl *) & stuff[1]);
458	break;
459    case PtrFeedbackClass:
460	if (len != bytes_to_int32(sizeof(xPtrFeedbackCtl)))
461	    return BadLength;
462
463	for (p = dev->ptrfeed; p; p = p->next)
464	    if (p->ctrl.id == ((xPtrFeedbackCtl *) & stuff[1])->id)
465		return ChangePtrFeedback(client, dev, stuff->mask, p,
466					 (xPtrFeedbackCtl *) & stuff[1]);
467	break;
468    case StringFeedbackClass:
469    {
470	char n;
471        xStringFeedbackCtl *f;
472
473        REQUEST_AT_LEAST_EXTRA_SIZE(xChangeFeedbackControlReq,
474                                    sizeof(xStringFeedbackCtl));
475        f = ((xStringFeedbackCtl *) &stuff[1]);
476	if (client->swapped) {
477            if (len < bytes_to_int32(sizeof(xStringFeedbackCtl)))
478                return BadLength;
479	    swaps(&f->num_keysyms, n);
480	}
481	if (len != (bytes_to_int32(sizeof(xStringFeedbackCtl)) + f->num_keysyms))
482	    return BadLength;
483
484	for (s = dev->stringfeed; s; s = s->next)
485	    if (s->ctrl.id == ((xStringFeedbackCtl *) & stuff[1])->id)
486		return ChangeStringFeedback(client, dev, stuff->mask, s,
487					    (xStringFeedbackCtl *) & stuff[1]);
488	break;
489    }
490    case IntegerFeedbackClass:
491	if (len != bytes_to_int32(sizeof(xIntegerFeedbackCtl)))
492	    return BadLength;
493
494	for (i = dev->intfeed; i; i = i->next)
495	    if (i->ctrl.id == ((xIntegerFeedbackCtl *) & stuff[1])->id)
496		return ChangeIntegerFeedback(client, dev, stuff->mask, i,
497					     (xIntegerFeedbackCtl *)&stuff[1]);
498	break;
499    case LedFeedbackClass:
500	if (len != bytes_to_int32(sizeof(xLedFeedbackCtl)))
501	    return BadLength;
502
503	for (l = dev->leds; l; l = l->next)
504	    if (l->ctrl.id == ((xLedFeedbackCtl *) & stuff[1])->id)
505		return ChangeLedFeedback(client, dev, stuff->mask, l,
506					 (xLedFeedbackCtl *) & stuff[1]);
507	break;
508    case BellFeedbackClass:
509	if (len != bytes_to_int32(sizeof(xBellFeedbackCtl)))
510	    return BadLength;
511
512	for (b = dev->bell; b; b = b->next)
513	    if (b->ctrl.id == ((xBellFeedbackCtl *) & stuff[1])->id)
514		return ChangeBellFeedback(client, dev, stuff->mask, b,
515					  (xBellFeedbackCtl *) & stuff[1]);
516	break;
517    default:
518	break;
519    }
520
521    return BadMatch;
522}
523
524