xvidtune.c revision cacd992d
1/* $XFree86: xc/programs/xvidtune/xvidtune.c,v 3.35tsi Exp $ */
2
3/*
4
5Copyright (c) 1995  Kaleb S. KEITHLEY
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21IN NO EVENT SHALL Kaleb S. KEITHLEY BE LIABLE FOR ANY CLAIM, DAMAGES
22OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24OTHER DEALINGS IN THE SOFTWARE.
25
26Except as contained in this notice, the name of Kaleb S. KEITHLEY
27shall not be used in advertising or otherwise to promote the sale, use
28or other dealings in this Software without prior written authorization
29from Kaleb S. KEITHLEY.
30
31*/
32
33#include <X11/Intrinsic.h>
34#include <X11/Shell.h>
35#include <X11/StringDefs.h>
36#include <X11/Xatom.h>
37#include <X11/Xaw/Form.h>
38#include <X11/Xaw/Scrollbar.h>
39#include <X11/Xaw/Label.h>
40#include <X11/Xaw/Command.h>
41#include <X11/Xaw/AsciiText.h>
42#include <X11/Xaw/Box.h>
43#include <X11/Xaw/Toggle.h>
44#include <X11/Xmu/StdSel.h>
45#include <X11/Xmd.h>
46#include <X11/extensions/xf86vmode.h>
47#include <ctype.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <signal.h>
51
52int MajorVersion, MinorVersion;
53int EventBase, ErrorBase;
54int dot_clock, mode_flags;
55unsigned long    TestTimeout=5000;  /* Default test timeout */
56XtSignalId sigId;
57
58/* Minimum extension version required */
59#define MINMAJOR 0
60#define MINMINOR 5
61
62/* Mode flags -- ignore flags not in V_FLAG_MASK */
63#define V_FLAG_MASK	0x1FF;
64#define V_PHSYNC	0x001
65#define V_NHSYNC	0x002
66#define V_PVSYNC	0x004
67#define V_NVSYNC	0x008
68#define V_INTERLACE	0x010
69#define V_DBLSCAN	0x020
70#define V_CSYNC		0x040
71#define V_PCSYNC	0x080
72#define V_NCSYNC	0x100
73
74typedef enum { HDisplay, HSyncStart, HSyncEnd, HTotal,
75	VDisplay, VSyncStart, VSyncEnd, VTotal, Flags,
76	InvertVclk, BlankDelay1, BlankDelay2, EarlySc,
77	PixelClock, HSyncRate, VSyncRate, fields_num } fields;
78
79typedef struct {
80    fields	me;
81    fields	use;
82    int		val;
83    int		lastpercent;
84    int		range;
85    Widget	textwidget;
86    Widget	scrollwidget;
87} ScrollData;
88
89static struct _AppResources {
90    ScrollData	field[fields_num];
91    Bool	ad_installed;
92    int		orig[fields_num];
93    int		old[fields_num];
94} AppRes = {
95    {
96	{ HDisplay, },
97	{ HSyncStart, HDisplay, },
98	{ HSyncEnd, HDisplay, },
99	{ HTotal, HDisplay, },
100	{ VDisplay, },
101	{ VSyncStart, VDisplay, },
102	{ VSyncEnd, VDisplay, },
103	{ VTotal, VDisplay, },
104	{ Flags, },
105	{ InvertVclk, },
106	{ BlankDelay1, },
107	{ BlankDelay2, },
108	{ EarlySc, },
109	{ PixelClock, },
110	{ HSyncRate, },
111	{ VSyncRate, },
112    },
113};
114
115static XtResource Resources[] = {
116    { "adInstalled", "AdInstalled", XtRBool, sizeof(Bool),
117	XtOffsetOf(struct _AppResources, ad_installed),
118	XtRImmediate, (XtPointer)FALSE },
119    { "hSyncStartRange", "SyncStartRange", XtRInt, sizeof(int),
120	XtOffsetOf(struct _AppResources, field[HSyncStart].range),
121	XtRImmediate, (XtPointer)200 },
122    { "hSyncEndRange", "SyncEndRange", XtRInt, sizeof(int),
123	XtOffsetOf(struct _AppResources, field[HSyncEnd].range),
124	XtRImmediate, (XtPointer)400 },
125    { "hTotalRange", "TotalRange", XtRInt, sizeof(int),
126	XtOffsetOf(struct _AppResources, field[HTotal].range),
127	XtRImmediate, (XtPointer)400 },
128    { "vSyncStartRange", "SyncStartRange", XtRInt, sizeof(int),
129	XtOffsetOf(struct _AppResources, field[VSyncStart].range),
130	XtRImmediate, (XtPointer)20 },
131    { "vSyncEndRange", "SyncEndRange", XtRInt, sizeof(int),
132	XtOffsetOf(struct _AppResources, field[VSyncEnd].range),
133	XtRImmediate, (XtPointer)40 },
134    { "vTotalRange", "TotalRange", XtRInt, sizeof(int),
135	XtOffsetOf(struct _AppResources, field[VTotal].range),
136	XtRImmediate, (XtPointer)80 },
137};
138
139static XtTranslations trans;
140
141static Atom wm_delete_window;
142static Widget invalid_mode_popup;
143static Widget testing_popup;
144static Widget Top;
145static Widget auto_apply_toggle;
146
147static Bool S3Specials = False;
148static char modebuf[160];
149
150static void UpdateSyncRates(Bool dolabels);
151
152static void
153CleanUp(Display *dpy)
154{
155    /* Make sure mode switching is not locked out at exit */
156    XF86VidModeLockModeSwitch(dpy, DefaultScreen(dpy), FALSE);
157    XFlush(dpy);
158}
159
160static void
161CatchSig(int signal)
162{
163    XtNoticeSignal(sigId);
164}
165
166static void
167CatchXtSig(XtPointer closure, XtSignalId *id)
168{
169    CleanUp(XtDisplay(Top));
170    exit(3);
171}
172
173static Bool
174GetModeLine (Display* dpy, int scrn)
175{
176    XF86VidModeModeLine mode_line;
177    fields i;
178
179    if (!XF86VidModeGetModeLine (dpy, scrn, &dot_clock, &mode_line))
180	return FALSE;
181
182    AppRes.field[HDisplay].val = mode_line.hdisplay;
183    AppRes.field[HSyncStart].val = mode_line.hsyncstart;
184    AppRes.field[HSyncEnd].val = mode_line.hsyncend;
185    AppRes.field[HTotal].val = mode_line.htotal;
186    AppRes.field[VDisplay].val = mode_line.vdisplay;
187    AppRes.field[VSyncStart].val = mode_line.vsyncstart;
188    AppRes.field[VSyncEnd].val = mode_line.vsyncend;
189    AppRes.field[VTotal].val = mode_line.vtotal;
190    mode_flags = mode_line.flags;
191    AppRes.field[Flags].val = mode_flags & V_FLAG_MASK;
192    AppRes.field[PixelClock].val = dot_clock;
193    UpdateSyncRates(FALSE);
194    if (mode_line.privsize && mode_line.private) {
195	S3Specials = True;
196	AppRes.field[InvertVclk].val = mode_line.private[1];
197	AppRes.field[BlankDelay1].val = mode_line.private[2] & 7;
198	AppRes.field[BlankDelay2].val = (mode_line.private[2] >> 4) & 7;
199	AppRes.field[EarlySc].val = mode_line.private[3];
200    }
201
202    for (i = HDisplay; i < fields_num; i++)
203	AppRes.orig[i] = AppRes.field[i].val;
204    return TRUE;
205}
206
207static Bool
208GetMonitor (Display* dpy, int scrn)
209{
210    XF86VidModeMonitor monitor;
211    int i;
212
213    if (!XF86VidModeGetMonitor (dpy, scrn, &monitor))
214	return FALSE;
215
216    printf("Vendor: %s, Model: %s\n", monitor.vendor, monitor.model);
217    printf("Num hsync: %d, Num vsync: %d\n", monitor.nhsync, monitor.nvsync);
218    for (i = 0; i < monitor.nhsync; i++) {
219	printf("hsync range %d: %6.2f - %6.2f\n", i, monitor.hsync[i].lo,
220	       monitor.hsync[i].hi);
221    }
222    for (i = 0; i < monitor.nvsync; i++) {
223	printf("vsync range %d: %6.2f - %6.2f\n", i, monitor.vsync[i].lo,
224	       monitor.vsync[i].hi);
225    }
226    return TRUE;
227}
228
229static Bool
230ModeSettable(void)
231{
232    if (AppRes.field[HTotal].val == 0 || AppRes.field[VTotal].val == 0)
233	return FALSE;
234    return TRUE;
235}
236
237static int hitError = 0;
238static int (*xtErrorfunc)(Display *, XErrorEvent *);
239
240static int
241vidmodeError(Display *dis, XErrorEvent *err)
242{
243  if ((err->error_code >= ErrorBase &&
244      err->error_code < ErrorBase + XF86VidModeNumberErrors) ||
245      err->error_code == BadValue) {
246     hitError=1;
247  } else {
248     CleanUp(dis);
249     if (xtErrorfunc)
250	(*xtErrorfunc)(dis, err);
251  }
252  return 0; /* ignored */
253}
254
255static void
256SetScrollbars (void)
257{
258    fields i;
259
260    for (i = HDisplay; i <= Flags; i++) {
261
262	ScrollData* sdp = &AppRes.field[i];
263
264	if (sdp->scrollwidget != (Widget) NULL) {
265	    int base;
266	    float percent;
267
268	    base = AppRes.field[sdp->use].val;
269	    percent = ((float)(sdp->val - base)) / ((float)sdp->range);
270	    XawScrollbarSetThumb (sdp->scrollwidget, percent, 0.0);
271	}
272    }
273}
274
275static void
276QuitCB (Widget w, XtPointer client, XtPointer call)
277{
278    CleanUp(XtDisplay(w));
279#if XtSpecificationRelease < 6
280    exit (0);
281#else
282    XtAppSetExitFlag (XtWidgetToApplicationContext (w));
283#endif
284}
285
286static void
287popdownInvalid(Widget w, XtPointer client, XtPointer call)
288{
289   XtPopdown((Widget)client);
290}
291
292static void
293ApplyCB (Widget w, XtPointer client, XtPointer call)
294{
295    XF86VidModeModeLine mode_line;
296    INT32 S3private[4];
297    unsigned int i;
298    char* string;
299    Boolean state;
300
301    mode_line.hdisplay = AppRes.field[HDisplay].val;
302    mode_line.hsyncstart = AppRes.field[HSyncStart].val;
303    mode_line.hsyncend = AppRes.field[HSyncEnd].val;
304    mode_line.htotal = AppRes.field[HTotal].val;
305    mode_line.vdisplay = AppRes.field[VDisplay].val;
306    mode_line.vsyncstart = AppRes.field[VSyncStart].val;
307    mode_line.vsyncend = AppRes.field[VSyncEnd].val;
308    mode_line.vtotal = AppRes.field[VTotal].val;
309    /* Don't read flags from widget */
310#if 0
311    XtVaGetValues (AppRes.field[Flags].textwidget,
312		XtNstring, &string, NULL);
313    (void) sscanf (string, "%x", &i);
314#endif
315    mode_line.flags = mode_flags;
316    if (S3Specials) {
317	mode_line.privsize = 4;
318	mode_line.private = S3private;
319	mode_line.private[0] = (1 << 1) | (1 << 2) | (1 << 3);
320	XtVaGetValues(AppRes.field[InvertVclk].textwidget,
321			XtNstate, &state, NULL);
322	AppRes.field[InvertVclk].val = state ? 1 : 0;
323	mode_line.private[1] = AppRes.field[InvertVclk].val;
324	XtVaGetValues (AppRes.field[BlankDelay1].textwidget,
325			XtNstring, &string, NULL);
326	(void) sscanf (string, "%x", &i);
327	AppRes.field[BlankDelay1].val = i;
328	mode_line.private[2] = AppRes.field[BlankDelay1].val;
329	XtVaGetValues (AppRes.field[BlankDelay2].textwidget,
330			XtNstring, &string, NULL);
331	(void) sscanf (string, "%x", &i);
332	AppRes.field[BlankDelay2].val = i;
333	mode_line.private[2] |= AppRes.field[BlankDelay2].val << 4;
334	XtVaGetValues(AppRes.field[EarlySc].textwidget,
335			XtNstate, &state, NULL);
336	AppRes.field[EarlySc].val = state ? 1 : 0;
337	mode_line.private[3] = AppRes.field[EarlySc].val;
338    } else
339	mode_line.privsize = 0;
340
341   hitError = 0;
342
343   XF86VidModeModModeLine (XtDisplay (w), DefaultScreen (XtDisplay (w)),
344		&mode_line);
345   XSync(XtDisplay (w), False); /* process errors  */
346   if (hitError) {
347       XBell(XtDisplay (w), 80);
348       XtPopup(invalid_mode_popup, XtGrabExclusive /*XtGrabNone*/);
349   }
350}
351
352
353static void
354SetLabel(fields i)
355{
356   ScrollData* sdp = &AppRes.field[i];
357
358   if (sdp->textwidget != (Widget) NULL) {
359      char buf[10];
360      Boolean state;
361
362      /*
363       * Disable AutoApply so that the apply doesn't happen more than
364       * once as a consequence of callbacks being called because of the
365       * XtSetValues calls
366       */
367
368      XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
369      if (state)
370	 XtVaSetValues(auto_apply_toggle, XtNstate, 0, NULL);
371
372      if (i == Flags)
373	 (void) sprintf (buf, "%04x", sdp->val);
374      else if (i >= PixelClock && i <= VSyncRate)
375	 (void) sprintf (buf, "%6.2f", (float)sdp->val / 1000.0);
376      else if (i == BlankDelay1 || i == BlankDelay2) {
377	 (void) sprintf (buf, "%d", sdp->val);
378      } else
379	 (void) sprintf (buf, "%5d", sdp->val);
380
381      sdp->lastpercent = -1;
382      if (i == Flags) {
383	 XawTextBlock text;
384
385	 text.firstPos = 0;
386	 text.length = 4;
387	 text.ptr = buf;
388	 text.format = XawFmt8Bit;
389	 XawTextReplace (sdp->textwidget, 0, 4, &text);
390      } else if (i == BlankDelay1 || i == BlankDelay2) {
391	 XawTextBlock text;
392
393	 text.firstPos = 0;
394	 text.length = 1;
395	 text.ptr = buf;
396	 XawTextReplace (sdp->textwidget, 0, 1, &text);
397      } else if (i == InvertVclk || i == EarlySc) {
398	XtVaSetValues (sdp->textwidget, XtNstate, sdp->val, NULL);
399      } else
400	XtVaSetValues (sdp->textwidget, XtNlabel, buf, NULL);
401
402      if (state)
403	 XtVaSetValues(auto_apply_toggle, XtNstate, 1, NULL);
404   }
405
406}
407
408static void
409UpdateSyncRates(Bool dolabels)
410{
411    if (!ModeSettable())
412	return;
413
414    AppRes.field[HSyncRate].val = AppRes.field[PixelClock].val * 1000 /
415				  AppRes.field[HTotal].val;
416    AppRes.field[VSyncRate].val = AppRes.field[HSyncRate].val * 1000 /
417				  AppRes.field[VTotal].val;
418    if (mode_flags & V_INTERLACE)
419	AppRes.field[VSyncRate].val *= 2;
420    else if (mode_flags & V_DBLSCAN)
421	AppRes.field[VSyncRate].val /= 2;
422    if (dolabels) {
423	SetLabel(HSyncRate);
424	SetLabel(VSyncRate);
425    }
426}
427
428static void
429RestoreCB (Widget w, XtPointer client, XtPointer call)
430{
431    fields i;
432    Boolean state;
433
434    for (i = HDisplay; i < fields_num; i++) {
435	AppRes.field[i].val = AppRes.orig[i];
436	SetLabel(i);
437    }
438    SetScrollbars ();
439    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
440    if (state)
441	 ApplyCB (w, client, call);
442}
443
444
445static void
446ApplyIfAutoCB (Widget w, XtPointer client, XtPointer call)
447{
448   Boolean state;
449
450   XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
451   if (state)
452       ApplyCB (w, client, call);
453}
454
455
456static void
457FetchCB (Widget w, XtPointer client, XtPointer call)
458{
459    fields i;
460    (void) GetModeLine(XtDisplay (w), DefaultScreen (XtDisplay (w)));
461    SetScrollbars ();
462    for (i = HDisplay; i < fields_num; i++) {
463        SetLabel(i);
464    }
465}
466
467static XtIntervalId TOid;
468
469static void
470TestTO (XtPointer client, XtIntervalId* id)
471{
472    fields i;
473    for (i = HDisplay; i < fields_num; i++)
474	AppRes.field[i].val = AppRes.orig[i];
475
476    ApplyCB ((Widget) client, NULL, NULL);
477
478    for (i = HDisplay; i < fields_num; i++)
479	AppRes.field[i].val = AppRes.old[i];
480    SetScrollbars ();
481
482    XtPopdown(testing_popup);
483}
484
485static void
486TestTOCB (Widget w, XtPointer client, XtPointer call)
487{
488  XtRemoveTimeOut(TOid);
489  TestTO(w, (XtIntervalId *) NULL);
490}
491
492static void
493TestCB (Widget w, XtPointer client, XtPointer call)
494{
495    fields i;
496    for (i = HDisplay; i < fields_num; i++)
497	AppRes.old[i] = AppRes.field[i].val;
498
499    XtPopup(testing_popup, XtGrabExclusive /*XtGrabNone*/);
500    XSync(XtDisplay(w), False);
501    TOid = XtAppAddTimeOut (XtWidgetToApplicationContext (w),
502		TestTimeout, TestTO, (XtPointer) w);
503
504    ApplyCB (w, client, call);
505}
506
507static Boolean
508ConvertSelection(
509    Widget w,
510    Atom *selection, Atom *target, Atom *type,
511    XtPointer *value,
512    unsigned long *length,
513    int *format)
514{
515    if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
516                                    (XPointer *) value, length, format))
517        return True;
518
519    if (*target == XA_STRING) {
520        *type = XA_STRING;
521        *value = modebuf;
522        *length = strlen(*value);
523        *format = 8;
524        return True;
525    }
526    return False;
527}
528
529static void
530ShowCB(Widget w, XtPointer client, XtPointer call)
531{
532    Time time;
533    char tmpbuf[16];
534
535    sprintf(tmpbuf, "\"%dx%d\"",
536	   AppRes.field[HDisplay].val, AppRes.field[VDisplay].val);
537    sprintf(modebuf, "%-11s   %6.2f   %4d %4d %4d %4d   %4d %4d %4d %4d",
538	   tmpbuf, (float)dot_clock/1000.0,
539	   AppRes.field[HDisplay].val,
540	   AppRes.field[HSyncStart].val,
541	   AppRes.field[HSyncEnd].val,
542	   AppRes.field[HTotal].val,
543	   AppRes.field[VDisplay].val,
544	   AppRes.field[VSyncStart].val,
545	   AppRes.field[VSyncEnd].val,
546	   AppRes.field[VTotal].val);
547    /* Print out the flags (if any) */
548    if (mode_flags & V_PHSYNC)    strcat(modebuf, " +hsync");
549    if (mode_flags & V_NHSYNC)    strcat(modebuf, " -hsync");
550    if (mode_flags & V_PVSYNC)    strcat(modebuf, " +vsync");
551    if (mode_flags & V_NVSYNC)    strcat(modebuf, " -vsync");
552    if (mode_flags & V_INTERLACE) strcat(modebuf, " interlace");
553    if (mode_flags & V_CSYNC)     strcat(modebuf, " composite");
554    if (mode_flags & V_PCSYNC)    strcat(modebuf, " +csync");
555    if (mode_flags & V_NCSYNC)    strcat(modebuf, " -csync");
556    if (mode_flags & V_DBLSCAN)   strcat(modebuf, " doublescan");
557    printf("%s\n", modebuf);
558    time = XtLastTimestampProcessed(XtDisplay(w));
559    XtOwnSelection(w, XA_PRIMARY, time, ConvertSelection, NULL, NULL);
560    if (S3Specials) {
561	unsigned int i;
562	Boolean state;
563	char *string;
564
565	XtVaGetValues(AppRes.field[InvertVclk].textwidget,
566			XtNstate, &state, NULL);
567	AppRes.field[InvertVclk].val = state ? 1 : 0;
568	XtVaGetValues (AppRes.field[BlankDelay1].textwidget,
569			XtNstring, &string, NULL);
570	(void) sscanf (string, "%x", &i);
571	AppRes.field[BlankDelay1].val = i;
572	XtVaGetValues (AppRes.field[BlankDelay2].textwidget,
573			XtNstring, &string, NULL);
574	(void) sscanf (string, "%x", &i);
575	AppRes.field[BlankDelay2].val = i;
576	XtVaGetValues(AppRes.field[EarlySc].textwidget,
577			XtNstate, &state, NULL);
578	AppRes.field[EarlySc].val = state ? 1 : 0;
579	if (AppRes.field[InvertVclk].val != AppRes.orig[InvertVclk])
580	    printf("InvertVCLK\t\"%dx%d\" %d\n", AppRes.field[HDisplay].val,
581		AppRes.field[VDisplay].val, AppRes.field[InvertVclk].val);
582	if (AppRes.field[EarlySc].val != AppRes.orig[EarlySc])
583	    printf("EarlySC\t\t\"%dx%d\" %d\n", AppRes.field[HDisplay].val,
584		AppRes.field[VDisplay].val, AppRes.field[EarlySc].val);
585	if (AppRes.field[BlankDelay1].val != AppRes.orig[BlankDelay1]
586	    || AppRes.field[BlankDelay2].val != AppRes.orig[BlankDelay2])
587	    printf("BlankDelay\t\"%dx%d\" %d %d\n", AppRes.field[HDisplay].val,
588		AppRes.field[VDisplay].val, AppRes.field[BlankDelay1].val,
589		AppRes.field[BlankDelay2].val);
590    }
591    printf("\n");
592}
593
594static void
595AdjustCB(Widget w, XtPointer client, XtPointer call)
596{
597   int what = (long) client;
598   Boolean state;
599
600   switch (what) {
601    case HSyncStart:
602      if (AppRes.field[HSyncEnd].val + 4 < AppRes.field[HTotal].val) {
603	 AppRes.field[HSyncEnd].val += 4;
604	 AppRes.field[HSyncStart].val += 4;
605	 SetLabel(HSyncStart);
606	 SetLabel(HSyncEnd);
607      } else
608	XBell(XtDisplay(w), 80);
609      break;
610    case -HSyncStart:
611      if (AppRes.field[HSyncStart].val - 4 > AppRes.field[HDisplay].val) {
612	 AppRes.field[HSyncEnd].val -= 4;
613	 AppRes.field[HSyncStart].val -= 4;
614	 SetLabel(HSyncStart);
615	 SetLabel(HSyncEnd);
616      } else
617	XBell(XtDisplay(w), 80);
618      break;
619    case HTotal:
620      AppRes.field[HTotal].val += 4;
621      SetLabel(HTotal);
622      UpdateSyncRates(TRUE);
623      break;
624    case -HTotal:
625      if (AppRes.field[HTotal].val - 4 >  AppRes.field[HSyncEnd].val) {
626	AppRes.field[HTotal].val -= 4;
627	SetLabel(HTotal);
628	UpdateSyncRates(TRUE);
629      } else
630	XBell(XtDisplay(w), 80);
631      break;
632    case VSyncStart:
633      if (AppRes.field[VSyncEnd].val + 4 < AppRes.field[VTotal].val) {
634	 AppRes.field[VSyncEnd].val += 4;
635	 AppRes.field[VSyncStart].val += 4;
636	 SetLabel(VSyncStart);
637	 SetLabel(VSyncEnd);
638      } else
639	XBell(XtDisplay(w), 80);
640      break;
641    case -VSyncStart:
642      if (AppRes.field[VSyncStart].val - 4 > AppRes.field[VDisplay].val) {
643	 AppRes.field[VSyncEnd].val -= 4;
644	 AppRes.field[VSyncStart].val -= 4;
645	 SetLabel(VSyncStart);
646	 SetLabel(VSyncEnd);
647      } else
648	XBell(XtDisplay(w), 80);
649      break;
650    case VTotal:
651      AppRes.field[VTotal].val += 4;
652      SetLabel(VTotal);
653      UpdateSyncRates(TRUE);
654      break;
655    case -VTotal:
656      if (AppRes.field[VTotal].val - 4 >  AppRes.field[VSyncEnd].val) {
657	AppRes.field[VTotal].val -= 4;
658	SetLabel(VTotal);
659	UpdateSyncRates(TRUE);
660      } else
661	XBell(XtDisplay(w), 80);
662      break;
663   }
664   SetScrollbars ();
665   XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
666   if (state)
667       ApplyCB (w, client, call);
668}
669
670
671#if 0
672static void
673EditCB (Widget w, XtPointer client, XtPointer call)
674{
675    int base, current, i, len;
676    int lower, upper;
677    float percent;
678    ScrollData* sdp = (ScrollData*) client;
679
680    len = strlen (sdp->string);
681
682    for (i = 0; i < len; i++) {
683	if (!(isdigit (sdp->string[i]) || isspace (sdp->string[i]))) {
684	    XBell (XtDisplay(XtParent(w)), 100);
685	    return;
686	}
687    }
688    switch (sdp->me) {
689    case HSyncStart:
690	lower = atoi (AppRes.field[HDisplay].string);
691	upper = atoi (AppRes.field[HSyncEnd].string);
692	break;
693
694    case HSyncEnd:
695	lower = atoi (AppRes.field[HSyncStart].string);
696	upper = atoi (AppRes.field[HTotal].string);
697	break;
698
699    case HTotal:
700	lower = atoi (AppRes.field[HSyncEnd].string);
701	upper = atoi (AppRes.field[HDisplay].string) +
702		AppRes.field[HTotal].range;
703	break;
704
705    case VSyncStart:
706	lower = atoi (AppRes.field[VDisplay].string);
707	upper = atoi (AppRes.field[VSyncEnd].string);
708	break;
709
710    case VSyncEnd:
711	lower = atoi (AppRes.field[VSyncStart].string);
712	upper = atoi (AppRes.field[VTotal].string);
713	break;
714
715    case VTotal:
716	lower = atoi (AppRes.field[VSyncEnd].string);
717	upper = atoi (AppRes.field[VDisplay].string) +
718		AppRes.field[VTotal].range;
719	break;
720    }
721    current = atoi (sdp->string);
722    if (current < lower || current > upper) {
723	XawTextBlock text;
724	char tmp[6];
725
726	if (current < lower) {
727	    (void) sprintf (tmp, "%5d", lower);
728	    current = lower;
729	} else {
730	    (void) sprintf (tmp, "%5d", upper);
731	    current = upper;
732	}
733	text.firstPos = 0;
734	text.length = strlen (tmp);
735	text.ptr = tmp;
736	text.format = XawFmt8Bit;
737	XawTextReplace (sdp->textwidget, 0, text.length, &text);
738    }
739    base = atoi (AppRes.field[sdp->use].string);
740    percent = ((float)(current - base)) / ((float)sdp->range);
741    XawScrollbarSetThumb (sdp->scrollwidget, percent, 0.0);
742}
743#endif
744
745static void
746FlagsEditCB (Widget w, XtPointer client, XtPointer call)
747{
748    int i, len;
749    char* string;
750    fields findex = (fields) (unsigned long) client;
751    ScrollData* sdp = &AppRes.field[findex];
752
753    XtVaGetValues (w, XtNstring, &string, NULL);
754    len = strlen (string);
755    if (len > 4) {
756	char buf[5];
757
758	XBell (XtDisplay(XtParent(w)), 100);
759	(void) strncpy (buf, string, 4);
760	buf[4] = '\0';
761	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
762	XawTextSetInsertionPoint (sdp->textwidget, 4);
763    }
764
765    for (i = 0; i < len; i++) {
766	if (!isxdigit (string[i])) {
767	    XBell (XtDisplay(XtParent(w)), 100);
768	}
769    }
770}
771
772static void
773BlankEditCB (Widget w, XtPointer client, XtPointer call)
774{
775    int len;
776    char* string;
777    fields findex = (fields) (unsigned long) client;
778    ScrollData* sdp = &AppRes.field[findex];
779    char buf[2], old;
780    Boolean state;
781    Boolean noAuto = False;
782
783    XtVaGetValues (w, XtNstring, &string, NULL);
784    len = strlen (string);
785    if (len == 0) {
786	XBell (XtDisplay(XtParent(w)), 100);
787	strcpy(buf, "0");
788	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
789	XawTextSetInsertionPoint (sdp->textwidget, 1);
790        return;
791    }
792    if (len > 1) {
793	if (XawTextGetInsertionPoint(sdp->textwidget) < 1) {
794	    buf[0] = string[0];
795	    old = string[1];
796	} else {
797	    buf[0] = string[1];
798	    old = string[0];
799	}
800	if (buf[0] == '+' && old < '7')
801	    buf[0] = old + 1;
802	else if (buf[0] == '-' && old > '0')
803	    buf[0] = old - 1;
804	if (!isdigit(buf[0]) || buf[0] > '7') {
805	    XBell (XtDisplay(XtParent(w)), 100);
806	    buf[0] = old;
807	    if (!isdigit(buf[0]) || buf[0] > '7')
808		buf[0] = '0';
809	    noAuto = True;
810	}
811	buf[1] = '\0';
812	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
813	XawTextSetInsertionPoint (sdp->textwidget, 1);
814    }
815    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
816    if (state && !noAuto)
817	ApplyCB (sdp->textwidget, client, call);
818}
819
820static void
821ChangeBlankCB (Widget w, XtPointer client, XtPointer call)
822{
823    char* string;
824    char buf[2];
825    fields findex;
826    ScrollData* sdp;
827    Boolean state;
828    int what = (long) client;
829
830
831    if (what < 0)
832	findex = (fields)-what;
833    else
834	findex = (fields)what;
835    sdp = &AppRes.field[findex];
836
837    XtVaGetValues (sdp->textwidget, XtNstring, &string, NULL);
838    if (what > 0)
839	string[0]++;
840    else
841	string[0]--;
842
843    if (string[0] < '0' || string[0] > '7') {
844	XBell (XtDisplay(XtParent(w)), 100);
845	return;
846    }
847
848    buf[0] = string[0];
849    buf[1] = '\0';
850    XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
851    XawTextSetInsertionPoint (sdp->textwidget, 1);
852
853    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
854    if (state)
855	ApplyCB (sdp->textwidget, client, call);
856}
857
858static int
859isValid(int val, int field)
860{
861   switch(field) {
862     case HSyncStart:
863	if (val+8 > AppRes.field[HSyncEnd].val)
864	   val = AppRes.field[HSyncEnd].val - 8;
865        break;
866     case HSyncEnd:
867        if (val-8 < AppRes.field[HSyncStart].val)
868	    val = AppRes.field[HSyncStart].val + 8;
869        if (val > AppRes.field[HTotal].val)
870	    val = AppRes.field[HTotal].val;
871        break;
872     case HTotal:
873	if (val < AppRes.field[HSyncEnd].val)
874	   val = AppRes.field[HSyncEnd].val;
875         break;
876     case VSyncStart:
877	if (val+8 > AppRes.field[VSyncEnd].val)
878	   val = AppRes.field[VSyncEnd].val - 8;
879        break;
880     case VSyncEnd:
881        if (val-8 < AppRes.field[VSyncStart].val)
882	    val = AppRes.field[VSyncStart].val + 8;
883        if (val > AppRes.field[VTotal].val)
884	    val = AppRes.field[VTotal].val;
885        break;
886     case VTotal:
887	if (val < AppRes.field[VSyncEnd].val)
888	   val = AppRes.field[VSyncEnd].val;
889        break;
890   }
891   return val;
892}
893
894static void
895ScrollCB (Widget w, XtPointer client, XtPointer call)
896{
897    float percent = *(float*) call;
898    int ipercent = percent * 100;
899    int fieldindex = (long) client;
900    ScrollData* sdp = &AppRes.field[fieldindex];
901
902
903
904    if (ipercent != sdp->lastpercent) {
905        int tmp_val;
906	char buf[6];
907
908	tmp_val = AppRes.field[sdp->use].val;
909	tmp_val += (int) (((float)sdp->range) * percent);
910
911        sdp->val = isValid(tmp_val, fieldindex);
912
913	sdp->lastpercent = ipercent;
914	(void) sprintf (buf, "%5d", sdp->val);
915	XtVaSetValues (sdp->textwidget, XtNlabel, buf, NULL);
916        if (sdp->val != tmp_val) {
917            int base;
918            float percent;
919
920            base = AppRes.field[sdp->use].val;
921            percent = ((float)(sdp->val - base)) / ((float)sdp->range);
922            /* This doesn't always work, why? */
923            XawScrollbarSetThumb (sdp->scrollwidget, percent, 0.0);
924	}
925	if (fieldindex == HTotal || fieldindex == VTotal)
926	    UpdateSyncRates(TRUE);
927    }
928}
929
930static void
931SwitchCB (Widget w, XtPointer client, XtPointer call)
932{
933    XF86VidModeLockModeSwitch(XtDisplay(w), DefaultScreen (XtDisplay (w)),
934			      FALSE);
935    XF86VidModeSwitchMode(XtDisplay(w), DefaultScreen (XtDisplay (w)),
936			  (int)(long) client);
937    XF86VidModeLockModeSwitch(XtDisplay(w), DefaultScreen (XtDisplay (w)),
938			      TRUE);
939    FetchCB(w, NULL, NULL);
940}
941
942static void
943AddCallback (
944    Widget w,
945    String  callback_name,
946    XtCallbackProc callback,
947    XtPointer client_data)
948{
949    Widget src;
950
951    XtVaGetValues (w, XtNtextSource, &src, NULL);
952    XtAddCallback (src, callback_name, callback, client_data);
953}
954
955static void
956CreateTyp (
957    Widget form,
958    fields findex,
959    String w1name,
960    String w2name,
961    String w3name)
962{
963    Widget wids[3];
964    char buf[10];
965
966    wids[0] = XtCreateWidget (w1name, labelWidgetClass, form, NULL, 0);
967    if (findex >= PixelClock && findex <= VSyncRate)
968	(void) sprintf(buf, "%6.2f", (float)AppRes.field[findex].val / 1000.0);
969    else
970	(void) sprintf (buf, "%5d", AppRes.field[findex].val);
971    wids[1] = XtVaCreateWidget (w2name, labelWidgetClass,
972		form, XtNlabel, buf, NULL);
973    if (w3name != NULL) {
974	wids[2] = XtCreateWidget (w3name, scrollbarWidgetClass, form, NULL, 0);
975	XtAddCallback (wids[2], XtNjumpProc, ScrollCB, (XtPointer) findex);
976	XtManageChildren (wids, 3);
977    } else {
978	wids[2] = (Widget) NULL;
979	XtManageChildren (wids, 2);
980    }
981    AppRes.field[findex].textwidget = wids[1];
982    AppRes.field[findex].scrollwidget = wids[2];
983}
984
985
986static void
987AckWarn (Widget w, XtPointer client, XtPointer call)
988{
989    XtPopdown((Widget) client);
990    XtDestroyWidget((Widget) client);
991}
992
993static void
994AckNoTune (Widget w, XtPointer client, XtPointer call)
995{
996    CleanUp(XtDisplay(w));
997#if XtSpecificationRelease < 6
998    exit (0);
999#else
1000    XtAppSetExitFlag (XtWidgetToApplicationContext (w));
1001#endif
1002}
1003
1004static void
1005displayWarning(Widget top)
1006{
1007    Widget w, popup, popupBox;
1008    int x, y;
1009
1010    x =  DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1011    y =  DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1012
1013    popup = XtVaCreatePopupShell("Warning",
1014			    transientShellWidgetClass, top,
1015			    XtNtitle, "WARNING",
1016			    XtNx, x,
1017			    XtNy, y,
1018			    NULL);
1019
1020    popupBox = XtVaCreateManagedWidget(
1021               "WarningBox",
1022               boxWidgetClass,
1023               popup,
1024               NULL);
1025
1026    w = XtVaCreateManagedWidget( "WarnLabel",
1027                                     labelWidgetClass,
1028				     popupBox,
1029                                     NULL);
1030
1031    w = XtVaCreateManagedWidget( "WarnOK",
1032                                     commandWidgetClass,
1033				     popupBox,
1034                                     NULL);
1035
1036    XtAddCallback (w, XtNcallback, AckWarn, (XtPointer)popup);
1037
1038    w = XtVaCreateManagedWidget( "WarnCancel",
1039                                     commandWidgetClass,
1040				     popupBox,
1041                                     NULL);
1042    XtAddCallback (w, XtNcallback, QuitCB, (XtPointer)NULL);
1043
1044    XtPopup(popup, XtGrabExclusive);
1045
1046}
1047
1048static void
1049displayNoTune(Widget top)
1050{
1051    Widget w, popup, popupBox;
1052
1053    popup = XtCreateWidget ("Notice", formWidgetClass, top, NULL, 0);
1054    popupBox = XtVaCreateManagedWidget(
1055               "WarningBox",
1056               boxWidgetClass,
1057               popup,
1058               NULL);
1059
1060    w = XtVaCreateManagedWidget( "NoTuneLabel",
1061                                     labelWidgetClass,
1062				     popupBox,
1063                                     NULL);
1064
1065    w = XtVaCreateManagedWidget( "NoTuneOK",
1066                                     commandWidgetClass,
1067				     popupBox,
1068                                     NULL);
1069
1070    XtAddCallback (w, XtNcallback, AckNoTune, (XtPointer)popup);
1071
1072    XtManageChild (popup);
1073}
1074
1075#if 0
1076static void
1077s3Special(Widget top)
1078{
1079    Widget w, popup, form, invert_vclk_toggle, wids[6];
1080    char buf1[5] = {'\0',};
1081    int x, y;
1082
1083    x =  DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1084    y =  DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1085
1086    popup = XtVaCreatePopupShell("S3Adjust",
1087			    transientShellWidgetClass, top,
1088			    XtNtitle, "S3Adjust",
1089			    XtNx, x,
1090			    XtNy, y,
1091			    NULL);
1092
1093    form = XtVaCreateManagedWidget(
1094               "S3Box",
1095               formWidgetClass,
1096               popup,
1097               NULL);
1098
1099    w = XtVaCreateManagedWidget( "S3Title",
1100                                     labelWidgetClass,
1101				     form,
1102                                     NULL);
1103
1104    invert_vclk_toggle = XtVaCreateManagedWidget( "InvertVclk-toggle",
1105                                     toggleWidgetClass,
1106				     form,
1107                                     NULL);
1108
1109    wids[0] = XtCreateWidget ("Blank1-label", labelWidgetClass,
1110		form, NULL, 0);
1111    wids[1] = XtVaCreateWidget ("Blank1-text", asciiTextWidgetClass,
1112		form, XtNstring, buf1, NULL);
1113    AddCallback (wids[1], XtNcallback, FlagsEditCB, (XtPointer) NULL);
1114
1115    XtManageChildren (wids, 2);
1116
1117    XtPopup(popup, XtGrabNone);
1118
1119}
1120#endif
1121
1122
1123
1124static void
1125CreateHierarchy(Widget top)
1126{
1127    char buf[5];
1128    Widget form, forms[14], s3form;
1129    Widget wids[10];
1130    Widget boxW, popdownW, w;
1131    int i;
1132    int x, y;
1133    static String form_names[] = {
1134	"HDisplay-form",
1135	"HSyncStart-form",
1136	"HSyncEnd-form",
1137	"HTotal-form",
1138	"VDisplay-form",
1139	"VSyncStart-form",
1140	"VSyncEnd-form",
1141	"VTotal-form",
1142	"Flags-form",
1143	"Buttons-form",
1144	"PixelClock-form",
1145	"HSyncRate-form",
1146	"VSyncRate-form",
1147	"Buttons2-form",
1148	};
1149
1150    form = XtCreateWidget ("form", formWidgetClass, top, NULL, 0);
1151    for (i = 0; i < 14; i++)
1152	forms[i] = XtCreateWidget (form_names[i], formWidgetClass,
1153		form, NULL, 0);
1154
1155    CreateTyp (forms[0], HDisplay, "HDisplay-label", "HDisplay-text", NULL);
1156    CreateTyp (forms[1], HSyncStart, "HSyncStart-label",
1157		"HSyncStart-text", "HSyncStart-scrollbar");
1158    CreateTyp (forms[2], HSyncEnd, "HSyncEnd-label", "HSyncEnd-text",
1159		"HSyncEnd-scrollbar");
1160    CreateTyp (forms[3], HTotal, "HTotal-label", "HTotal-text",
1161		"HTotal-scrollbar");
1162
1163    w = XtVaCreateManagedWidget(
1164                                     "Left-button",
1165                                     commandWidgetClass,
1166                                     forms[3],
1167                                     NULL);
1168    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)HSyncStart);
1169    w = XtVaCreateManagedWidget(
1170                                     "Right-button",
1171                                     commandWidgetClass,
1172                                     forms[3],
1173                                     NULL);
1174    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-HSyncStart);
1175    w=  XtVaCreateManagedWidget(
1176                                     "Wider-button",
1177                                     commandWidgetClass,
1178                                     forms[3],
1179                                     NULL);
1180    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-HTotal);
1181    w = XtVaCreateManagedWidget(
1182                                     "Narrower-button",
1183                                     commandWidgetClass,
1184                                     forms[3],
1185                                     NULL);
1186    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)HTotal);
1187    CreateTyp (forms[4], VDisplay, "VDisplay-label", "VDisplay-text", NULL);
1188    CreateTyp (forms[5], VSyncStart, "VSyncStart-label",
1189		"VSyncStart-text", "VSyncStart-scrollbar");
1190    CreateTyp (forms[6], VSyncEnd, "VSyncEnd-label", "VSyncEnd-text",
1191		"VSyncEnd-scrollbar");
1192    CreateTyp (forms[7], VTotal, "VTotal-label", "VTotal-text",
1193		"VTotal-scrollbar");
1194    w = XtVaCreateManagedWidget(
1195                                     "Up-button",
1196                                     commandWidgetClass,
1197                                     forms[7],
1198                                     NULL);
1199    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)VSyncStart);
1200    w = XtVaCreateManagedWidget(
1201                                     "Down-button",
1202                                     commandWidgetClass,
1203                                     forms[7],
1204                                     NULL);
1205    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-VSyncStart);
1206    w=  XtVaCreateManagedWidget(
1207                                     "Shorter-button",
1208                                     commandWidgetClass,
1209                                     forms[7],
1210                                     NULL);
1211    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)VTotal);
1212    w = XtVaCreateManagedWidget(
1213                                     "Taller-button",
1214                                     commandWidgetClass,
1215                                     forms[7],
1216                                     NULL);
1217    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-VTotal);
1218
1219    (void) sprintf (buf, "%04x", AppRes.field[Flags].val);
1220    wids[0] = XtCreateWidget ("Flags-label", labelWidgetClass,
1221		forms[8], NULL, 0);
1222    wids[1] = XtVaCreateWidget ("Flags-text", asciiTextWidgetClass,
1223		forms[8], XtNstring, buf, XtNtranslations, trans, NULL);
1224    AddCallback (wids[1], XtNcallback, FlagsEditCB, (XtPointer) Flags);
1225    XtManageChildren (wids, 2);
1226    AppRes.field[Flags].textwidget = wids[1];
1227
1228    wids[0] = XtCreateWidget ("Quit-button", commandWidgetClass,
1229		forms[9], NULL, 0);
1230    XtAddCallback (wids[0], XtNcallback, QuitCB, NULL);
1231
1232    wids[1] = XtCreateWidget ("Apply-button", commandWidgetClass,
1233		forms[9], NULL, 0);
1234    XtAddCallback (wids[1], XtNcallback, ApplyCB, NULL);
1235
1236    wids[2] = XtCreateWidget ("AutoApply-toggle", toggleWidgetClass,
1237		forms[9], NULL, 0);
1238    auto_apply_toggle = wids[2];
1239
1240    wids[3] = XtCreateWidget ("Test-button", commandWidgetClass,
1241		forms[9], NULL, 0);
1242    XtAddCallback (wids[3], XtNcallback, TestCB, NULL);
1243
1244    wids[4] = XtCreateWidget ("Restore-button", commandWidgetClass,
1245		forms[9], NULL, 0);
1246    XtAddCallback (wids[4], XtNcallback, RestoreCB, NULL);
1247
1248    XtManageChildren (wids, 5);
1249
1250
1251    CreateTyp (forms[10], PixelClock, "PixelClock-label", "PixelClock-text",
1252	       NULL);
1253    CreateTyp (forms[11], HSyncRate, "HSyncRate-label", "HSyncRate-text",
1254	       NULL);
1255    CreateTyp (forms[12], VSyncRate, "VSyncRate-label", "VSyncRate-text",
1256	       NULL);
1257
1258    wids[0] = XtCreateWidget ("Fetch-button", commandWidgetClass,
1259		forms[13], NULL, 0);
1260    XtAddCallback (wids[0], XtNcallback, FetchCB, NULL);
1261
1262    wids[1] = XtCreateWidget ("Show-button", commandWidgetClass,
1263		forms[13], NULL, 0);
1264    XtAddCallback (wids[1], XtNcallback, ShowCB, NULL);
1265
1266    wids[2] = XtCreateWidget ("Next-button", commandWidgetClass,
1267		forms[13], NULL, 0);
1268    XtAddCallback (wids[2], XtNcallback, SwitchCB, (XtPointer)1);
1269
1270    wids[3] = XtCreateWidget ("Prev-button", commandWidgetClass,
1271		forms[13], NULL, 0);
1272    XtAddCallback (wids[3], XtNcallback, SwitchCB, (XtPointer)-1);
1273
1274    XtManageChildren (wids, 4);
1275
1276    XtManageChildren (forms, 14);
1277
1278    if (S3Specials) {
1279	char buf[2] = "0";
1280	s3form = XtCreateWidget ("S3-form", formWidgetClass,
1281		form, NULL, 0);
1282	wids[0] = XtVaCreateWidget("InvertVclk-toggle", toggleWidgetClass,
1283			s3form, XtNstate, AppRes.field[InvertVclk].val, NULL);
1284	XtAddCallback (wids[0], XtNcallback, ApplyIfAutoCB, NULL);
1285	AppRes.field[InvertVclk].textwidget = wids[0];
1286	wids[1] = XtVaCreateWidget("EarlySc-toggle", toggleWidgetClass,
1287			s3form, XtNstate, AppRes.field[EarlySc].val, NULL);
1288	XtAddCallback (wids[1], XtNcallback, ApplyIfAutoCB, NULL);
1289	AppRes.field[EarlySc].textwidget = wids[1];
1290	wids[2] = XtCreateWidget("Blank1-label", labelWidgetClass, s3form,
1291			NULL, 0);
1292	wids[3] = XtVaCreateWidget("Blank1Dec-button", commandWidgetClass,
1293				   s3form, NULL);
1294	XtAddCallback (wids[3], XtNcallback, ChangeBlankCB,
1295			(XtPointer)-BlankDelay1);
1296	(void) sprintf (buf, "%d", AppRes.field[BlankDelay1].val);
1297	wids[4] = XtVaCreateWidget("Blank1-text", asciiTextWidgetClass,
1298			s3form, XtNstring, buf, XtNtranslations, trans, NULL);
1299	AddCallback(wids[4], XtNcallback, BlankEditCB, (XPointer) BlankDelay1);
1300	AppRes.field[BlankDelay1].textwidget = wids[4];
1301	wids[5] = XtVaCreateWidget("Blank1Inc-button", commandWidgetClass,
1302				   s3form, NULL);
1303	XtAddCallback (wids[5], XtNcallback, ChangeBlankCB,
1304			(XtPointer)BlankDelay1);
1305
1306	wids[6] = XtCreateWidget("Blank2-label", labelWidgetClass, s3form,
1307			NULL, 0);
1308	wids[7] = XtVaCreateWidget("Blank2Dec-button", commandWidgetClass,
1309				   s3form, NULL);
1310	XtAddCallback (wids[7], XtNcallback, ChangeBlankCB,
1311			(XtPointer)-BlankDelay2);
1312	(void) sprintf (buf, "%d", AppRes.field[BlankDelay2].val);
1313	wids[8] = XtVaCreateWidget("Blank2-text", asciiTextWidgetClass,
1314			s3form, XtNstring, buf, XtNtranslations, trans, NULL);
1315	AddCallback(wids[8], XtNcallback, BlankEditCB, (XPointer) BlankDelay2);
1316	AppRes.field[BlankDelay2].textwidget = wids[8];
1317	wids[9] = XtVaCreateWidget("Blank2Inc-button", commandWidgetClass,
1318				   s3form, NULL);
1319	XtAddCallback (wids[9], XtNcallback, ChangeBlankCB,
1320			(XtPointer)BlankDelay2);
1321	XtManageChildren (wids, 10);
1322	XtManageChild(s3form);
1323    }
1324
1325    XtManageChild (form);
1326
1327    SetScrollbars ();
1328    x = DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 2;
1329    y = DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 2;
1330
1331    invalid_mode_popup = XtVaCreatePopupShell("invalidMode",
1332			    transientShellWidgetClass, top,
1333			    XtNtitle, "Invalid Mode requested",
1334			    XtNx, x - 20,
1335			    XtNy, y - 40,
1336			    NULL);
1337
1338    testing_popup = XtVaCreatePopupShell("testing",
1339			    transientShellWidgetClass, top,
1340			    XtNtitle, "Testing_1_2_3",
1341			    XtNx, x - 20,
1342			    XtNy, y - 40,
1343			    NULL);
1344    boxW = XtVaCreateManagedWidget(
1345                                   "TestingBox",
1346                                   boxWidgetClass,
1347                                   testing_popup,
1348                                   NULL);
1349
1350    w = XtVaCreateManagedWidget(
1351		   "testingMessage",
1352                   labelWidgetClass,
1353                   boxW,
1354                   NULL);
1355
1356    w = XtVaCreateManagedWidget(
1357                               "Abort",
1358                                commandWidgetClass,
1359                                boxW,
1360                                NULL);
1361
1362    XtAddCallback (w, XtNcallback, (XtCallbackProc) TestTOCB,
1363		  (XtPointer) NULL);
1364
1365    boxW = XtVaCreateManagedWidget(
1366                                   "invalidBox",
1367                                   boxWidgetClass,
1368                                   invalid_mode_popup,
1369                                   NULL);
1370
1371    (void) XtVaCreateManagedWidget(
1372		   "ErrorMessage",
1373                   labelWidgetClass,
1374                   boxW,
1375                   NULL);
1376
1377    popdownW = XtVaCreateManagedWidget(
1378                                     "AckError",
1379                                     commandWidgetClass,
1380                                     boxW,
1381                                     NULL);
1382
1383    XtAddCallback (popdownW, XtNcallback, (XtCallbackProc)popdownInvalid,
1384		   (XtPointer) invalid_mode_popup);
1385}
1386
1387static void
1388QuitAction (Widget w, XEvent* e, String* vector, Cardinal* count)
1389{
1390    if ((e->type == ClientMessage
1391      && e->xclient.data.l[0] == (long) wm_delete_window)
1392	|| e->type == KeyPress)
1393	QuitCB(w, NULL, NULL);
1394}
1395
1396static void
1397RestoreAction (Widget w, XEvent* e, String* vector, Cardinal* count)
1398{
1399    Boolean state;
1400
1401    RestoreCB(w, NULL, NULL);
1402    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
1403    if (!state)
1404	ApplyCB (w, NULL, NULL);
1405}
1406
1407
1408static void
1409ShowAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1410{
1411    ShowCB(w, NULL, NULL);
1412}
1413
1414static void
1415MoveLeftAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1416{
1417    AdjustCB(w, (XtPointer)HSyncStart, NULL);
1418}
1419
1420static void
1421MoveRightAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1422{
1423    AdjustCB(w, (XtPointer)-HSyncStart, NULL);
1424}
1425
1426static void
1427NarrowerAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1428{
1429    AdjustCB(w, (XtPointer)HTotal, NULL);
1430}
1431
1432static void
1433WiderAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1434{
1435    AdjustCB(w, (XtPointer)-HTotal, NULL);
1436}
1437
1438static void
1439MoveUpAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1440{
1441    AdjustCB(w, (XtPointer)VSyncStart, NULL);
1442}
1443
1444static void
1445MoveDownAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1446{
1447    AdjustCB(w, (XtPointer)-VSyncStart, NULL);
1448}
1449
1450static void
1451TallerAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1452{
1453    AdjustCB(w, (XtPointer)-VTotal, NULL);
1454}
1455
1456static void
1457ShorterAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1458{
1459    AdjustCB(w, (XtPointer)VTotal, NULL);
1460}
1461
1462static void
1463NextModeAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1464{
1465	SwitchCB(w, (XPointer) 1, NULL);
1466}
1467
1468static void
1469PrevModeAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1470{
1471	SwitchCB(w, (XPointer) -1, NULL);
1472}
1473
1474
1475
1476static void
1477usage(void)
1478{
1479    fprintf(stderr, "Usage: xvidtune [option]\n");
1480    fprintf(stderr, "    where option is one of:\n");
1481    fprintf(stderr, "        -show                             Print current modeline to stdout\n");
1482    fprintf(stderr, "        -next                             Switch to next video mode\n");
1483    fprintf(stderr, "        -prev                             Switch to previous video mode\n");
1484    fprintf(stderr, "        -unlock                           Enable mode switch hot-keys\n");
1485    fprintf(stderr, "        -timeout [seconds]                Set testmode timeout in seconds,\n");
1486    exit(1);
1487}
1488
1489
1490int
1491main (int argc, char** argv)
1492{
1493    Widget top;
1494    XtAppContext app;
1495    Display* dpy;
1496    Bool modeSettable = TRUE;
1497
1498    static XtActionsRec actions[] = { { "xvidtune-quit", QuitAction },
1499				      { "xvidtune-restore", RestoreAction },
1500				      { "xvidtune-show", ShowAction },
1501				      {	"xvidtune-moveleft", MoveLeftAction },
1502				      {	"xvidtune-moveright", MoveRightAction },
1503				      {	"xvidtune-wider", WiderAction },
1504				      {	"xvidtune-narrower", NarrowerAction },
1505				      {	"xvidtune-moveup", MoveUpAction },
1506				      {	"xvidtune-movedown", MoveDownAction },
1507				      {	"xvidtune-taller", TallerAction },
1508				      {	"xvidtune-shorter", ShorterAction },
1509				      {	"xvidtune-nextmode", NextModeAction },
1510				      {	"xvidtune-prevmode", PrevModeAction } };
1511
1512    Top = top = XtVaOpenApplication (&app, "Xvidtune", NULL, 0, &argc, argv,
1513		NULL, applicationShellWidgetClass,
1514		XtNmappedWhenManaged, False, NULL);
1515
1516    XtGetApplicationResources (top, (XtPointer)&AppRes,
1517		Resources, XtNumber(Resources),
1518		NULL, 0);
1519
1520    if (!AppRes.ad_installed) {
1521	fprintf(stderr, "Please install the program before using\n");
1522	return 3;
1523    }
1524
1525    if (!XF86VidModeQueryVersion(XtDisplay (top), &MajorVersion, &MinorVersion)) {
1526	fprintf(stderr, "Unable to query video extension version\n");
1527	return 2;
1528    }
1529
1530    if (!XF86VidModeQueryExtension(XtDisplay (top), &EventBase, &ErrorBase)) {
1531	fprintf(stderr, "Unable to query video extension information\n");
1532	return 2;
1533    }
1534
1535    /* Fail if the extension version in the server is too old */
1536    if (MajorVersion < MINMAJOR ||
1537	(MajorVersion == MINMAJOR && MinorVersion < MINMINOR)) {
1538	fprintf(stderr,
1539		"Xserver is running an old XFree86-VidModeExtension version"
1540		" (%d.%d)\n", MajorVersion, MinorVersion);
1541	fprintf(stderr, "Minimum required version is %d.%d\n",
1542		MINMAJOR, MINMINOR);
1543	exit(2);
1544    }
1545
1546    /* This should probably be done differently */
1547
1548    if(  argc == 3  ) { /* this can only be the timeout case */
1549        if(  (!strcmp(argv[1], "-timeout"))  ) {
1550            TestTimeout = ((unsigned long) atol( argv[2] )) * 1000L;
1551	}
1552	else
1553	    usage();
1554    }
1555
1556    if (argc > 1) {
1557	int i = 0;
1558
1559	if (argc != 2)
1560		usage();
1561	if (!strcmp(argv[1], "-show")) {
1562	  if (!GetModeLine(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1563	    fprintf(stderr, "Unable to get mode info\n");
1564	    CleanUp(XtDisplay (top));
1565	    return 2;
1566	  }
1567	  ShowCB(top, NULL, NULL);
1568	  return 0;
1569	} else if (!strcmp(argv[1], "-next"))
1570	    i = 1;
1571	else if (!strcmp(argv[1], "-prev"))
1572	    i = -1;
1573	else if (!strcmp(argv[1], "-unlock")) {
1574	    CleanUp(XtDisplay (top));
1575	    XSync(XtDisplay (top), True);
1576	    return 0;
1577	} else
1578		usage();
1579	if (i != 0) {
1580	    XF86VidModeSwitchMode(XtDisplay (top),
1581				  DefaultScreen (XtDisplay (top)), i);
1582	    XSync(XtDisplay (top), True);
1583	    return 0;
1584	}
1585    }
1586    if (!GetMonitor(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1587	fprintf(stderr, "Unable to query monitor info\n");
1588	return 2;
1589    }
1590
1591    if (!XF86VidModeLockModeSwitch(XtDisplay (top),
1592				   DefaultScreen (XtDisplay (top)), TRUE)) {
1593	fprintf(stderr, "Failed to disable mode-switch hot-keys\n");
1594	return 2;
1595    }
1596
1597    signal(SIGINT, CatchSig);
1598    signal(SIGQUIT, CatchSig);
1599    signal(SIGTERM, CatchSig);
1600    signal(SIGHUP, CatchSig);
1601    sigId = XtAppAddSignal(app, CatchXtSig, NULL);
1602
1603    if (!GetModeLine(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1604	fprintf(stderr, "Unable to get mode info\n");
1605	CleanUp(XtDisplay (top));
1606	return 2;
1607    }
1608
1609    xtErrorfunc = XSetErrorHandler(vidmodeError);
1610
1611    trans = XtParseTranslationTable ("\
1612	<Key>0: insert-char()\n<Key>1: insert-char()\n\
1613	<Key>2: insert-char()\n<Key>3: insert-char()\n\
1614	<Key>4: insert-char()\n<Key>5: insert-char()\n\
1615	<Key>6: insert-char()\n<Key>7: insert-char()\n\
1616	<Key>8: insert-char()\n<Key>9: insert-char()\n\
1617	<Key>a: insert-char()\n<Key>b: insert-char()\n\
1618	<Key>c: insert-char()\n<Key>d: insert-char()\n\
1619	<Key>e: insert-char()\n<Key>f: insert-char()\n\
1620	<Key>+: insert-char()\n<Key>-: insert-char()\n\
1621	<Key>r: xvidtune-restore()\n<Key>q: xvidtune-quit()\n\
1622	<Key>BackSpace: delete-previous-character()\n\
1623	<Key>Right: forward-character()\n<Key>KP_Right: forward-character()\n\
1624	<Key>Left: backward-character()\n<Key>KP_Left: backward-character()\n\
1625	<Key>Delete: delete-previous-character()\n\
1626	<Key>KP_Delete: delete-previous-character()\n\
1627	<EnterWindow>: enter-window()\n<LeaveWindow>: leave-window()\n\
1628	<FocusIn>: focus-in()\n<FocusOut>: focus-out()\n\
1629	<Btn1Down>: select-start()\n");
1630
1631    if (!ModeSettable()) {
1632	printf("Video are not settable on this chip\n");
1633	displayNoTune(top);
1634	modeSettable = FALSE;
1635    } else
1636	CreateHierarchy (top);
1637
1638
1639    XtAppAddActions (app, actions, XtNumber(actions));
1640
1641    XtOverrideTranslations (top,
1642		XtParseTranslationTable ("<Message>WM_PROTOCOLS: xvidtune-quit()"));
1643
1644    XtRealizeWidget (top);
1645
1646    dpy = XtDisplay(top);
1647
1648    wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
1649
1650    (void) XSetWMProtocols (dpy, XtWindow (top), &wm_delete_window, 1);
1651
1652    XtMapWidget (top);
1653
1654    if (modeSettable)
1655	displayWarning(top);
1656
1657    /* really we should run our own event dispatching here until the
1658     * warning has been read...
1659     */
1660    XtAppMainLoop (app);
1661
1662    return 0;
1663}
1664