xvidtune.c revision 14ddf674
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
52static int MajorVersion, MinorVersion;
53static int EventBase, ErrorBase;
54static int dot_clock, mode_flags;
55static unsigned long TestTimeout=5000;  /* Default test timeout */
56static XtSignalId 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) snprintf (buf, sizeof(buf), "%04x", sdp->val);
374      else if (i >= PixelClock && i <= VSyncRate)
375	 (void) snprintf (buf, sizeof(buf), "%6.2f", (float)sdp->val / 1000.0);
376      else if (i == BlankDelay1 || i == BlankDelay2) {
377	 (void) snprintf (buf, sizeof(buf), "%d", sdp->val);
378      } else
379	 (void) snprintf (buf, sizeof(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    snprintf(tmpbuf, sizeof(tmpbuf), "\"%dx%d\"",
536	   AppRes.field[HDisplay].val, AppRes.field[VDisplay].val);
537    snprintf(modebuf, sizeof(modebuf),
538	   "%-11s   %6.2f   %4d %4d %4d %4d   %4d %4d %4d %4d",
539	   tmpbuf, (float)dot_clock/1000.0,
540	   AppRes.field[HDisplay].val,
541	   AppRes.field[HSyncStart].val,
542	   AppRes.field[HSyncEnd].val,
543	   AppRes.field[HTotal].val,
544	   AppRes.field[VDisplay].val,
545	   AppRes.field[VSyncStart].val,
546	   AppRes.field[VSyncEnd].val,
547	   AppRes.field[VTotal].val);
548    /* Print out the flags (if any) */
549    if (mode_flags & V_PHSYNC)    strcat(modebuf, " +hsync");
550    if (mode_flags & V_NHSYNC)    strcat(modebuf, " -hsync");
551    if (mode_flags & V_PVSYNC)    strcat(modebuf, " +vsync");
552    if (mode_flags & V_NVSYNC)    strcat(modebuf, " -vsync");
553    if (mode_flags & V_INTERLACE) strcat(modebuf, " interlace");
554    if (mode_flags & V_CSYNC)     strcat(modebuf, " composite");
555    if (mode_flags & V_PCSYNC)    strcat(modebuf, " +csync");
556    if (mode_flags & V_NCSYNC)    strcat(modebuf, " -csync");
557    if (mode_flags & V_DBLSCAN)   strcat(modebuf, " doublescan");
558    printf("%s\n", modebuf);
559    time = XtLastTimestampProcessed(XtDisplay(w));
560    XtOwnSelection(w, XA_PRIMARY, time, ConvertSelection, NULL, NULL);
561    if (S3Specials) {
562	unsigned int i;
563	Boolean state;
564	char *string;
565
566	XtVaGetValues(AppRes.field[InvertVclk].textwidget,
567			XtNstate, &state, NULL);
568	AppRes.field[InvertVclk].val = state ? 1 : 0;
569	XtVaGetValues (AppRes.field[BlankDelay1].textwidget,
570			XtNstring, &string, NULL);
571	(void) sscanf (string, "%x", &i);
572	AppRes.field[BlankDelay1].val = i;
573	XtVaGetValues (AppRes.field[BlankDelay2].textwidget,
574			XtNstring, &string, NULL);
575	(void) sscanf (string, "%x", &i);
576	AppRes.field[BlankDelay2].val = i;
577	XtVaGetValues(AppRes.field[EarlySc].textwidget,
578			XtNstate, &state, NULL);
579	AppRes.field[EarlySc].val = state ? 1 : 0;
580	if (AppRes.field[InvertVclk].val != AppRes.orig[InvertVclk])
581	    printf("InvertVCLK\t\"%dx%d\" %d\n", AppRes.field[HDisplay].val,
582		AppRes.field[VDisplay].val, AppRes.field[InvertVclk].val);
583	if (AppRes.field[EarlySc].val != AppRes.orig[EarlySc])
584	    printf("EarlySC\t\t\"%dx%d\" %d\n", AppRes.field[HDisplay].val,
585		AppRes.field[VDisplay].val, AppRes.field[EarlySc].val);
586	if (AppRes.field[BlankDelay1].val != AppRes.orig[BlankDelay1]
587	    || AppRes.field[BlankDelay2].val != AppRes.orig[BlankDelay2])
588	    printf("BlankDelay\t\"%dx%d\" %d %d\n", AppRes.field[HDisplay].val,
589		AppRes.field[VDisplay].val, AppRes.field[BlankDelay1].val,
590		AppRes.field[BlankDelay2].val);
591    }
592    printf("\n");
593}
594
595static void
596AdjustCB(Widget w, XtPointer client, XtPointer call)
597{
598   int what = (long) client;
599   Boolean state;
600
601   switch (what) {
602    case HSyncStart:
603      if (AppRes.field[HSyncEnd].val + 4 < AppRes.field[HTotal].val) {
604	 AppRes.field[HSyncEnd].val += 4;
605	 AppRes.field[HSyncStart].val += 4;
606	 SetLabel(HSyncStart);
607	 SetLabel(HSyncEnd);
608      } else
609	XBell(XtDisplay(w), 80);
610      break;
611    case -HSyncStart:
612      if (AppRes.field[HSyncStart].val - 4 > AppRes.field[HDisplay].val) {
613	 AppRes.field[HSyncEnd].val -= 4;
614	 AppRes.field[HSyncStart].val -= 4;
615	 SetLabel(HSyncStart);
616	 SetLabel(HSyncEnd);
617      } else
618	XBell(XtDisplay(w), 80);
619      break;
620    case HTotal:
621      AppRes.field[HTotal].val += 4;
622      SetLabel(HTotal);
623      UpdateSyncRates(TRUE);
624      break;
625    case -HTotal:
626      if (AppRes.field[HTotal].val - 4 >  AppRes.field[HSyncEnd].val) {
627	AppRes.field[HTotal].val -= 4;
628	SetLabel(HTotal);
629	UpdateSyncRates(TRUE);
630      } else
631	XBell(XtDisplay(w), 80);
632      break;
633    case VSyncStart:
634      if (AppRes.field[VSyncEnd].val + 4 < AppRes.field[VTotal].val) {
635	 AppRes.field[VSyncEnd].val += 4;
636	 AppRes.field[VSyncStart].val += 4;
637	 SetLabel(VSyncStart);
638	 SetLabel(VSyncEnd);
639      } else
640	XBell(XtDisplay(w), 80);
641      break;
642    case -VSyncStart:
643      if (AppRes.field[VSyncStart].val - 4 > AppRes.field[VDisplay].val) {
644	 AppRes.field[VSyncEnd].val -= 4;
645	 AppRes.field[VSyncStart].val -= 4;
646	 SetLabel(VSyncStart);
647	 SetLabel(VSyncEnd);
648      } else
649	XBell(XtDisplay(w), 80);
650      break;
651    case VTotal:
652      AppRes.field[VTotal].val += 4;
653      SetLabel(VTotal);
654      UpdateSyncRates(TRUE);
655      break;
656    case -VTotal:
657      if (AppRes.field[VTotal].val - 4 >  AppRes.field[VSyncEnd].val) {
658	AppRes.field[VTotal].val -= 4;
659	SetLabel(VTotal);
660	UpdateSyncRates(TRUE);
661      } else
662	XBell(XtDisplay(w), 80);
663      break;
664   }
665   SetScrollbars ();
666   XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
667   if (state)
668       ApplyCB (w, client, call);
669}
670
671
672#if 0
673static void
674EditCB (Widget w, XtPointer client, XtPointer call)
675{
676    int base, current, i, len;
677    int lower, upper;
678    float percent;
679    ScrollData* sdp = (ScrollData*) client;
680
681    len = strlen (sdp->string);
682
683    for (i = 0; i < len; i++) {
684	if (!(isdigit (sdp->string[i]) || isspace (sdp->string[i]))) {
685	    XBell (XtDisplay(XtParent(w)), 100);
686	    return;
687	}
688    }
689    switch (sdp->me) {
690    case HSyncStart:
691	lower = atoi (AppRes.field[HDisplay].string);
692	upper = atoi (AppRes.field[HSyncEnd].string);
693	break;
694
695    case HSyncEnd:
696	lower = atoi (AppRes.field[HSyncStart].string);
697	upper = atoi (AppRes.field[HTotal].string);
698	break;
699
700    case HTotal:
701	lower = atoi (AppRes.field[HSyncEnd].string);
702	upper = atoi (AppRes.field[HDisplay].string) +
703		AppRes.field[HTotal].range;
704	break;
705
706    case VSyncStart:
707	lower = atoi (AppRes.field[VDisplay].string);
708	upper = atoi (AppRes.field[VSyncEnd].string);
709	break;
710
711    case VSyncEnd:
712	lower = atoi (AppRes.field[VSyncStart].string);
713	upper = atoi (AppRes.field[VTotal].string);
714	break;
715
716    case VTotal:
717	lower = atoi (AppRes.field[VSyncEnd].string);
718	upper = atoi (AppRes.field[VDisplay].string) +
719		AppRes.field[VTotal].range;
720	break;
721    }
722    current = atoi (sdp->string);
723    if (current < lower || current > upper) {
724	XawTextBlock text;
725	char tmp[6];
726
727	if (current < lower) {
728	    (void) snprintf (tmp, sizeof(tmp), "%5d", lower);
729	    current = lower;
730	} else {
731	    (void) snprintf (tmp, sizeof(tmp), "%5d", upper);
732	    current = upper;
733	}
734	text.firstPos = 0;
735	text.length = strlen (tmp);
736	text.ptr = tmp;
737	text.format = XawFmt8Bit;
738	XawTextReplace (sdp->textwidget, 0, text.length, &text);
739    }
740    base = atoi (AppRes.field[sdp->use].string);
741    percent = ((float)(current - base)) / ((float)sdp->range);
742    XawScrollbarSetThumb (sdp->scrollwidget, percent, 0.0);
743}
744#endif
745
746static void
747FlagsEditCB (Widget w, XtPointer client, XtPointer call)
748{
749    int i, len;
750    char* string;
751    fields findex = (fields) (unsigned long) client;
752    ScrollData* sdp = &AppRes.field[findex];
753
754    XtVaGetValues (w, XtNstring, &string, NULL);
755    len = strlen (string);
756    if (len > 4) {
757	char buf[5];
758
759	XBell (XtDisplay(XtParent(w)), 100);
760	(void) strncpy (buf, string, 4);
761	buf[4] = '\0';
762	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
763	XawTextSetInsertionPoint (sdp->textwidget, 4);
764    }
765
766    for (i = 0; i < len; i++) {
767	if (!isxdigit (string[i])) {
768	    XBell (XtDisplay(XtParent(w)), 100);
769	}
770    }
771}
772
773static void
774BlankEditCB (Widget w, XtPointer client, XtPointer call)
775{
776    int len;
777    char* string;
778    fields findex = (fields) (unsigned long) client;
779    ScrollData* sdp = &AppRes.field[findex];
780    char buf[2], old;
781    Boolean state;
782    Boolean noAuto = False;
783
784    XtVaGetValues (w, XtNstring, &string, NULL);
785    len = strlen (string);
786    if (len == 0) {
787	XBell (XtDisplay(XtParent(w)), 100);
788	strcpy(buf, "0");
789	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
790	XawTextSetInsertionPoint (sdp->textwidget, 1);
791        return;
792    }
793    if (len > 1) {
794	if (XawTextGetInsertionPoint(sdp->textwidget) < 1) {
795	    buf[0] = string[0];
796	    old = string[1];
797	} else {
798	    buf[0] = string[1];
799	    old = string[0];
800	}
801	if (buf[0] == '+' && old < '7')
802	    buf[0] = old + 1;
803	else if (buf[0] == '-' && old > '0')
804	    buf[0] = old - 1;
805	if (!isdigit(buf[0]) || buf[0] > '7') {
806	    XBell (XtDisplay(XtParent(w)), 100);
807	    buf[0] = old;
808	    if (!isdigit(buf[0]) || buf[0] > '7')
809		buf[0] = '0';
810	    noAuto = True;
811	}
812	buf[1] = '\0';
813	XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
814	XawTextSetInsertionPoint (sdp->textwidget, 1);
815    }
816    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
817    if (state && !noAuto)
818	ApplyCB (sdp->textwidget, client, call);
819}
820
821static void
822ChangeBlankCB (Widget w, XtPointer client, XtPointer call)
823{
824    char* string;
825    char buf[2];
826    fields findex;
827    ScrollData* sdp;
828    Boolean state;
829    int what = (long) client;
830
831
832    if (what < 0)
833	findex = (fields)-what;
834    else
835	findex = (fields)what;
836    sdp = &AppRes.field[findex];
837
838    XtVaGetValues (sdp->textwidget, XtNstring, &string, NULL);
839    if (what > 0)
840	string[0]++;
841    else
842	string[0]--;
843
844    if (string[0] < '0' || string[0] > '7') {
845	XBell (XtDisplay(XtParent(w)), 100);
846	return;
847    }
848
849    buf[0] = string[0];
850    buf[1] = '\0';
851    XtVaSetValues (sdp->textwidget, XtNstring, buf, NULL);
852    XawTextSetInsertionPoint (sdp->textwidget, 1);
853
854    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
855    if (state)
856	ApplyCB (sdp->textwidget, client, call);
857}
858
859static int
860isValid(int val, int field)
861{
862   switch(field) {
863     case HSyncStart:
864	if (val+8 > AppRes.field[HSyncEnd].val)
865	   val = AppRes.field[HSyncEnd].val - 8;
866        break;
867     case HSyncEnd:
868        if (val-8 < AppRes.field[HSyncStart].val)
869	    val = AppRes.field[HSyncStart].val + 8;
870        if (val > AppRes.field[HTotal].val)
871	    val = AppRes.field[HTotal].val;
872        break;
873     case HTotal:
874	if (val < AppRes.field[HSyncEnd].val)
875	   val = AppRes.field[HSyncEnd].val;
876         break;
877     case VSyncStart:
878	if (val+8 > AppRes.field[VSyncEnd].val)
879	   val = AppRes.field[VSyncEnd].val - 8;
880        break;
881     case VSyncEnd:
882        if (val-8 < AppRes.field[VSyncStart].val)
883	    val = AppRes.field[VSyncStart].val + 8;
884        if (val > AppRes.field[VTotal].val)
885	    val = AppRes.field[VTotal].val;
886        break;
887     case VTotal:
888	if (val < AppRes.field[VSyncEnd].val)
889	   val = AppRes.field[VSyncEnd].val;
890        break;
891   }
892   return val;
893}
894
895static void
896ScrollCB (Widget w, XtPointer client, XtPointer call)
897{
898    float percent = *(float*) call;
899    int ipercent = percent * 100;
900    int fieldindex = (long) client;
901    ScrollData* sdp = &AppRes.field[fieldindex];
902
903
904
905    if (ipercent != sdp->lastpercent) {
906        int tmp_val;
907	char buf[6];
908
909	tmp_val = AppRes.field[sdp->use].val;
910	tmp_val += (int) (((float)sdp->range) * percent);
911
912        sdp->val = isValid(tmp_val, fieldindex);
913
914	sdp->lastpercent = ipercent;
915	(void) snprintf (buf, sizeof(buf), "%5d", sdp->val);
916	XtVaSetValues (sdp->textwidget, XtNlabel, buf, NULL);
917        if (sdp->val != tmp_val) {
918            int base;
919            float percent;
920
921            base = AppRes.field[sdp->use].val;
922            percent = ((float)(sdp->val - base)) / ((float)sdp->range);
923            /* This doesn't always work, why? */
924            XawScrollbarSetThumb (sdp->scrollwidget, percent, 0.0);
925	}
926	if (fieldindex == HTotal || fieldindex == VTotal)
927	    UpdateSyncRates(TRUE);
928    }
929}
930
931static void
932SwitchCB (Widget w, XtPointer client, XtPointer call)
933{
934    XF86VidModeLockModeSwitch(XtDisplay(w), DefaultScreen (XtDisplay (w)),
935			      FALSE);
936    XF86VidModeSwitchMode(XtDisplay(w), DefaultScreen (XtDisplay (w)),
937			  (int)(long) client);
938    XF86VidModeLockModeSwitch(XtDisplay(w), DefaultScreen (XtDisplay (w)),
939			      TRUE);
940    FetchCB(w, NULL, NULL);
941}
942
943static void
944AddCallback (
945    Widget w,
946    String  callback_name,
947    XtCallbackProc callback,
948    XtPointer client_data)
949{
950    Widget src;
951
952    XtVaGetValues (w, XtNtextSource, &src, NULL);
953    XtAddCallback (src, callback_name, callback, client_data);
954}
955
956static void
957CreateTyp (
958    Widget form,
959    fields findex,
960    String w1name,
961    String w2name,
962    String w3name)
963{
964    Widget wids[3];
965    char buf[10];
966
967    wids[0] = XtCreateWidget (w1name, labelWidgetClass, form, NULL, 0);
968    if (findex >= PixelClock && findex <= VSyncRate)
969	(void) snprintf(buf, sizeof(buf), "%6.2f",
970			(float)AppRes.field[findex].val / 1000.0);
971    else
972	(void) snprintf (buf, sizeof(buf), "%5d", AppRes.field[findex].val);
973    wids[1] = XtVaCreateWidget (w2name, labelWidgetClass,
974		form, XtNlabel, buf, NULL);
975    if (w3name != NULL) {
976	wids[2] = XtCreateWidget (w3name, scrollbarWidgetClass, form, NULL, 0);
977	XtAddCallback (wids[2], XtNjumpProc, ScrollCB, (XtPointer) findex);
978	XtManageChildren (wids, 3);
979    } else {
980	wids[2] = (Widget) NULL;
981	XtManageChildren (wids, 2);
982    }
983    AppRes.field[findex].textwidget = wids[1];
984    AppRes.field[findex].scrollwidget = wids[2];
985}
986
987
988static void
989AckWarn (Widget w, XtPointer client, XtPointer call)
990{
991    XtPopdown((Widget) client);
992    XtDestroyWidget((Widget) client);
993}
994
995static void
996AckNoTune (Widget w, XtPointer client, XtPointer call)
997{
998    CleanUp(XtDisplay(w));
999#if XtSpecificationRelease < 6
1000    exit (0);
1001#else
1002    XtAppSetExitFlag (XtWidgetToApplicationContext (w));
1003#endif
1004}
1005
1006static void
1007displayWarning(Widget top)
1008{
1009    Widget w, popup, popupBox;
1010    int x, y;
1011
1012    x =  DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1013    y =  DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1014
1015    popup = XtVaCreatePopupShell("Warning",
1016			    transientShellWidgetClass, top,
1017			    XtNtitle, "WARNING",
1018			    XtNx, x,
1019			    XtNy, y,
1020			    NULL);
1021
1022    popupBox = XtVaCreateManagedWidget(
1023               "WarningBox",
1024               boxWidgetClass,
1025               popup,
1026               NULL);
1027
1028    w = XtVaCreateManagedWidget( "WarnLabel",
1029                                     labelWidgetClass,
1030				     popupBox,
1031                                     NULL);
1032
1033    w = XtVaCreateManagedWidget( "WarnOK",
1034                                     commandWidgetClass,
1035				     popupBox,
1036                                     NULL);
1037
1038    XtAddCallback (w, XtNcallback, AckWarn, (XtPointer)popup);
1039
1040    w = XtVaCreateManagedWidget( "WarnCancel",
1041                                     commandWidgetClass,
1042				     popupBox,
1043                                     NULL);
1044    XtAddCallback (w, XtNcallback, QuitCB, (XtPointer)NULL);
1045
1046    XtPopup(popup, XtGrabExclusive);
1047
1048}
1049
1050static void
1051displayNoTune(Widget top)
1052{
1053    Widget w, popup, popupBox;
1054
1055    popup = XtCreateWidget ("Notice", formWidgetClass, top, NULL, 0);
1056    popupBox = XtVaCreateManagedWidget(
1057               "WarningBox",
1058               boxWidgetClass,
1059               popup,
1060               NULL);
1061
1062    w = XtVaCreateManagedWidget( "NoTuneLabel",
1063                                     labelWidgetClass,
1064				     popupBox,
1065                                     NULL);
1066
1067    w = XtVaCreateManagedWidget( "NoTuneOK",
1068                                     commandWidgetClass,
1069				     popupBox,
1070                                     NULL);
1071
1072    XtAddCallback (w, XtNcallback, AckNoTune, (XtPointer)popup);
1073
1074    XtManageChild (popup);
1075}
1076
1077#if 0
1078static void
1079s3Special(Widget top)
1080{
1081    Widget w, popup, form, invert_vclk_toggle, wids[6];
1082    char buf1[5] = {'\0',};
1083    int x, y;
1084
1085    x =  DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1086    y =  DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 3;
1087
1088    popup = XtVaCreatePopupShell("S3Adjust",
1089			    transientShellWidgetClass, top,
1090			    XtNtitle, "S3Adjust",
1091			    XtNx, x,
1092			    XtNy, y,
1093			    NULL);
1094
1095    form = XtVaCreateManagedWidget(
1096               "S3Box",
1097               formWidgetClass,
1098               popup,
1099               NULL);
1100
1101    w = XtVaCreateManagedWidget( "S3Title",
1102                                     labelWidgetClass,
1103				     form,
1104                                     NULL);
1105
1106    invert_vclk_toggle = XtVaCreateManagedWidget( "InvertVclk-toggle",
1107                                     toggleWidgetClass,
1108				     form,
1109                                     NULL);
1110
1111    wids[0] = XtCreateWidget ("Blank1-label", labelWidgetClass,
1112		form, NULL, 0);
1113    wids[1] = XtVaCreateWidget ("Blank1-text", asciiTextWidgetClass,
1114		form, XtNstring, buf1, NULL);
1115    AddCallback (wids[1], XtNcallback, FlagsEditCB, (XtPointer) NULL);
1116
1117    XtManageChildren (wids, 2);
1118
1119    XtPopup(popup, XtGrabNone);
1120
1121}
1122#endif
1123
1124
1125
1126static void
1127CreateHierarchy(Widget top)
1128{
1129    char buf[5];
1130    Widget form, forms[14], s3form;
1131    Widget wids[10];
1132    Widget boxW, popdownW, w;
1133    int i;
1134    int x, y;
1135    static String form_names[] = {
1136	"HDisplay-form",
1137	"HSyncStart-form",
1138	"HSyncEnd-form",
1139	"HTotal-form",
1140	"VDisplay-form",
1141	"VSyncStart-form",
1142	"VSyncEnd-form",
1143	"VTotal-form",
1144	"Flags-form",
1145	"Buttons-form",
1146	"PixelClock-form",
1147	"HSyncRate-form",
1148	"VSyncRate-form",
1149	"Buttons2-form",
1150	};
1151
1152    form = XtCreateWidget ("form", formWidgetClass, top, NULL, 0);
1153    for (i = 0; i < 14; i++)
1154	forms[i] = XtCreateWidget (form_names[i], formWidgetClass,
1155		form, NULL, 0);
1156
1157    CreateTyp (forms[0], HDisplay, "HDisplay-label", "HDisplay-text", NULL);
1158    CreateTyp (forms[1], HSyncStart, "HSyncStart-label",
1159		"HSyncStart-text", "HSyncStart-scrollbar");
1160    CreateTyp (forms[2], HSyncEnd, "HSyncEnd-label", "HSyncEnd-text",
1161		"HSyncEnd-scrollbar");
1162    CreateTyp (forms[3], HTotal, "HTotal-label", "HTotal-text",
1163		"HTotal-scrollbar");
1164
1165    w = XtVaCreateManagedWidget(
1166                                     "Left-button",
1167                                     commandWidgetClass,
1168                                     forms[3],
1169                                     NULL);
1170    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)HSyncStart);
1171    w = XtVaCreateManagedWidget(
1172                                     "Right-button",
1173                                     commandWidgetClass,
1174                                     forms[3],
1175                                     NULL);
1176    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-HSyncStart);
1177    w=  XtVaCreateManagedWidget(
1178                                     "Wider-button",
1179                                     commandWidgetClass,
1180                                     forms[3],
1181                                     NULL);
1182    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-HTotal);
1183    w = XtVaCreateManagedWidget(
1184                                     "Narrower-button",
1185                                     commandWidgetClass,
1186                                     forms[3],
1187                                     NULL);
1188    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)HTotal);
1189    CreateTyp (forms[4], VDisplay, "VDisplay-label", "VDisplay-text", NULL);
1190    CreateTyp (forms[5], VSyncStart, "VSyncStart-label",
1191		"VSyncStart-text", "VSyncStart-scrollbar");
1192    CreateTyp (forms[6], VSyncEnd, "VSyncEnd-label", "VSyncEnd-text",
1193		"VSyncEnd-scrollbar");
1194    CreateTyp (forms[7], VTotal, "VTotal-label", "VTotal-text",
1195		"VTotal-scrollbar");
1196    w = XtVaCreateManagedWidget(
1197                                     "Up-button",
1198                                     commandWidgetClass,
1199                                     forms[7],
1200                                     NULL);
1201    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)VSyncStart);
1202    w = XtVaCreateManagedWidget(
1203                                     "Down-button",
1204                                     commandWidgetClass,
1205                                     forms[7],
1206                                     NULL);
1207    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-VSyncStart);
1208    w=  XtVaCreateManagedWidget(
1209                                     "Shorter-button",
1210                                     commandWidgetClass,
1211                                     forms[7],
1212                                     NULL);
1213    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)VTotal);
1214    w = XtVaCreateManagedWidget(
1215                                     "Taller-button",
1216                                     commandWidgetClass,
1217                                     forms[7],
1218                                     NULL);
1219    XtAddCallback (w, XtNcallback, AdjustCB, (XtPointer)-VTotal);
1220
1221    (void) snprintf (buf, sizeof(buf), "%04x", AppRes.field[Flags].val);
1222    wids[0] = XtCreateWidget ("Flags-label", labelWidgetClass,
1223		forms[8], NULL, 0);
1224    wids[1] = XtVaCreateWidget ("Flags-text", asciiTextWidgetClass,
1225		forms[8], XtNstring, buf, XtNtranslations, trans, NULL);
1226    AddCallback (wids[1], XtNcallback, FlagsEditCB, (XtPointer) Flags);
1227    XtManageChildren (wids, 2);
1228    AppRes.field[Flags].textwidget = wids[1];
1229
1230    wids[0] = XtCreateWidget ("Quit-button", commandWidgetClass,
1231		forms[9], NULL, 0);
1232    XtAddCallback (wids[0], XtNcallback, QuitCB, NULL);
1233
1234    wids[1] = XtCreateWidget ("Apply-button", commandWidgetClass,
1235		forms[9], NULL, 0);
1236    XtAddCallback (wids[1], XtNcallback, ApplyCB, NULL);
1237
1238    wids[2] = XtCreateWidget ("AutoApply-toggle", toggleWidgetClass,
1239		forms[9], NULL, 0);
1240    auto_apply_toggle = wids[2];
1241
1242    wids[3] = XtCreateWidget ("Test-button", commandWidgetClass,
1243		forms[9], NULL, 0);
1244    XtAddCallback (wids[3], XtNcallback, TestCB, NULL);
1245
1246    wids[4] = XtCreateWidget ("Restore-button", commandWidgetClass,
1247		forms[9], NULL, 0);
1248    XtAddCallback (wids[4], XtNcallback, RestoreCB, NULL);
1249
1250    XtManageChildren (wids, 5);
1251
1252
1253    CreateTyp (forms[10], PixelClock, "PixelClock-label", "PixelClock-text",
1254	       NULL);
1255    CreateTyp (forms[11], HSyncRate, "HSyncRate-label", "HSyncRate-text",
1256	       NULL);
1257    CreateTyp (forms[12], VSyncRate, "VSyncRate-label", "VSyncRate-text",
1258	       NULL);
1259
1260    wids[0] = XtCreateWidget ("Fetch-button", commandWidgetClass,
1261		forms[13], NULL, 0);
1262    XtAddCallback (wids[0], XtNcallback, FetchCB, NULL);
1263
1264    wids[1] = XtCreateWidget ("Show-button", commandWidgetClass,
1265		forms[13], NULL, 0);
1266    XtAddCallback (wids[1], XtNcallback, ShowCB, NULL);
1267
1268    wids[2] = XtCreateWidget ("Next-button", commandWidgetClass,
1269		forms[13], NULL, 0);
1270    XtAddCallback (wids[2], XtNcallback, SwitchCB, (XtPointer)1);
1271
1272    wids[3] = XtCreateWidget ("Prev-button", commandWidgetClass,
1273		forms[13], NULL, 0);
1274    XtAddCallback (wids[3], XtNcallback, SwitchCB, (XtPointer)-1);
1275
1276    XtManageChildren (wids, 4);
1277
1278    XtManageChildren (forms, 14);
1279
1280    if (S3Specials) {
1281	char buf[2] = "0";
1282	s3form = XtCreateWidget ("S3-form", formWidgetClass,
1283		form, NULL, 0);
1284	wids[0] = XtVaCreateWidget("InvertVclk-toggle", toggleWidgetClass,
1285			s3form, XtNstate, AppRes.field[InvertVclk].val, NULL);
1286	XtAddCallback (wids[0], XtNcallback, ApplyIfAutoCB, NULL);
1287	AppRes.field[InvertVclk].textwidget = wids[0];
1288	wids[1] = XtVaCreateWidget("EarlySc-toggle", toggleWidgetClass,
1289			s3form, XtNstate, AppRes.field[EarlySc].val, NULL);
1290	XtAddCallback (wids[1], XtNcallback, ApplyIfAutoCB, NULL);
1291	AppRes.field[EarlySc].textwidget = wids[1];
1292	wids[2] = XtCreateWidget("Blank1-label", labelWidgetClass, s3form,
1293			NULL, 0);
1294	wids[3] = XtVaCreateWidget("Blank1Dec-button", commandWidgetClass,
1295				   s3form, NULL);
1296	XtAddCallback (wids[3], XtNcallback, ChangeBlankCB,
1297			(XtPointer)-BlankDelay1);
1298	(void) snprintf (buf, sizeof(buf), "%d", AppRes.field[BlankDelay1].val);
1299	wids[4] = XtVaCreateWidget("Blank1-text", asciiTextWidgetClass,
1300			s3form, XtNstring, buf, XtNtranslations, trans, NULL);
1301	AddCallback(wids[4], XtNcallback, BlankEditCB, (XPointer) BlankDelay1);
1302	AppRes.field[BlankDelay1].textwidget = wids[4];
1303	wids[5] = XtVaCreateWidget("Blank1Inc-button", commandWidgetClass,
1304				   s3form, NULL);
1305	XtAddCallback (wids[5], XtNcallback, ChangeBlankCB,
1306			(XtPointer)BlankDelay1);
1307
1308	wids[6] = XtCreateWidget("Blank2-label", labelWidgetClass, s3form,
1309			NULL, 0);
1310	wids[7] = XtVaCreateWidget("Blank2Dec-button", commandWidgetClass,
1311				   s3form, NULL);
1312	XtAddCallback (wids[7], XtNcallback, ChangeBlankCB,
1313			(XtPointer)-BlankDelay2);
1314	(void) snprintf (buf, sizeof(buf), "%d", AppRes.field[BlankDelay2].val);
1315	wids[8] = XtVaCreateWidget("Blank2-text", asciiTextWidgetClass,
1316			s3form, XtNstring, buf, XtNtranslations, trans, NULL);
1317	AddCallback(wids[8], XtNcallback, BlankEditCB, (XPointer) BlankDelay2);
1318	AppRes.field[BlankDelay2].textwidget = wids[8];
1319	wids[9] = XtVaCreateWidget("Blank2Inc-button", commandWidgetClass,
1320				   s3form, NULL);
1321	XtAddCallback (wids[9], XtNcallback, ChangeBlankCB,
1322			(XtPointer)BlankDelay2);
1323	XtManageChildren (wids, 10);
1324	XtManageChild(s3form);
1325    }
1326
1327    XtManageChild (form);
1328
1329    SetScrollbars ();
1330    x = DisplayWidth(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 2;
1331    y = DisplayHeight(XtDisplay (top),DefaultScreen (XtDisplay (top))) / 2;
1332
1333    invalid_mode_popup = XtVaCreatePopupShell("invalidMode",
1334			    transientShellWidgetClass, top,
1335			    XtNtitle, "Invalid Mode requested",
1336			    XtNx, x - 20,
1337			    XtNy, y - 40,
1338			    NULL);
1339
1340    testing_popup = XtVaCreatePopupShell("testing",
1341			    transientShellWidgetClass, top,
1342			    XtNtitle, "Testing_1_2_3",
1343			    XtNx, x - 20,
1344			    XtNy, y - 40,
1345			    NULL);
1346    boxW = XtVaCreateManagedWidget(
1347                                   "TestingBox",
1348                                   boxWidgetClass,
1349                                   testing_popup,
1350                                   NULL);
1351
1352    w = XtVaCreateManagedWidget(
1353		   "testingMessage",
1354                   labelWidgetClass,
1355                   boxW,
1356                   NULL);
1357
1358    w = XtVaCreateManagedWidget(
1359                               "Abort",
1360                                commandWidgetClass,
1361                                boxW,
1362                                NULL);
1363
1364    XtAddCallback (w, XtNcallback, (XtCallbackProc) TestTOCB,
1365		  (XtPointer) NULL);
1366
1367    boxW = XtVaCreateManagedWidget(
1368                                   "invalidBox",
1369                                   boxWidgetClass,
1370                                   invalid_mode_popup,
1371                                   NULL);
1372
1373    (void) XtVaCreateManagedWidget(
1374		   "ErrorMessage",
1375                   labelWidgetClass,
1376                   boxW,
1377                   NULL);
1378
1379    popdownW = XtVaCreateManagedWidget(
1380                                     "AckError",
1381                                     commandWidgetClass,
1382                                     boxW,
1383                                     NULL);
1384
1385    XtAddCallback (popdownW, XtNcallback, (XtCallbackProc)popdownInvalid,
1386		   (XtPointer) invalid_mode_popup);
1387}
1388
1389static void
1390QuitAction (Widget w, XEvent* e, String* vector, Cardinal* count)
1391{
1392    if ((e->type == ClientMessage
1393      && e->xclient.data.l[0] == (long) wm_delete_window)
1394	|| e->type == KeyPress)
1395	QuitCB(w, NULL, NULL);
1396}
1397
1398static void
1399RestoreAction (Widget w, XEvent* e, String* vector, Cardinal* count)
1400{
1401    Boolean state;
1402
1403    RestoreCB(w, NULL, NULL);
1404    XtVaGetValues(auto_apply_toggle, XtNstate, &state, NULL);
1405    if (!state)
1406	ApplyCB (w, NULL, NULL);
1407}
1408
1409
1410static void
1411ShowAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1412{
1413    ShowCB(w, NULL, NULL);
1414}
1415
1416static void
1417MoveLeftAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1418{
1419    AdjustCB(w, (XtPointer)HSyncStart, NULL);
1420}
1421
1422static void
1423MoveRightAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1424{
1425    AdjustCB(w, (XtPointer)-HSyncStart, NULL);
1426}
1427
1428static void
1429NarrowerAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1430{
1431    AdjustCB(w, (XtPointer)HTotal, NULL);
1432}
1433
1434static void
1435WiderAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1436{
1437    AdjustCB(w, (XtPointer)-HTotal, NULL);
1438}
1439
1440static void
1441MoveUpAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1442{
1443    AdjustCB(w, (XtPointer)VSyncStart, NULL);
1444}
1445
1446static void
1447MoveDownAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1448{
1449    AdjustCB(w, (XtPointer)-VSyncStart, NULL);
1450}
1451
1452static void
1453TallerAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1454{
1455    AdjustCB(w, (XtPointer)-VTotal, NULL);
1456}
1457
1458static void
1459ShorterAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1460{
1461    AdjustCB(w, (XtPointer)VTotal, NULL);
1462}
1463
1464static void
1465NextModeAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1466{
1467	SwitchCB(w, (XPointer) 1, NULL);
1468}
1469
1470static void
1471PrevModeAction(Widget w, XEvent* e, String* vector, Cardinal* count)
1472{
1473	SwitchCB(w, (XPointer) -1, NULL);
1474}
1475
1476
1477
1478static void
1479usage(void)
1480{
1481    fprintf(stderr, "Usage: xvidtune [option]\n");
1482    fprintf(stderr, "    where option is one of:\n");
1483    fprintf(stderr, "        -show                             Print current modeline to stdout\n");
1484    fprintf(stderr, "        -next                             Switch to next video mode\n");
1485    fprintf(stderr, "        -prev                             Switch to previous video mode\n");
1486    fprintf(stderr, "        -unlock                           Enable mode switch hot-keys\n");
1487    fprintf(stderr, "        -timeout [seconds]                Set testmode timeout in seconds,\n");
1488    exit(1);
1489}
1490
1491
1492int
1493main (int argc, char** argv)
1494{
1495    Widget top;
1496    XtAppContext app;
1497    Display* dpy;
1498    Bool modeSettable = TRUE;
1499
1500    static XtActionsRec actions[] = { { "xvidtune-quit", QuitAction },
1501				      { "xvidtune-restore", RestoreAction },
1502				      { "xvidtune-show", ShowAction },
1503				      {	"xvidtune-moveleft", MoveLeftAction },
1504				      {	"xvidtune-moveright", MoveRightAction },
1505				      {	"xvidtune-wider", WiderAction },
1506				      {	"xvidtune-narrower", NarrowerAction },
1507				      {	"xvidtune-moveup", MoveUpAction },
1508				      {	"xvidtune-movedown", MoveDownAction },
1509				      {	"xvidtune-taller", TallerAction },
1510				      {	"xvidtune-shorter", ShorterAction },
1511				      {	"xvidtune-nextmode", NextModeAction },
1512				      {	"xvidtune-prevmode", PrevModeAction } };
1513
1514    Top = top = XtVaOpenApplication (&app, "Xvidtune", NULL, 0, &argc, argv,
1515		NULL, applicationShellWidgetClass,
1516		XtNmappedWhenManaged, False, NULL);
1517
1518    XtGetApplicationResources (top, (XtPointer)&AppRes,
1519		Resources, XtNumber(Resources),
1520		NULL, 0);
1521
1522    if (!AppRes.ad_installed) {
1523	fprintf(stderr, "Please install the program before using\n");
1524	return 3;
1525    }
1526
1527    if (!XF86VidModeQueryVersion(XtDisplay (top), &MajorVersion, &MinorVersion)) {
1528	fprintf(stderr, "Unable to query video extension version\n");
1529	return 2;
1530    }
1531
1532    if (!XF86VidModeQueryExtension(XtDisplay (top), &EventBase, &ErrorBase)) {
1533	fprintf(stderr, "Unable to query video extension information\n");
1534	return 2;
1535    }
1536
1537    /* Fail if the extension version in the server is too old */
1538    if (MajorVersion < MINMAJOR ||
1539	(MajorVersion == MINMAJOR && MinorVersion < MINMINOR)) {
1540	fprintf(stderr,
1541		"Xserver is running an old XFree86-VidModeExtension version"
1542		" (%d.%d)\n", MajorVersion, MinorVersion);
1543	fprintf(stderr, "Minimum required version is %d.%d\n",
1544		MINMAJOR, MINMINOR);
1545	exit(2);
1546    }
1547
1548    /* This should probably be done differently */
1549
1550    if(  argc == 3  ) { /* this can only be the timeout case */
1551        if(  (!strcmp(argv[1], "-timeout"))  ) {
1552            TestTimeout = ((unsigned long) atol( argv[2] )) * 1000L;
1553	}
1554	else
1555	    usage();
1556    }
1557
1558    if (argc > 1) {
1559	int i = 0;
1560
1561	if (argc != 2)
1562		usage();
1563	if (!strcmp(argv[1], "-show")) {
1564	  if (!GetModeLine(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1565	    fprintf(stderr, "Unable to get mode info\n");
1566	    CleanUp(XtDisplay (top));
1567	    return 2;
1568	  }
1569	  ShowCB(top, NULL, NULL);
1570	  return 0;
1571	} else if (!strcmp(argv[1], "-next"))
1572	    i = 1;
1573	else if (!strcmp(argv[1], "-prev"))
1574	    i = -1;
1575	else if (!strcmp(argv[1], "-unlock")) {
1576	    CleanUp(XtDisplay (top));
1577	    XSync(XtDisplay (top), True);
1578	    return 0;
1579	} else
1580		usage();
1581	if (i != 0) {
1582	    XF86VidModeSwitchMode(XtDisplay (top),
1583				  DefaultScreen (XtDisplay (top)), i);
1584	    XSync(XtDisplay (top), True);
1585	    return 0;
1586	}
1587    }
1588    if (!GetMonitor(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1589	fprintf(stderr, "Unable to query monitor info\n");
1590	return 2;
1591    }
1592
1593    if (!XF86VidModeLockModeSwitch(XtDisplay (top),
1594				   DefaultScreen (XtDisplay (top)), TRUE)) {
1595	fprintf(stderr, "Failed to disable mode-switch hot-keys\n");
1596	return 2;
1597    }
1598
1599    signal(SIGINT, CatchSig);
1600    signal(SIGQUIT, CatchSig);
1601    signal(SIGTERM, CatchSig);
1602    signal(SIGHUP, CatchSig);
1603    sigId = XtAppAddSignal(app, CatchXtSig, NULL);
1604
1605    if (!GetModeLine(XtDisplay (top), DefaultScreen (XtDisplay (top)))) {
1606	fprintf(stderr, "Unable to get mode info\n");
1607	CleanUp(XtDisplay (top));
1608	return 2;
1609    }
1610
1611    xtErrorfunc = XSetErrorHandler(vidmodeError);
1612
1613    trans = XtParseTranslationTable ("\
1614	<Key>0: insert-char()\n<Key>1: insert-char()\n\
1615	<Key>2: insert-char()\n<Key>3: insert-char()\n\
1616	<Key>4: insert-char()\n<Key>5: insert-char()\n\
1617	<Key>6: insert-char()\n<Key>7: insert-char()\n\
1618	<Key>8: insert-char()\n<Key>9: insert-char()\n\
1619	<Key>a: insert-char()\n<Key>b: insert-char()\n\
1620	<Key>c: insert-char()\n<Key>d: insert-char()\n\
1621	<Key>e: insert-char()\n<Key>f: insert-char()\n\
1622	<Key>+: insert-char()\n<Key>-: insert-char()\n\
1623	<Key>r: xvidtune-restore()\n<Key>q: xvidtune-quit()\n\
1624	<Key>BackSpace: delete-previous-character()\n\
1625	<Key>Right: forward-character()\n<Key>KP_Right: forward-character()\n\
1626	<Key>Left: backward-character()\n<Key>KP_Left: backward-character()\n\
1627	<Key>Delete: delete-previous-character()\n\
1628	<Key>KP_Delete: delete-previous-character()\n\
1629	<EnterWindow>: enter-window()\n<LeaveWindow>: leave-window()\n\
1630	<FocusIn>: focus-in()\n<FocusOut>: focus-out()\n\
1631	<Btn1Down>: select-start()\n");
1632
1633    if (!ModeSettable()) {
1634	printf("Video modes are not settable on this chip\n");
1635	displayNoTune(top);
1636	modeSettable = FALSE;
1637    } else
1638	CreateHierarchy (top);
1639
1640
1641    XtAppAddActions (app, actions, XtNumber(actions));
1642
1643    XtOverrideTranslations (top,
1644		XtParseTranslationTable ("<Message>WM_PROTOCOLS: xvidtune-quit()"));
1645
1646    XtRealizeWidget (top);
1647
1648    dpy = XtDisplay(top);
1649
1650    wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
1651
1652    (void) XSetWMProtocols (dpy, XtWindow (top), &wm_delete_window, 1);
1653
1654    XtMapWidget (top);
1655
1656    if (modeSettable)
1657	displayWarning(top);
1658
1659    /* really we should run our own event dispatching here until the
1660     * warning has been read...
1661     */
1662    XtAppMainLoop (app);
1663
1664    return 0;
1665}
1666