1/*
2
3Copyright 1985, 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
25*/
26/* Modified by Stephen so keyboard rate is set using XKB extensions */
27
28#ifdef HAVE_CONFIG_H
29# include <config.h>
30#endif
31
32#ifdef HAVE_X11_EXTENSIONS_DPMS_H
33# define DPMSExtension
34#endif
35
36#ifdef HAVE_X11_EXTENSIONS_MITMISC_H
37# define MITMISC
38#endif
39
40#ifdef HAVE_X11_XKBLIB_H
41# define XKB
42#endif
43
44#if defined(HAVE_X11_EXTENSIONS_XF86MISC_H) && defined(HAVE_X11_EXTENSIONS_XF86MSCSTR_H)
45# define XF86MISC
46#endif
47
48#if defined(HAVE_X11_EXTENSIONS_FONTCACHE_H) && defined(HAVE_X11_EXTENSIONS_FONTCACHEP_H)
49# define FONTCACHE
50#endif
51
52#include <stdio.h>
53#include <ctype.h>
54#include <stdarg.h>
55#include <stdlib.h>
56#ifdef HAVE_USLEEP
57#include <unistd.h>
58#endif
59#include <X11/Xos.h>
60#include <X11/Xfuncs.h>
61#include <X11/Xlib.h>
62#include <X11/keysym.h>
63#include <X11/Xproto.h>
64#include <X11/Xutil.h>
65#include <X11/Xmu/Error.h>
66#ifdef MITMISC
67# include <X11/extensions/MITMisc.h>
68#endif
69#ifdef DPMSExtension
70# include <X11/extensions/dpms.h>
71#endif /* DPMSExtension */
72
73#ifdef XF86MISC
74# include <X11/extensions/xf86misc.h>
75# include <X11/extensions/xf86mscstr.h>
76#endif
77#ifdef XKB
78# include <X11/XKBlib.h>
79#endif
80#ifdef FONTCACHE
81# include <X11/extensions/fontcache.h>
82# include <X11/extensions/fontcacheP.h>
83
84static Status set_font_cache(Display *, long, long, long);
85static void query_cache_status(Display *dpy);
86#endif
87
88#define ON 1
89#define OFF 0
90
91#define SERVER_DEFAULT (-1)
92#define DONT_CHANGE -2
93
94#define DEFAULT_ON (-50)
95#define DEFAULT_TIMEOUT (-600)
96
97#define ALL -1
98#define TIMEOUT 1
99#define INTERVAL 2
100#define PREFER_BLANK 3
101#define ALLOW_EXP 4
102
103#ifdef XF86MISC
104# define KBDDELAY_DEFAULT 500
105# define KBDRATE_DEFAULT 30
106#endif
107#ifdef XKB
108# define XKBDDELAY_DEFAULT 660
109# define XKBDRATE_DEFAULT (1000/40)
110#endif
111
112#define	nextarg(i, argv) \
113	argv[i]; \
114	if (i >= argc) \
115		break; \
116
117static char *progName;
118
119static int error_status = 0;
120
121static int is_number(const char *arg, int maximum);
122static void set_click(Display *dpy, int percent);
123static void set_bell_vol(Display *dpy, int percent);
124static void set_bell_pitch(Display *dpy, int pitch);
125static void set_bell_dur(Display *dpy, int duration);
126static void set_font_path(Display *dpy, const char *path, int special,
127			  int before, int after);
128static void set_led(Display *dpy, int led, int led_mode);
129static void xkbset_led(Display *dpy, const char *led, int led_mode);
130static void set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold);
131static void set_saver(Display *dpy, int mask, int value);
132static void set_repeat(Display *dpy, int key, int auto_repeat_mode);
133static void set_pixels(Display *dpy, const unsigned long *pixels,
134                       caddr_t *colors, int numpixels);
135static void set_lock(Display *dpy, Bool onoff);
136static const char *on_or_off(int val, int onval, const char *onstr,
137                             int offval, const char *offstr,
138                             char buf[], size_t bufsize);
139static void query(Display *dpy);
140static void usage(const char *fmt, ...) _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2);
141static void error(const char *message) _X_NORETURN;
142static int local_xerror(Display *dpy, XErrorEvent *rep);
143
144#ifdef XF86MISC
145static void set_repeatrate(Display *dpy, int delay, int rate);
146#endif
147#ifdef XKB
148static void xkbset_repeatrate(Display *dpy, int delay, int rate);
149#endif
150
151int
152main(int argc, char *argv[])
153{
154    const char *arg;
155
156#define MAX_PIXEL_COUNT 512
157    unsigned long pixels[MAX_PIXEL_COUNT];
158    caddr_t colors[MAX_PIXEL_COUNT];
159    int numpixels = 0;
160    char *disp = NULL;
161    Display *dpy;
162    Bool hasargs = False;
163
164    progName = argv[0];
165    for (int i = 1; i < argc; i++) {
166	arg = argv[i];
167	if (strcmp(arg, "-display") == 0 || strcmp(arg, "-d") == 0) {
168	    if (++i >= argc)
169		usage("missing argument to -display");
170	    disp = argv[i];
171	} else if (strcmp(arg, "-version") == 0) {
172	    puts(PACKAGE_STRING);
173	    exit(EXIT_SUCCESS);
174	} else {
175	    hasargs = True;
176	}
177    }
178    if (!hasargs) {
179	usage(NULL);		       /* replace with window interface */
180    }
181
182    dpy = XOpenDisplay(disp);    /*  Open display and check for success */
183    if (dpy == NULL) {
184	fprintf(stderr, "%s:  unable to open display \"%s\"\n",
185		argv[0], XDisplayName(disp));
186	exit(EXIT_FAILURE);
187    }
188    XSetErrorHandler(local_xerror);
189    for (int i = 1; i < argc;) {
190	arg = argv[i++];
191	if (strcmp(arg, "-display") == 0 || strcmp(arg, "-d") == 0) {
192	    ++i;		       		/* already dealt with */
193	    continue;
194	} else if (*arg == '-' && *(arg + 1) == 'c') {	/* Does arg start
195							   with "-c"? */
196	    set_click(dpy, 0);	       		/* If so, turn click off */
197	} else if (*arg == 'c') {      		/* Well, does it start
198						   with "c", then? */
199	    int percent = SERVER_DEFAULT; 	/* Default click volume. */
200	    if (i >= argc) {
201		set_click(dpy, percent);	/* set click to default */
202		break;
203	    }
204	    arg = nextarg(i, argv);
205	    if (strcmp(arg, "on") == 0) {	/* Let click be default. */
206		percent = DEFAULT_ON;
207		i++;
208	    } else if (strcmp(arg, "off") == 0) {
209		percent = 0;	       		/* Turn it off.          */
210		i++;
211	    } else if (is_number(arg, 100)) {
212		percent = atoi(arg);		/* Set to spec. volume */
213		i++;
214	    }
215	    set_click(dpy, percent);
216	} else if (strcmp(arg, "-b") == 0) {
217	    set_bell_vol(dpy, 0);      		/* Then turn off bell.    */
218	} else if (strcmp(arg, "b") == 0) {
219	    int percent = SERVER_DEFAULT;  	/* Set bell to default. */
220	    if (i >= argc) {
221		set_bell_vol(dpy, percent);	/* set bell to default */
222		set_bell_pitch(dpy, percent);	/* set pitch to default */
223		set_bell_dur(dpy, percent);	/* set duration to default */
224		break;
225	    }
226	    arg = nextarg(i, argv);
227	    if (strcmp(arg, "on") == 0) {	/* Let it stay that way.  */
228		set_bell_vol(dpy, DEFAULT_ON);	/* set bell on */
229		set_bell_pitch(dpy, percent);	/* set pitch to default */
230		set_bell_dur(dpy, percent);	/* set duration to default */
231		i++;
232	    } else if (strcmp(arg, "off") == 0) {
233		percent = 0;	       		/* Turn the bell off.     */
234		set_bell_vol(dpy, percent);
235		i++;
236	    } else if (is_number(arg, 100)) {	/* If volume is given:    */
237		percent = atoi(arg);   	       	/* set bell appropriately. */
238		set_bell_vol(dpy, percent);
239		i++;
240		arg = nextarg(i, argv);
241
242		if (is_number(arg, 32767)) {	/* If pitch is given:     */
243		    set_bell_pitch(dpy, atoi(arg));	/* set the bell.  */
244		    i++;
245
246		    arg = nextarg(i, argv);
247		    if (is_number(arg, 32767)) { /* If duration is given:  */
248			set_bell_dur(dpy, atoi(arg));	/*  set the bell.  */
249			i++;
250		    }
251		}
252	    } else
253		set_bell_vol(dpy, percent);	/* set bell to default */
254	}
255#ifdef MITMISC
256	else if (strcmp(arg, "bc") == 0) {
257	    int dummy;
258
259	    if (XMITMiscQueryExtension(dpy, &dummy, &dummy))
260		XMITMiscSetBugMode(dpy, True);
261	    else
262		fprintf(stderr,
263			"server does not have extension for bc option\n");
264	} else if (strcmp(arg, "-bc") == 0) {
265	    int dummy;
266
267	    if (XMITMiscQueryExtension(dpy, &dummy, &dummy))
268		XMITMiscSetBugMode(dpy, False);
269	    else
270		fprintf(stderr,
271			"server does not have extension for -bc option\n");
272	}
273#endif
274#ifdef FONTCACHE
275	else if (strcmp(arg, "fc") == 0) {
276	    int dummy;
277	    FontCacheSettings cs;
278
279	    if (FontCacheQueryExtension(dpy, &dummy, &dummy)) {
280		long himark, lowmark, balance;
281
282		FontCacheGetCacheSettings(dpy, &cs);
283		himark = cs.himark / 1024;
284		lowmark = cs.lowmark / 1024;
285		balance = cs.balance;
286		if (i >= argc) {
287		    /* Set to server's values, and clear all cache
288		       in side effect */
289		    set_font_cache(dpy, himark, lowmark, balance);
290		    break;
291		}
292		arg = nextarg(i, argv);
293		if (is_number(arg, 32767)) {	/* If hi-mark is given: */
294		    himark = atoi(arg);
295		    i++;
296		    if (himark <= 0) {
297			usage("hi-mark must be greater than 0");
298		    }
299		    if (i >= argc) {
300			lowmark = (himark * 70) / 100;
301			set_font_cache(dpy, himark, lowmark, balance);
302			break;
303		    }
304		    arg = nextarg(i, argv);
305		    if (is_number(arg, 32767)) { /* If low-mark is given: */
306			lowmark = atoi(arg);
307			i++;
308			if (lowmark <= 0) {
309			    usage("low-mark must be greater than 0");
310			}
311			if (himark <= lowmark) {
312			    usage("hi-mark must be greater than low-mark");
313			}
314			if (i >= argc) {
315			    set_font_cache(dpy, himark, lowmark, balance);
316			    break;
317			}
318			arg = nextarg(i, argv);
319			if (is_number(arg, 90)) {
320			    balance = atoi(arg);
321			    i++;
322			    if (!(10 <= balance && balance <= 90)) {
323				usage("balance must be 10 to 90\n");
324			    }
325			    set_font_cache(dpy, himark, lowmark, balance);
326			}
327		    }
328		} else if (strcmp(arg, "s") == 0
329		    || strcmp(arg, "status") == 0) {
330		    /* display cache status */
331		    query_cache_status(dpy);
332		}
333	    } else {
334		fprintf(stderr,
335			"server does not have extension for fc option\n");
336	    }
337	}
338#endif
339	else if (strcmp(arg, "fp") == 0) {	/* set font path */
340	    if (i >= argc) {
341		arg = "default";
342	    } else {
343		arg = nextarg(i, argv);
344	    }
345	    set_font_path(dpy, arg, 1, 0, 0);	/* special argument */
346	    i++;
347	} else if (strcmp(arg, "fp=") == 0) {	/* unconditionally set */
348	    if (i >= argc) {
349		usage("missing fp= argument");
350	    } else {
351		arg = nextarg(i, argv);
352	    }
353	    set_font_path(dpy, arg, 0, 0, 0);	/* not special, set */
354	    i++;
355	} else if (strcmp(arg, "+fp") == 0) {	/* set font path */
356	    if (i >= argc)
357		usage("missing +fp argument");
358	    arg = nextarg(i, argv);
359	    set_font_path(dpy, arg, 0, 1, 0);	/* not special, prepend */
360	    i++;
361	} else if (strcmp(arg, "fp+") == 0) {	/* set font path */
362	    if (i >= argc)
363		usage("missing fp+ argument");
364	    arg = nextarg(i, argv);
365	    set_font_path(dpy, arg, 0, 0, 1);	/* not special, append */
366	    i++;
367	} else if (strcmp(arg, "-fp") == 0) {	/* set font path */
368	    if (i >= argc)
369		usage("missing -fp argument");
370	    arg = nextarg(i, argv);
371	    set_font_path(dpy, arg, 0, -1, 0);	/* not special, preremove */
372	    i++;
373	} else if (strcmp(arg, "fp-") == 0) {	/* set font path */
374	    if (i >= argc)
375		usage("missing fp- argument");
376	    arg = nextarg(i, argv);
377	    set_font_path(dpy, arg, 0, 0, -1);	/* not special, postremove */
378	    i++;
379	} else if (strcmp(arg, "-led") == 0) {	/* Turn off one or all LEDs */
380	    XKeyboardControl values = {
381		.led_mode = OFF,
382		.led = ALL	       		/* None specified */
383	    };
384
385	    if (i >= argc) {
386		set_led(dpy, values.led, values.led_mode);
387		break;
388	    }
389	    arg = nextarg(i, argv);
390	    if (strcmp(arg, "named") == 0) {
391		if (++i >= argc) {
392		    usage("missing argument to led named");
393		} else {
394		    arg = nextarg(i, argv);
395		    xkbset_led(dpy, arg, values.led_mode);
396		}
397		break;
398	    }
399	    if (is_number(arg, 32) && atoi(arg) > 0) {
400		values.led = atoi(arg);
401		i++;
402	    }
403	    set_led(dpy, values.led, values.led_mode);
404	} else if (strcmp(arg, "led") == 0) {	/* Turn on one or all LEDs  */
405	    XKeyboardControl values = {
406		.led_mode = ON,
407		.led = ALL
408	    };
409
410	    if (i >= argc) {
411		set_led(dpy, values.led,
412			values.led_mode);	/* set led to def */
413		break;
414	    }
415	    arg = nextarg(i, argv);
416	    if (strcmp(arg, "named") == 0) {
417		if (++i >= argc) {
418		    usage("missing argument to -led named");
419		} else {
420		    arg = nextarg(i, argv);
421		    xkbset_led(dpy, arg, values.led_mode);
422		}
423		break;
424	    }
425	    if (strcmp(arg, "on") == 0) {
426		i++;
427	    } else if (strcmp(arg, "off") == 0) { /* ...except in this case. */
428		values.led_mode = OFF;
429		i++;
430	    } else if (is_number(arg, 32) && atoi(arg) > 0) {
431		values.led = atoi(arg);
432		i++;
433	    }
434	    set_led(dpy, values.led, values.led_mode);
435	}
436/*  Set pointer (mouse) settings:  Acceleration and Threshold. */
437	else if (strcmp(arg, "m") == 0 || strcmp(arg, "mouse") == 0) {
438	    int acc_num = SERVER_DEFAULT;	/* restore server defaults */
439	    int acc_denom = SERVER_DEFAULT;
440	    int threshold = SERVER_DEFAULT;
441
442	    if (i >= argc) {
443		set_mouse(dpy, acc_num, acc_denom, threshold);
444		break;
445	    }
446	    arg = argv[i];
447	    if (strcmp(arg, "default") == 0) {
448		i++;
449	    } else if (*arg >= '0' && *arg <= '9') {
450		acc_denom = 1;
451		sscanf(arg, "%d/%d", &acc_num, &acc_denom);
452		i++;
453		if (i >= argc) {
454		    set_mouse(dpy, acc_num, acc_denom, threshold);
455		    break;
456		}
457		arg = argv[i];
458		if (*arg >= '0' && *arg <= '9') {
459		    threshold = atoi(arg); /* Set threshold as user specified. */
460		    i++;
461		}
462	    }
463	    set_mouse(dpy, acc_num, acc_denom, threshold);
464	}
465#ifdef DPMSExtension
466	else if (strcmp(arg, "+dpms") == 0) {	/* turn on DPMS */
467	    int dummy;
468
469	    if (DPMSQueryExtension(dpy, &dummy, &dummy))
470		DPMSEnable(dpy);
471	    else
472		fprintf(stderr,
473		    "server does not have extension for +dpms option\n");
474	} else if (strcmp(arg, "-dpms") == 0) {	/* shut off DPMS */
475	    int dummy;
476
477	    if (DPMSQueryExtension(dpy, &dummy, &dummy))
478		DPMSDisable(dpy);
479	    else
480		fprintf(stderr,
481		    "server does not have extension for -dpms option\n");
482
483	} else if (strcmp(arg, "dpms") == 0) {	/* tune DPMS */
484	    int dummy;
485
486	    if (DPMSQueryExtension(dpy, &dummy, &dummy)) {
487		CARD16 standby_timeout, suspend_timeout, off_timeout;
488
489		DPMSGetTimeouts(dpy, &standby_timeout, &suspend_timeout,
490		    &off_timeout);
491		if (i >= argc) {
492		    DPMSEnable(dpy);
493		    break;
494		}
495		arg = argv[i];
496		if (*arg >= '0' && *arg <= '9') {
497		    sscanf(arg, "%hu", &standby_timeout);
498		    i++;
499		    arg = argv[i];
500		    if ((arg) && (*arg >= '0' && *arg <= '9')) {
501			sscanf(arg, "%hu", &suspend_timeout);
502			i++;
503			arg = argv[i];
504			if ((arg) && (*arg >= '0' && *arg <= '9')) {
505			    sscanf(arg, "%hu", &off_timeout);
506			    i++;
507			    arg = argv[i];
508			}
509		    }
510		    if ((suspend_timeout != 0)
511			&& (standby_timeout > suspend_timeout)) {
512			fprintf(stderr, "illegal combination of values\n");
513			fprintf(stderr,
514			    "  standby time of %d is greater than suspend time of %d\n",
515			    standby_timeout, suspend_timeout);
516			exit(EXIT_FAILURE);
517		    }
518		    if ((off_timeout != 0) && (suspend_timeout > off_timeout)) {
519			fprintf(stderr, "illegal combination of values\n");
520			fprintf(stderr,
521			    "  suspend time of %d is greater than off time of %d\n",
522			    suspend_timeout, off_timeout);
523			exit(EXIT_FAILURE);
524		    }
525		    if ((suspend_timeout == 0) && (off_timeout != 0) &&
526			(standby_timeout > off_timeout)) {
527			fprintf(stderr, "illegal combination of values\n");
528			fprintf(stderr,
529			    "  standby time of %d is greater than off time of %d\n",
530			    standby_timeout, off_timeout);
531			exit(EXIT_FAILURE);
532		    }
533		    DPMSEnable(dpy);
534		    DPMSSetTimeouts(dpy, standby_timeout, suspend_timeout,
535			off_timeout);
536		} else if (strcmp(arg, "force") == 0) {
537		    if (++i >= argc)
538			usage("missing argument to dpms force");
539		    arg = argv[i];
540		    /*
541		     * The calls to usleep below are necessary to
542		     * delay the actual DPMS mode setting briefly.
543		     * Without them, it's likely that the mode will be
544		     * set between the Down and Up key transitions, in
545		     * which case the Up transition may immediately
546		     * turn the display back on.
547		     *
548		     */
549
550#ifdef HAVE_USLEEP
551# define Usleep(us) usleep((us))
552#elif defined(WIN32)
553# define Usleep(us) Sleep(us)
554#else
555# define Usleep(us) sleep((us / 1000000 > 0) ? us / 1000000 : 1)
556#endif /* HAVE_USLEEP */
557
558		    if (strcmp(arg, "on") == 0) {
559			DPMSEnable(dpy);
560			DPMSForceLevel(dpy, DPMSModeOn);
561			i++;
562		    } else if (strcmp(arg, "standby") == 0) {
563			DPMSEnable(dpy);
564			Usleep(100000);
565			DPMSForceLevel(dpy, DPMSModeStandby);
566			i++;
567		    } else if (strcmp(arg, "suspend") == 0) {
568			DPMSEnable(dpy);
569			Usleep(100000);
570			DPMSForceLevel(dpy, DPMSModeSuspend);
571			i++;
572		    } else if (strcmp(arg, "off") == 0) {
573			DPMSEnable(dpy);
574			Usleep(100000);
575			DPMSForceLevel(dpy, DPMSModeOff);
576			i++;
577		    } else {
578			fprintf(stderr, "bad parameter %s\n", arg);
579			i++;
580		    }
581		}
582	    } else {
583		fprintf(stderr,
584		    "server does not have extension for dpms option\n");
585	    }
586	}
587#endif /* DPMSExtension */
588	else if (strcmp(arg, "s") == 0) {
589	    if (i >= argc) {
590		set_saver(dpy, ALL, 0);	/* Set everything to default  */
591		break;
592	    }
593	    arg = argv[i];
594	    if (strcmp(arg, "blank") == 0) { /* Alter blanking preference. */
595		set_saver(dpy, PREFER_BLANK, PreferBlanking);
596		i++;
597	    } else if (strcmp(arg, "noblank") == 0) {	/*  Ditto.  */
598		set_saver(dpy, PREFER_BLANK, DontPreferBlanking);
599		i++;
600	    } else if (strcmp(arg, "expose") == 0) {	/* Alter exposure preference. */
601		set_saver(dpy, ALLOW_EXP, AllowExposures);
602		i++;
603	    } else if (strcmp(arg, "noexpose") == 0) {	/*  Ditto.  */
604		set_saver(dpy, ALLOW_EXP, DontAllowExposures);
605		i++;
606	    } else if (strcmp(arg, "off") == 0) {
607		set_saver(dpy, TIMEOUT, 0);	/*  Turn off screen saver.  */
608		i++;
609		if (i >= argc)
610		    break;
611		arg = argv[i];
612		if (strcmp(arg, "off") == 0) {
613		    set_saver(dpy, INTERVAL, 0);
614		    i++;
615		}
616	    } else if (strcmp(arg, "default") == 0) {	/* Leave as default. */
617		set_saver(dpy, ALL, SERVER_DEFAULT);
618		i++;
619	    } else if (strcmp(arg, "on") == 0) {	/* Turn on.       */
620		set_saver(dpy, ALL, DEFAULT_TIMEOUT);
621		i++;
622	    } else if (strcmp(arg, "activate") == 0) {	/* force it active */
623		XActivateScreenSaver(dpy);
624		i++;
625	    } else if (strcmp(arg, "reset") == 0) {	/* force it inactive */
626		XResetScreenSaver(dpy);
627		i++;
628	    } else if (*arg >= '0' && *arg <= '9') {	/* Set as user wishes. */
629		set_saver(dpy, TIMEOUT, atoi(arg));
630		i++;
631		if (i >= argc)
632		    break;
633		arg = argv[i];
634		if (*arg >= '0' && *arg <= '9') {
635		    set_saver(dpy, INTERVAL, atoi(arg));
636		    i++;
637		}
638	    }
639	} else if (strcmp(arg, "-r") == 0) {		/* Turn off one or
640							   all autorepeats */
641	    int auto_repeat_mode = OFF;
642	    int key = ALL;	       			/* None specified */
643
644	    arg = argv[i];
645	    if (i < argc)
646		if (is_number(arg, 255)) {
647		    key = atoi(arg);
648		    i++;
649		}
650	    set_repeat(dpy, key, auto_repeat_mode);
651	} else if (strcmp(arg, "r") == 0) {		/* Turn on one or
652							   all autorepeats */
653	    int auto_repeat_mode = ON;
654	    int key = ALL;	       			/* None specified */
655
656	    arg = argv[i];
657	    if (i < argc) {
658		if (strcmp(arg, "on") == 0) {
659		    i++;
660		} else if (strcmp(arg, "off") == 0) {	/*  ...except in
661							    this case */
662		    auto_repeat_mode = OFF;
663		    i++;
664		}
665#if defined(XF86MISC) || defined(XKB)
666		else if (strcmp(arg, "rate") == 0) {	/*  ...or this one. */
667		    int delay = 0, rate = 0;
668		    int miscpresent = 0;
669		    int xkbpresent = 0;
670
671#ifdef XF86MISC
672		    int rate_set = 0;
673#endif
674#ifdef XKB
675		    int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
676		    int xkbopcode, xkbevent, xkberror;
677
678		    if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent,
679					  &xkberror, &xkbmajor, &xkbminor)) {
680			delay = XKBDDELAY_DEFAULT;
681			rate = XKBDRATE_DEFAULT;
682			xkbpresent = 1;
683		    }
684#endif
685#ifdef XF86MISC
686		    if (!xkbpresent) {
687			int dummy;
688
689			if (XF86MiscQueryExtension(dpy, &dummy, &dummy)) {
690			    delay = KBDDELAY_DEFAULT;
691			    rate = KBDRATE_DEFAULT;
692			    miscpresent = 1;
693			}
694		    }
695#endif
696		    if (!xkbpresent && !miscpresent)
697			fprintf(stderr,
698				"server does not have extension for \"r rate\" option\n");
699		    i++;
700		    arg = argv[i];
701		    if (i < argc) {
702			if (is_number(arg, 10000) && atoi(arg) > 0) {
703			    delay = atoi(arg);
704			    i++;
705			    arg = argv[i];
706			    if (i < argc) {
707				if (is_number(arg, 255) && atoi(arg) > 0) {
708				    rate = atoi(arg);
709				    i++;
710				}
711			    }
712			}
713		    }
714#ifdef XKB
715		    if (xkbpresent) {
716			xkbset_repeatrate(dpy, delay, 1000 / rate);
717#ifdef XF86MISC
718			rate_set = 1;
719#endif
720		    }
721#endif
722#ifdef XF86MISC
723		    if (miscpresent && !rate_set) {
724			set_repeatrate(dpy, delay, rate);
725		    }
726#endif
727		}
728#endif
729		else if (is_number(arg, 255)) {
730		    key = atoi(arg);
731		    i++;
732		}
733	    }
734	    set_repeat(dpy, key, auto_repeat_mode);
735	} else if (strcmp(arg, "p") == 0) {
736	    if (i + 1 >= argc)
737		usage("missing argument to p");
738	    arg = argv[i];
739	    if (numpixels >= MAX_PIXEL_COUNT)
740		usage("more than %d pixels specified", MAX_PIXEL_COUNT);
741	    if (*arg >= '0' && *arg <= '9')
742		pixels[numpixels] = strtoul(arg, NULL, 10);
743	    else
744		usage("invalid pixel number %s", arg);
745	    i++;
746	    colors[numpixels] = argv[i];
747	    i++;
748	    numpixels++;
749	} else if (strcmp(arg, "-k") == 0) {
750	    set_lock(dpy, OFF);
751	} else if (strcmp(arg, "k") == 0) {
752	    set_lock(dpy, ON);
753	} else if (strcmp(arg, "q") == 0 || strcmp(arg, "-q") == 0) {
754	    query(dpy);
755	} else
756	    usage("unknown option %s", arg);
757    }
758
759    if (numpixels)
760	set_pixels(dpy, pixels, colors, numpixels);
761
762    XCloseDisplay(dpy);
763
764    exit(error_status);		       /*  Done.  We can go home now.  */
765}
766
767static int
768is_number(const char *arg, int maximum)
769{
770    const char *p;
771
772    if (arg[0] == '-' && arg[1] == '1' && arg[2] == '\0')
773	return (1);
774    for (p = arg; isdigit(*p); p++) ;
775    if (*p || atoi(arg) > maximum)
776	return (0);
777    return (1);
778}
779
780/*  These next few functions do the real work (xsetting things).
781 */
782static void
783set_click(Display *dpy, int percent)
784{
785    XKeyboardControl values = { .key_click_percent = percent };
786
787    if (percent == DEFAULT_ON)
788	values.key_click_percent = SERVER_DEFAULT;
789    XChangeKeyboardControl(dpy, KBKeyClickPercent, &values);
790    if (percent == DEFAULT_ON) {
791	XKeyboardState kbstate;
792
793	XGetKeyboardControl(dpy, &kbstate);
794	if (!kbstate.key_click_percent) {
795	    values.key_click_percent = -percent;
796	    XChangeKeyboardControl(dpy, KBKeyClickPercent, &values);
797	}
798    }
799    return;
800}
801
802static void
803set_bell_vol(Display *dpy, int percent)
804{
805    XKeyboardControl values = { .bell_percent = percent };
806
807    if (percent == DEFAULT_ON)
808	values.bell_percent = SERVER_DEFAULT;
809    XChangeKeyboardControl(dpy, KBBellPercent, &values);
810    if (percent == DEFAULT_ON) {
811	XKeyboardState kbstate;
812
813	XGetKeyboardControl(dpy, &kbstate);
814	if (!kbstate.bell_percent) {
815	    values.bell_percent = -percent;
816	    XChangeKeyboardControl(dpy, KBBellPercent, &values);
817	}
818    }
819    return;
820}
821
822static void
823set_bell_pitch(Display *dpy, int pitch)
824{
825    XKeyboardControl values = { .bell_pitch = pitch };
826
827    XChangeKeyboardControl(dpy, KBBellPitch, &values);
828    return;
829}
830
831static void
832set_bell_dur(Display *dpy, int duration)
833{
834    XKeyboardControl values = { .bell_duration = duration };
835
836    XChangeKeyboardControl(dpy, KBBellDuration, &values);
837    return;
838}
839
840/*
841 * Set, add, or subtract the path according to before and after flags:
842 *
843 *	before	after	action
844 *
845 *	   0      0	FontPath := path
846 *	  -1      0	FontPath := current - path
847 *	   0     -1	FontPath := current - path
848 *	   1      0	FontPath := path + current
849 *	   0      1	FontPath := current + path
850 */
851static void
852set_font_path(Display *dpy, const char *path, int special, int before, int after)
853{
854    char *directories = NULL;
855    char **directoryList = NULL;
856    unsigned int ndirs = 0;
857    char **currentList = NULL;
858    unsigned int ncurrent = 0;
859
860    if (special) {
861	if (strcmp(path, "default") == 0) {
862	    XSetFontPath(dpy, NULL, 0);
863	    return;
864	}
865	if (strcmp(path, "rehash") == 0) {
866	    currentList = XGetFontPath(dpy, (int *) &ncurrent);
867	    if (!currentList) {
868		fprintf(stderr, "%s:  unable to get current font path.\n",
869			progName);
870		return;
871	    }
872	    XSetFontPath(dpy, currentList, (int) ncurrent);
873	    XFreeFontPath(currentList);
874	    return;
875	}
876	/*
877	 * for now, fall though and process keyword and directory list for
878	 * compatibility with previous versions.
879	 */
880    }
881
882    /*
883     * parse the path list.  If before or after is non-zero, we'll need
884     * the current value.
885     */
886
887    if (before != 0 || after != 0) {
888	currentList = XGetFontPath(dpy, (int *) &ncurrent);
889	if (!currentList) {
890	    fprintf(stderr, "%s:  unable to get old font path.\n", progName);
891	    before = after = 0;
892	}
893    }
894
895    {
896	/* count the number of directories in path */
897	const char *cp = path;
898
899	ndirs = 1;
900	while ((cp = strchr(cp, ',')) != NULL) {
901	    ndirs++;
902	    cp++;
903	}
904    }
905
906    directoryList = malloc(ndirs * sizeof(char *));
907    if (!directoryList)
908	error("out of memory for font path directory list");
909
910    directories = strdup(path);
911    if (!directories)
912        error("out of memory for font path directory string");
913    else
914    {
915	/* mung the path and set directoryList pointers */
916	unsigned int i = 0;
917	char *cp = directories;
918
919	directoryList[i++] = cp;
920	while ((cp = strchr(cp, ',')) != NULL) {
921	    directoryList[i++] = cp + 1;
922	    *cp++ = '\0';
923	}
924	if (i != ndirs) {
925	    fprintf(stderr,
926		"%s: internal error, only parsed %d of %d directories.\n",
927		progName, i, ndirs);
928	    exit(EXIT_FAILURE);
929	}
930    }
931
932    /*
933     * now we have have parsed the input path, so we can set it
934     */
935
936    if (before == 0 && after == 0) {
937	XSetFontPath(dpy, directoryList, (int) ndirs);
938    }
939
940    /* if adding to list, build a superset */
941    if (before > 0 || after > 0) {
942	unsigned int nnew = ndirs + ncurrent;
943	char **newList = malloc(nnew * sizeof(char *));
944
945	if (!newList)
946	    error("out of memory");
947	if (before > 0) {	       /* new + current */
948	    memmove(newList, directoryList, (ndirs * sizeof(char *)));
949	    memmove((newList + ndirs), currentList, (ncurrent * sizeof(char *)));
950	    XSetFontPath(dpy, newList, (int) nnew);
951	} else if (after > 0) {
952	    memmove(newList, currentList, (ncurrent * sizeof(char *)));
953	    memmove((newList + ncurrent), directoryList,
954		    (ndirs * sizeof(char *)));
955	    XSetFontPath(dpy, newList,(int) nnew);
956	}
957	free(newList);
958    }
959
960    /* if deleting from list, build one the same size */
961    if (before < 0 || after < 0) {
962	unsigned int i, j;
963	unsigned int nnew = 0;
964	char **newList = malloc(ncurrent * sizeof(char *));
965
966	if (!newList)
967	    error("out of memory");
968	for (i = 0; i < ncurrent; i++) {
969	    for (j = 0; j < ndirs; j++) {
970		if (strcmp(currentList[i], directoryList[j]) == 0)
971		    break;
972	    }
973	    /* if we ran out, then insert into new list */
974	    if (j == ndirs)
975		newList[nnew++] = currentList[i];
976	}
977	if (nnew == ncurrent) {
978	    fprintf(stderr,
979		    "%s:  warning, no entries deleted from font path.\n",
980		    progName);
981	}
982	XSetFontPath(dpy, newList, (int) nnew);
983	free(newList);
984    }
985
986    free(directories);
987    free(directoryList);
988    if (currentList)
989	XFreeFontPath(currentList);
990
991    return;
992}
993
994static void
995set_led(Display *dpy, int led, int led_mode)
996{
997    XKeyboardControl values = { .led_mode = led_mode };
998
999    if (led != ALL) {
1000	values.led = led;
1001	XChangeKeyboardControl(dpy, KBLed | KBLedMode, &values);
1002    } else {
1003	XChangeKeyboardControl(dpy, KBLedMode, &values);
1004    }
1005    return;
1006}
1007
1008static void
1009xkbset_led(Display *dpy, const char *led, int led_mode)
1010{
1011#ifndef XKB
1012    error("  xset was not built with XKB Extension support\n");
1013#else
1014    int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
1015    int xkbopcode, xkbevent, xkberror;
1016
1017    if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror,
1018			  &xkbmajor, &xkbminor)) {
1019	Atom ledatom = XInternAtom(dpy, led, True);
1020
1021	if ((ledatom != None) &&
1022	    XkbGetNamedIndicator(dpy, ledatom, NULL, NULL, NULL, NULL)) {
1023	    if (XkbSetNamedIndicator(dpy, ledatom, True,
1024				     led_mode, False, NULL) == False) {
1025		printf("Failed to set led named %s %s\n",
1026		       led, led_mode ? "on" : "off");
1027	    }
1028	} else {
1029	    fprintf(stderr,"%s: Invalid led name: %s\n", progName, led);
1030	}
1031    } else {
1032	printf("  Server does not have the XKB Extension\n");
1033    }
1034#endif
1035    return;
1036}
1037
1038static void
1039set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold)
1040{
1041    int do_accel = True, do_threshold = True;
1042
1043    if (acc_num == DONT_CHANGE)	       /* what an incredible crock... */
1044	do_accel = False;
1045    if (threshold == DONT_CHANGE)
1046	do_threshold = False;
1047    if (acc_num < 0)		       /* shouldn't happen */
1048	acc_num = SERVER_DEFAULT;
1049    if (acc_denom <= 0)		       /* prevent divide by zero */
1050	acc_denom = SERVER_DEFAULT;
1051    if (threshold < 0)
1052	threshold = SERVER_DEFAULT;
1053    XChangePointerControl(dpy, do_accel, do_threshold, acc_num,
1054			  acc_denom, threshold);
1055    return;
1056}
1057
1058static void
1059set_saver(Display *dpy, int mask, int value)
1060{
1061    int timeout, interval, prefer_blank, allow_exp;
1062
1063    XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp);
1064    if (mask == TIMEOUT)
1065	timeout = value;
1066    if (mask == INTERVAL)
1067	interval = value;
1068    if (mask == PREFER_BLANK)
1069	prefer_blank = value;
1070    if (mask == ALLOW_EXP)
1071	allow_exp = value;
1072    if (mask == ALL) {
1073	timeout = SERVER_DEFAULT;
1074	interval = SERVER_DEFAULT;
1075	prefer_blank = DefaultBlanking;
1076	allow_exp = DefaultExposures;
1077    }
1078    XSetScreenSaver(dpy, timeout, interval, prefer_blank, allow_exp);
1079    if (mask == ALL && value == DEFAULT_TIMEOUT) {
1080	XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp);
1081	if (!timeout)
1082	    XSetScreenSaver(dpy, -DEFAULT_TIMEOUT, interval, prefer_blank,
1083			    allow_exp);
1084    }
1085    return;
1086}
1087
1088static void
1089set_repeat(Display *dpy, int key, int auto_repeat_mode)
1090{
1091    XKeyboardControl values = { .auto_repeat_mode = auto_repeat_mode };
1092
1093    if (key != ALL) {
1094	values.key = key;
1095	XChangeKeyboardControl(dpy, KBKey | KBAutoRepeatMode, &values);
1096    } else {
1097	XChangeKeyboardControl(dpy, KBAutoRepeatMode, &values);
1098    }
1099    return;
1100}
1101
1102#ifdef XF86MISC
1103static void
1104set_repeatrate(Display *dpy, int delay, int rate)
1105{
1106    XF86MiscKbdSettings values;
1107
1108    XF86MiscGetKbdSettings(dpy, &values);
1109    values.delay = delay;
1110    values.rate = rate;
1111    XF86MiscSetKbdSettings(dpy, &values);
1112    return;
1113}
1114#endif
1115
1116#ifdef XKB
1117static void
1118xkbset_repeatrate(Display *dpy, int delay, int interval)
1119{
1120    XkbDescPtr xkb = XkbAllocKeyboard();
1121
1122    if (!xkb)
1123	return;
1124    XkbGetControls(dpy, XkbRepeatKeysMask, xkb);
1125    xkb->ctrls->repeat_delay = delay;
1126    xkb->ctrls->repeat_interval = interval;
1127    XkbSetControls(dpy, XkbRepeatKeysMask, xkb);
1128    XkbFreeKeyboard(xkb, 0, True);
1129}
1130#endif
1131
1132static void
1133set_pixels(Display *dpy, const unsigned long *pixels, caddr_t * colors,
1134    int numpixels)
1135{
1136    XColor def;
1137    int scr = DefaultScreen(dpy);
1138    Visual *visual = DefaultVisual(dpy, scr);
1139    Colormap cmap = DefaultColormap(dpy, scr);
1140    unsigned long max_cells = (unsigned long) DisplayCells(dpy, scr);
1141    XVisualInfo viproto, *vip;
1142    int nvisuals = 0;
1143    const char *visual_type = NULL;
1144
1145    viproto.visualid = XVisualIDFromVisual(visual);
1146    vip = XGetVisualInfo(dpy, VisualIDMask, &viproto, &nvisuals);
1147    if (!vip) {
1148	fprintf(stderr, "%s: Can't get visual for visualID 0x%x\n",
1149		progName, (unsigned int)viproto.visualid);
1150	return;
1151    }
1152
1153    switch (vip->class) {
1154    case GrayScale:
1155    case PseudoColor:
1156	break;
1157    case TrueColor:
1158	visual_type = "TrueColor";
1159	/* fall through */
1160    case DirectColor:
1161	max_cells *= max_cells * max_cells;
1162	break;
1163    case StaticGray:
1164	visual_type = "StaticGray";
1165	break;
1166    case StaticColor:
1167	visual_type = "StaticColor";
1168	break;
1169    default:
1170	fprintf(stderr, "%s:  unknown visual class type %d\n",
1171		progName, vip->class);
1172	numpixels = 0;
1173    }
1174
1175    if (visual_type) {
1176	fprintf(stderr,
1177		"%s:  cannot set pixel values in read-only %s visuals\n",
1178		progName, visual_type);
1179    } else {
1180	for (int i = 0; i < numpixels; i++) {
1181	    def.pixel = pixels[i];
1182	    if (def.pixel >= max_cells)
1183		fprintf(stderr,
1184			"%s:  pixel value %ld out of colormap range 0 through %ld\n",
1185			progName, def.pixel, max_cells - 1);
1186	    else {
1187		if (XParseColor(dpy, cmap, colors[i], &def))
1188		    XStoreColor(dpy, cmap, &def);
1189		else
1190		    fprintf(stderr, "%s:  invalid color \"%s\"\n", progName,
1191			    colors[i]);
1192	    }
1193	}
1194    }
1195
1196    XFree(vip);
1197
1198    return;
1199}
1200
1201static void
1202set_lock(Display *dpy, Bool onoff)
1203{
1204    XModifierKeymap *mods;
1205
1206    mods = XGetModifierMapping(dpy);
1207
1208    if (onoff)
1209	mods =
1210	    XInsertModifiermapEntry(mods, (KeyCode) XK_Caps_Lock,
1211				    LockMapIndex);
1212    else
1213	mods =
1214	    XDeleteModifiermapEntry(mods, (KeyCode) XK_Caps_Lock,
1215				    LockMapIndex);
1216    XSetModifierMapping(dpy, mods);
1217    XFreeModifiermap(mods);
1218    return;
1219}
1220
1221#ifdef FONTCACHE
1222static Status
1223set_font_cache(Display *dpy, long himark, long lowmark, long balance)
1224{
1225    FontCacheSettings cs = {
1226	.himark = himark * 1024,
1227	.lowmark = lowmark * 1024,
1228	.balance = balance
1229    };
1230
1231    Status status = FontCacheChangeCacheSettings(dpy, &cs);
1232
1233    return status;
1234}
1235#endif
1236
1237static const char *
1238on_or_off(int val, int onval, const char *onstr,
1239    int offval, const char *offstr, char buf[], size_t bufsize)
1240{
1241    if (val == onval)
1242	return onstr;
1243    else if (val == offval)
1244	return offstr;
1245
1246    buf[0] = '\0';
1247    snprintf(buf, bufsize, "<%d>", val);
1248    return buf;
1249}
1250
1251/*  This is the information-getting function for telling the user what the
1252 *  current "xsettings" are.
1253 */
1254static void
1255query(Display *dpy)
1256{
1257    int scr = DefaultScreen(dpy);
1258    XKeyboardState values;
1259    int acc_num, acc_denom, threshold;
1260    int timeout, interval, prefer_blank, allow_exp;
1261
1262#ifdef XKB
1263    XkbDescPtr xkb;
1264    int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
1265    int xkbopcode, xkbevent, xkberror;
1266#endif
1267    char **font_path;
1268    int npaths;
1269    int i, j;
1270    char buf[20];		       /* big enough for 16 bit number */
1271
1272    XGetKeyboardControl(dpy, &values);
1273    XGetPointerControl(dpy, &acc_num, &acc_denom, &threshold);
1274    XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp);
1275    font_path = XGetFontPath(dpy, &npaths);
1276
1277    printf("Keyboard Control:\n");
1278    printf
1279	("  auto repeat:  %s    key click percent:  %d    LED mask:  %08lx\n",
1280	 on_or_off(values.global_auto_repeat, AutoRepeatModeOn, "on",
1281		   AutoRepeatModeOff, "off", buf, sizeof(buf)),
1282	 values.key_click_percent, values.led_mask);
1283#ifdef XKB
1284    if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror, &xkbmajor,
1285			  &xkbminor)
1286	&& (xkb = XkbAllocKeyboard()) != NULL) {
1287	if (XkbGetNames(dpy, XkbIndicatorNamesMask, xkb) == Success) {
1288	    Atom iatoms[XkbNumIndicators];
1289	    char *iatomnames[XkbNumIndicators];
1290	    Bool istates[XkbNumIndicators];
1291	    int inds[XkbNumIndicators];
1292	    int activecount = 0;
1293	    int maxnamelen = 0;
1294
1295	    printf("  XKB indicators:\n");
1296
1297	    for (i = 0, j = 0; i < XkbNumIndicators; i++) {
1298		if (xkb->names->indicators[i] != None) {
1299		    iatoms[j++] =  xkb->names->indicators[i];
1300		}
1301	    }
1302
1303	    if (XGetAtomNames(dpy, iatoms, j, iatomnames)) {
1304		for (i = 0; i < j; i++) {
1305		    if (XkbGetNamedIndicator(dpy, iatoms[i], &inds[i],
1306					     &istates[i], NULL, NULL)) {
1307			int namelen = (int) strlen(iatomnames[i]);
1308			if (namelen > maxnamelen) {
1309			    maxnamelen = namelen;
1310			}
1311			activecount++;
1312		    } else {
1313			inds[i] = -1;
1314		    }
1315		}
1316	    }
1317
1318	    if (activecount == 0) {
1319		printf("    None\n");
1320	    } else {
1321		int columnwidth;
1322		int linewidth;
1323
1324#define XKB_IND_FORMAT_CHARS 13 /* size of other chars in '    DD: X: off' */
1325#define MAX_LINE_WIDTH	     76
1326
1327		columnwidth = maxnamelen + XKB_IND_FORMAT_CHARS;
1328		if (columnwidth > MAX_LINE_WIDTH) {
1329		    columnwidth = MAX_LINE_WIDTH;
1330		}
1331
1332		for (i = 0, linewidth = 0; i < activecount ; i++) {
1333		    if (inds[i] != -1) {
1334			int spaces = columnwidth - XKB_IND_FORMAT_CHARS
1335			    - (int) strlen(iatomnames[i]);
1336
1337			if (spaces < 0)
1338			    spaces = 0;
1339
1340			linewidth += printf("    %02d: %s: %*s",
1341					    inds[i], iatomnames[i],
1342					    spaces + 3,
1343					    on_or_off(istates[i],
1344						      True,  "on ",
1345						      False, "off",
1346						      buf, sizeof(buf)));
1347		    }
1348		    if (linewidth > (MAX_LINE_WIDTH - columnwidth)) {
1349			printf("\n");
1350			linewidth = 0;
1351		    }
1352		}
1353		if (linewidth > 0) {
1354		    printf("\n");
1355		}
1356	    }
1357	}
1358	if (XkbGetControls(dpy, XkbRepeatKeysMask, xkb) == Success) {
1359	    printf("  auto repeat delay:  %d    repeat rate:  %d\n",
1360		   xkb->ctrls->repeat_delay,
1361		   1000 / xkb->ctrls->repeat_interval);
1362	}
1363    }
1364#ifdef XF86MISC
1365    else
1366#endif
1367#endif
1368#ifdef XF86MISC
1369    {
1370	int dummy;
1371	XF86MiscKbdSettings kbdinfo;
1372
1373	if (XF86MiscQueryExtension(dpy, &dummy, &dummy) &&
1374	    XF86MiscGetKbdSettings(dpy, &kbdinfo))
1375	    printf("  auto repeat delay:  %d    repeat rate:  %d\n",
1376	           kbdinfo.delay, kbdinfo.rate);
1377    }
1378#endif
1379    printf("  auto repeating keys:  ");
1380    for (i = 0; i < 4; i++) {
1381	if (i)
1382	    printf("                        ");
1383	for (j = 0; j < 8; j++) {
1384	    printf("%02x", (unsigned char)values.auto_repeats[i * 8 + j]);
1385	}
1386	printf("\n");
1387    }
1388    printf("  bell percent:  %d    bell pitch:  %d    bell duration:  %d\n",
1389	   values.bell_percent, values.bell_pitch, values.bell_duration);
1390
1391    printf("Pointer Control:\n");
1392    printf("  acceleration:  %d/%d    threshold:  %d\n",
1393	   acc_num, acc_denom, threshold);
1394
1395    printf("Screen Saver:\n");
1396    printf("  prefer blanking:  %s    ",
1397	   on_or_off(prefer_blank, PreferBlanking, "yes",
1398		     DontPreferBlanking, "no", buf, sizeof(buf)));
1399    printf("allow exposures:  %s\n",
1400	   on_or_off(allow_exp, AllowExposures, "yes",
1401		     DontAllowExposures, "no", buf, sizeof(buf)));
1402    printf("  timeout:  %d    cycle:  %d\n", timeout, interval);
1403
1404    printf("Colors:\n");
1405    printf("  default colormap:  0x%lx    BlackPixel:  0x%lx    WhitePixel:  0x%lx\n",
1406	   DefaultColormap(dpy, scr), BlackPixel(dpy, scr), WhitePixel(dpy,
1407								       scr));
1408
1409    printf("Font Path:\n");
1410    if (npaths) {
1411	printf("  %s", *font_path++);
1412	for (--npaths; npaths; npaths--)
1413	    printf(",%s", *font_path++);
1414	printf("\n");
1415    } else {
1416	printf("  (empty)\n");
1417    }
1418
1419#ifdef MITMISC
1420    {
1421	int dummy;
1422
1423	if (XMITMiscQueryExtension(dpy, &dummy, &dummy)) {
1424	    if (XMITMiscGetBugMode(dpy))
1425		printf("Bug Mode: compatibility mode is enabled\n");
1426	    else
1427		printf("Bug Mode: compatibility mode is disabled\n");
1428	}
1429    }
1430#endif
1431#ifdef DPMSExtension
1432    {
1433
1434	int dummy;
1435	CARD16 standby, suspend, off;
1436	BOOL onoff;
1437	CARD16 state;
1438
1439	printf("DPMS (Display Power Management Signaling):\n");
1440	if (DPMSQueryExtension(dpy, &dummy, &dummy)) {
1441	    if (DPMSCapable(dpy)) {
1442		DPMSGetTimeouts(dpy, &standby, &suspend, &off);
1443		printf("  Standby: %d    Suspend: %d    Off: %d\n",
1444		       standby, suspend, off);
1445		DPMSInfo(dpy, &state, &onoff);
1446		if (onoff) {
1447		    printf("  DPMS is Enabled\n");
1448		    switch (state) {
1449		    case DPMSModeOn:
1450			printf("  Monitor is On\n");
1451			break;
1452		    case DPMSModeStandby:
1453			printf("  Monitor is in Standby\n");
1454			break;
1455		    case DPMSModeSuspend:
1456			printf("  Monitor is in Suspend\n");
1457			break;
1458		    case DPMSModeOff:
1459			printf("  Monitor is Off\n");
1460			break;
1461		    default:
1462			printf("  Unrecognized response from server\n");
1463		    }
1464		} else
1465		    printf("  DPMS is Disabled\n");
1466	    } else
1467		printf("  Display is not capable of DPMS\n");
1468	} else {
1469	    printf("  Server does not have the DPMS Extension\n");
1470	}
1471    }
1472#endif
1473#ifdef FONTCACHE
1474    {
1475	int dummy;
1476
1477	printf("Font cache:\n");
1478	if (FontCacheQueryExtension(dpy, &dummy, &dummy)) {
1479            FontCacheSettings cs;
1480
1481	    if (FontCacheGetCacheSettings(dpy, &cs)) {
1482		int himark = cs.himark / 1024;
1483		int lowmark = cs.lowmark / 1024;
1484		int balance = cs.balance;
1485
1486		printf("  hi-mark (KB): %d  low-mark (KB): %d  balance (%%): %d\n",
1487		       himark, lowmark, balance);
1488	    }
1489	} else {
1490	    printf("  Server does not have the FontCache Extension\n");
1491	}
1492    }
1493#endif
1494#ifdef XF86MISC
1495    {
1496	int dummy;
1497	int maj, min;
1498	XF86MiscFilePaths paths;
1499
1500	if (XF86MiscQueryExtension(dpy, &dummy, &dummy) &&
1501	    XF86MiscQueryVersion(dpy, &maj, &min) &&
1502	    ((maj > 0) || (maj == 0 && min >= 7)) &&
1503	    XF86MiscGetFilePaths(dpy, &paths)) {
1504	    printf("File paths:\n");
1505	    printf("  Config file:  %s\n", paths.configfile);
1506	    printf("  Modules path: %s\n", paths.modulepath);
1507	    printf("  Log file:     %s\n", paths.logfile);
1508	}
1509    }
1510#endif
1511
1512    return;
1513}
1514
1515#ifdef FONTCACHE
1516/*
1517 *  query_cache_status()
1518 *
1519 *  This is the information-getting function for telling the user what the
1520 *  current settings and statistics are.
1521 */
1522static void
1523query_cache_status(Display *dpy)
1524{
1525    int dummy;
1526
1527    if (FontCacheQueryExtension(dpy, &dummy, &dummy)) {
1528	FontCacheSettings cs;
1529	FontCacheStatistics cstats;
1530
1531	if (FontCacheGetCacheSettings(dpy, &cs)) {
1532	    int himark = cs.himark / 1024;
1533	    int lowmark = cs.lowmark / 1024;
1534	    int balance = cs.balance;
1535
1536	    printf("font cache settings:\n");
1537	    printf("  hi-mark (KB): %d  low-mark (KB): %d  balance (%%): %d\n",
1538		   himark, lowmark, balance);
1539	}
1540	if (FontCacheGetCacheStatistics(dpy, &cstats)) {
1541	    printf("font cache statistics:\n");
1542	    printf("   cache purged: %ld\n", cstats.purge_runs);
1543	    printf("   cache status: %ld\n", cstats.purge_stat);
1544	    printf("  cache balance: %ld\n", cstats.balance);
1545	    printf("font cache entry statistics:\n");
1546	    printf("      hits: %ld\n", cstats.f.hits);
1547	    printf("  misshits: %ld\n", cstats.f.misshits);
1548	    printf("    purged: %ld\n", cstats.f.purged);
1549	    printf("     usage: %ld\n", cstats.f.usage);
1550	    printf("large bitmap cache entry statistics:\n");
1551	    printf("      hits: %ld\n", cstats.v.hits);
1552	    printf("  misshits: %ld\n", cstats.v.misshits);
1553	    printf("    purged: %ld\n", cstats.v.purged);
1554	    printf("     usage: %ld\n", cstats.v.usage);
1555	}
1556    } else {
1557	printf("Server does not have the FontCache Extension\n");
1558    }
1559}
1560#endif
1561
1562/*  This is the usage function */
1563
1564static void
1565usage(const char *fmt, ...)
1566{
1567    va_list ap;
1568
1569    if (fmt) {
1570	fprintf(stderr, "%s:  ", progName);
1571	va_start(ap, fmt);
1572	vfprintf(stderr, fmt, ap);
1573	va_end(ap);
1574	fprintf(stderr, "\n\n");
1575
1576    }
1577
1578    fprintf(stderr, "usage:  %s [-display host:dpy] option ...\n%s", progName,
1579            "    To turn bell off:\n"
1580            "\t-b                b off               b 0\n"
1581            "    To set bell volume, pitch and duration:\n"
1582            "\t b [vol [pitch [dur]]]          b on\n"
1583#ifdef MITMISC
1584            "    To disable bug compatibility mode:\n"
1585            "\t-bc\n"
1586            "    To enable bug compatibility mode:\n"
1587            "\tbc\n"
1588#endif
1589            "    To turn keyclick off:\n"
1590            "\t-c                c off               c 0\n"
1591            "    To set keyclick volume:\n"
1592            "\t c [0-100]        c on\n"
1593#ifdef DPMSExtension
1594            "    To control Display Power Management Signaling (DPMS) features:\n"
1595            "\t-dpms      DPMS features off\n"
1596            "\t+dpms      DPMS features on\n"
1597            "\t dpms [standby [suspend [off]]]     \n"
1598            "\t      force standby \n"
1599            "\t      force suspend \n"
1600            "\t      force off \n"
1601            "\t      force on \n"
1602            "\t      (also implicitly enables DPMS features) \n"
1603            "\t      a timeout value of zero disables the mode \n"
1604#endif
1605#ifdef FONTCACHE
1606            "    To control font cache:\n"
1607            "\t fc [hi-mark [low-mark [balance]]]\n"
1608            "\t    both mark values specified in KB\n"
1609            "\t    balance value specified in percent (10 - 90)\n"
1610            "    Show font cache statistics:\n"
1611            "\t fc s\n"
1612#endif
1613            "    To set the font path:\n"
1614            "\t fp= path[,path...]\n"
1615            "    To restore the default font path:\n"
1616            "\t fp default\n"
1617            "    To have the server reread font databases:\n"
1618            "\t fp rehash\n"
1619            "    To remove elements from font path:\n"
1620            "\t-fp path[,path...]  fp- path[,path...]\n"
1621            "    To prepend or append elements to font path:\n"
1622            "\t+fp path[,path...]  fp+ path[,path...]\n"
1623            "    To set LED states off or on:\n"
1624            "\t-led [1-32]         led off\n"
1625            "\t led [1-32]         led on\n"
1626#ifdef XKB
1627            "\t-led named 'name'   led off\n"
1628            "\t led named 'name'   led on\n"
1629#endif
1630            "    To set mouse acceleration and threshold:\n"
1631            "\t m [acc_mult[/acc_div] [thr]]    m default\n"
1632            "    To set pixel colors:\n"
1633            "\t p pixel_value color_name\n"
1634            "    To turn auto-repeat off or on:\n"
1635            "\t-r [keycode]        r off\n"
1636            "\t r [keycode]        r on\n"
1637#if defined(XF86MISC) || defined(XKB)
1638            "\t r rate [delay [rate]]\n"
1639#endif
1640            "    For screen-saver control:\n"
1641            "\t s [timeout [cycle]]  s default    s on\n"
1642            "\t s blank              s noblank    s off\n"
1643            "\t s expose             s noexpose\n"
1644            "\t s activate           s reset\n"
1645            "    For status information:  q\n"
1646            "    To print version: -version\n"
1647        );
1648    exit(EXIT_SUCCESS);
1649}
1650
1651static void
1652error(const char *message)
1653{
1654    fprintf(stderr, "%s: %s\n", progName, message);
1655    exit(EXIT_FAILURE);
1656}
1657
1658static int
1659local_xerror(Display *dpy, XErrorEvent *rep)
1660{
1661    if (rep->request_code == X_SetFontPath && rep->error_code == BadValue) {
1662	fprintf(stderr,
1663		"%s:  bad font path element (#%ld), possible causes are:\n",
1664		progName, rep->resourceid);
1665	fprintf(stderr,
1666                "    Directory does not exist or has wrong permissions\n"
1667                "    Directory missing fonts.dir\n"
1668                "    Incorrect font server address or syntax\n");
1669    } else if (rep->request_code == X_StoreColors) {
1670	switch (rep->error_code) {
1671	  case BadAccess:
1672	    fprintf(stderr,
1673		    "%s:  pixel not allocated read/write\n", progName);
1674	    break;
1675	  case BadValue:
1676	    fprintf(stderr,
1677		    "%s:  cannot store in pixel 0x%lx, invalid pixel number\n",
1678		    progName, rep->resourceid);
1679	    break;
1680	  default:
1681	    XmuPrintDefaultErrorMessage(dpy, rep, stderr);
1682	}
1683    } else
1684	XmuPrintDefaultErrorMessage(dpy, rep, stderr);
1685
1686    error_status = -1;
1687
1688    return (0);
1689}
1690