diff options
Diffstat (limited to 'xorg-server/hw/xfree86/utils/xorgcfg/vidmode.c')
-rw-r--r-- | xorg-server/hw/xfree86/utils/xorgcfg/vidmode.c | 1346 |
1 files changed, 1346 insertions, 0 deletions
diff --git a/xorg-server/hw/xfree86/utils/xorgcfg/vidmode.c b/xorg-server/hw/xfree86/utils/xorgcfg/vidmode.c new file mode 100644 index 000000000..2d613b6df --- /dev/null +++ b/xorg-server/hw/xfree86/utils/xorgcfg/vidmode.c @@ -0,0 +1,1346 @@ +/* + * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Conectiva Linux shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from + * Conectiva Linux. + * + * Author: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> + * + */ + +/* + * Most of the code here is based on the xvidtune code. + */ + +#include "vidmode.h" +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/MenuButton.h> +#include <X11/Xaw/Repeater.h> +#include <X11/Shell.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Dialog.h> +#include <X11/Xaw/SimpleMenP.h> +#include <X11/Xaw/SmeBSB.h> +#include <X11/Xaw/Toggle.h> +#include "xf86config.h" + +#define V_FLAG_MASK 0x1FF +#define V_PHSYNC 0x001 +#define V_NHSYNC 0x002 +#define V_PVSYNC 0x004 +#define V_NVSYNC 0x008 +#define V_INTERLACE 0x010 +#define V_DBLSCAN 0x020 +#define V_CSYNC 0x040 +#define V_PCSYNC 0x080 +#define V_NCSYNC 0x100 + +#define LEFT 0 +#define RIGHT 1 +#define UP 2 +#define DOWN 3 +#define WIDER 4 +#define TALLER 5 +#define NARROWER 6 +#define SHORTER 7 + +#define HDISPLAY 0 +#define VDISPLAY 1 +#define HSYNCSTART 2 +#define HSYNCEND 3 +#define HTOTAL 4 +#define VSYNCSTART 5 +#define VSYNCEND 6 +#define VTOTAL 7 +#define FLAGS 8 +#define CLOCK 9 +#define HSYNC 10 +#define VSYNC 11 + +#define MINMAJOR 2 +#define MINMINOR 0 + +/* + * Types + */ +typedef struct { + char *ident; + XF86VidModeModeInfo info; +} xf86cfgVesaModeInfo; + +/* + * Prototypes + */ +static Bool GetModeLine(Bool); +static void StartAdjustMonitorCallback(Widget, XtPointer, XtPointer); +static void AdjustMonitorCallback(Widget, XtPointer, XtPointer); +static void EndAdjustMonitorCallback(Widget, XtPointer, XtPointer); +static void SetLabel(int, int); +static void UpdateSyncRates(Bool); +static int VidmodeError(Display*, XErrorEvent*); +static void CleanUp(Display*); +static void ApplyCallback(Widget, XtPointer, XtPointer); +static void AutoCallback(Widget, XtPointer, XtPointer); +static void RestoreCallback(Widget, XtPointer, XtPointer); +static void SelectCallback(Widget, XtPointer, XtPointer); +static void SelectMonitorCallback(Widget, XtPointer, XtPointer); +static void SwitchCallback(Widget, XtPointer, XtPointer); +static void SetLabels(void); +static void UpdateCallback(Widget, XtPointer, XtPointer); +static void ChangeScreenCallback(Widget, XtPointer, XtPointer); +static void SetLabelAndModeline(void); +static void AddVesaModeCallback(Widget, XtPointer, XtPointer); +static void GetModes(void); +static void AddModeCallback(Widget, XtPointer, XtPointer); +static void TestCallback(Widget, XtPointer, XtPointer); +static void TestTimeout(XtPointer, XtIntervalId*); +static void StopTestCallback(Widget, XtPointer, XtPointer); +static int ForceAddMode(void); +static int AddMode(void); +/* + * Initialization + */ +extern Widget work; +Widget vtune; +static Widget apply, automatic, restore, mode, menu, screenb, screenp; +static Bool autoflag; +static xf86cfgVidmode *vidtune; +static XF86VidModeModeLine modeline, orig_modeline; +static int dot_clock, hsync_rate, vsync_rate, hitError; +static int screenno; +static int (*XtErrorFunc)(Display*, XErrorEvent*); +static Widget values[VSYNC + 1], repeater, monitor, + monitorb, add, text, vesap, forceshell, testshell, addshell; +static int MajorVersion, MinorVersion, EventBase, ErrorBase; +static XtIntervalId timeout; + +/* The information bellow is extracted from + * xc/programs/Xserver/hw/xfree86/etc/vesamodes + * If that file is changed, please update the table bellow also. Or even + * better, write a script to generate the table. + */ +static xf86cfgVesaModeInfo vesamodes[] = { + { + "640x350 @ 85Hz (VESA) hsync: 37.9kHz", + { + 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, + V_PHSYNC | V_NVSYNC + } + }, + { + "640x400 @ 85Hz (VESA) hsync: 37.9kHz", + { + 31500, 640, 672, 736, 832, 0, 400, 401, 404, 445, + V_NHSYNC | V_PVSYNC + } + }, + { + "720x400 @ 85Hz (VESA) hsync: 37.9kHz", + { + 35500, 720, 756, 828, 936, 0, 400, 401, 404, 446, + V_NHSYNC | V_PVSYNC + } + }, + { + "640x480 @ 60Hz (Industry standard) hsync: 31.5kHz", + { + 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, + V_NHSYNC | V_NVSYNC + } + }, + { + "640x480 @ 72Hz (VESA) hsync: 37.9kHz", + { + 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, + V_NHSYNC | V_NVSYNC + } + }, + { + "640x480 @ 75Hz (VESA) hsync: 37.5kHz", + { + 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, + V_NHSYNC | V_NVSYNC + } + }, + { + "640x480 @ 85Hz (VESA) hsync: 43.3kHz", + { + 36000, 640, 696, 752, 832, 0, 480, 481, 484, 509, + V_NHSYNC | V_NVSYNC + } + }, + { + "800x600 @ 56Hz (VESA) hsync: 35.2kHz", + { + 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, + V_PHSYNC | V_PVSYNC + } + }, + { + "800x600 @ 60Hz (VESA) hsync: 37.9kHz", + { + 400000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, + V_PHSYNC | V_PVSYNC + } + }, + { + "800x600 @ 72Hz (VESA) hsync: 48.1kHz", + { + 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, + V_PHSYNC | V_PVSYNC + } + }, + { + "800x600 @ 75Hz (VESA) hsync: 46.9kHz", + { + 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, + V_PHSYNC | V_PVSYNC + } + }, + { + "800x600 @ 85Hz (VESA) hsync: 53.7kHz", + { + 563000, 800, 832, 896, 1048, 0, 600, 601, 604, 631, + V_PHSYNC | V_PVSYNC + } + }, + { + "1024x768i @ 43Hz (industry standard) hsync: 35.5kHz", + { + 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, + V_PHSYNC | V_PVSYNC | V_INTERLACE + } + }, + { + "1024x768 @ 60Hz (VESA) hsync: 48.4kHz", + { + 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, + V_NHSYNC | V_NVSYNC + } + }, + { + "1024x768 @ 70Hz (VESA) hsync: 56.5kHz", + { + 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, + V_NHSYNC | V_NVSYNC + } + }, + { + "1024x768 @ 75Hz (VESA) hsync: 60.0kHz", + { + 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, + V_PHSYNC | V_PVSYNC + } + }, + { + "1024x768 @ 85Hz (VESA) hsync: 68.7kHz", + { + 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, + V_PHSYNC | V_PVSYNC + } + }, + { + "1152x864 @ 75Hz (VESA) hsync: 67.5kHz", + { + 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, + V_PHSYNC | V_PVSYNC + } + }, + { + "1280x960 @ 60Hz (VESA) hsync: 60.0kHz", + { + 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, + V_PHSYNC | V_PVSYNC + } + }, + { + "1280x960 @ 85Hz (VESA) hsync: 85.9kHz", + { + 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, + V_PHSYNC | V_PVSYNC + } + }, + { + "1280x1024 @ 60Hz (VESA) hsync: 64.0kHz", + { + 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, + V_PHSYNC | V_PVSYNC + } + }, + { + "1280x1024 @ 75Hz (VESA) hsync: 80.0kHz", + { + 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, + V_PHSYNC | V_PVSYNC + } + }, + { + "1280x1024 @ 85Hz (VESA) hsync: 91.1kHz", + { + 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, + V_PHSYNC | V_PVSYNC + } + }, + { + "1600x1200 @ 60Hz (VESA) hsync: 75.0kHz", + { + 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, + V_PHSYNC | V_PVSYNC + } + }, + { + "1600x1200 @ 65Hz (VESA) hsync: 81.3kHz", + { + 175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, + V_PHSYNC | V_PVSYNC + } + }, + { + "1600x1200 @ 70Hz (VESA) hsync: 87.5kHz", + { + 189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, + V_PHSYNC | V_PVSYNC + } + }, + { + "1600x1200 @ 75Hz (VESA) hsync: 93.8kHz", + { + 202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, + V_PHSYNC | V_PVSYNC + } + }, + { + "1600x1200 @ 85Hz (VESA) hsync: 106.3kHz", + { + 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, + V_PHSYNC | V_PVSYNC + } + }, + { + "1792x1344 @ 60Hz (VESA) hsync: 83.6kHz", + { + 204800, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, + V_NHSYNC | V_PVSYNC + } + }, + { + "1792x1344 @ 75Hz (VESA) hsync: 106.3kHz", + { + 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, + V_NHSYNC | V_PVSYNC + } + }, + { + "1856x1392 @ 60Hz (VESA) hsync: 86.3kHz", + { + 218300, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, + V_NHSYNC | V_PVSYNC + } + }, + { + "1856x1392 @ 75Hz (VESA) hsync: 112.5kHz", + { + 288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, + V_NHSYNC | V_PVSYNC + } + }, + { + "1920x1440 @ 60Hz (VESA) hsync: 90.0kHz", + { + 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, + V_NHSYNC | V_PVSYNC + } + }, + { + "1920x1440 @ 75Hz (VESA) hsync: 112.5kHz", + { + 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, + V_NHSYNC | V_PVSYNC + } + }, +}; + +/* + * Implementation + */ +Bool +VideoModeInitialize(void) +{ + Widget form; + char dispstr[128], *ptr, *tmp; + + static char *names[] = { + NULL, + NULL, + "hsyncstart", + "hsyncend", + "htotal", + "vsyncstart", + "vsyncend", + "vtotal", + "flags", + "clock", + "hsync", + "vsync", + }; + static char *vnames[] = { + NULL, + NULL, + "v-hsyncstart", + "v-hsyncend", + "v-htotal", + "v-vsyncstart", + "v-vsyncend", + "v-vtotal", + "v-flags", + "v-clock", + "v-hsync", + "v-vsync", + }; + Widget rep; + int i; + + if (!XF86VidModeQueryVersion(XtDisplay(toplevel), + &MajorVersion, &MinorVersion)) { + fprintf(stderr, "Unable to query video extension version\n"); + return (False); + } + else if (!XF86VidModeQueryExtension(XtDisplay(toplevel), + &EventBase, &ErrorBase)) { + fprintf(stderr, "Unable to query video extension information\n"); + return (False); + } + else if (MajorVersion < MINMAJOR || + (MajorVersion == MINMAJOR && MinorVersion < MINMINOR)) { + fprintf(stderr, + "Xserver is running an old XFree86-VidModeExtension version" + " (%d.%d)\n", MajorVersion, MinorVersion); + fprintf(stderr, "Minimum required version is %d.%d\n", + MINMAJOR, MINMINOR); + return (False); + } + else + InitializeVidmodes(); + + vtune = XtCreateWidget("vidtune", formWidgetClass, + work, NULL, 0); + + (void) XtVaCreateManagedWidget("vesaB", menuButtonWidgetClass, vtune, + XtNmenuName, "vesaP", NULL); + vesap = XtCreatePopupShell("vesaP", simpleMenuWidgetClass, vtune, NULL, 0); + for (i = 0; i < sizeof(vesamodes) / sizeof(vesamodes[0]); i++) { + rep = XtCreateManagedWidget(vesamodes[i].ident, smeBSBObjectClass, + vesap, NULL, 0); + XtAddCallback(rep, XtNcallback, AddVesaModeCallback, + (XtPointer)&vesamodes[i]); + } + + rep = XtCreateManagedWidget("prev", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(rep, XtNcallback, SwitchCallback, (XtPointer)-1); + mode = XtCreateManagedWidget("mode", menuButtonWidgetClass, vtune, NULL, 0); + rep = XtCreateManagedWidget("next", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(rep, XtNcallback, SwitchCallback, (XtPointer)1); + + screenp = XtCreatePopupShell("screenP", simpleMenuWidgetClass, vtune, + NULL, 0); + + XmuSnprintf(dispstr, sizeof(dispstr), "%s", + DisplayString(XtDisplay(toplevel))); + ptr = strrchr(dispstr, '.'); + tmp = strrchr(dispstr, ':'); + if (tmp != NULL && ptr != NULL && ptr > tmp) + *ptr = '\0'; + + for (i = 0; i < ScreenCount(XtDisplay(toplevel)); i++) { + char name[128]; + + XmuSnprintf(name, sizeof(name), "%s.%d", dispstr, i); + rep = XtCreateManagedWidget(name, smeBSBObjectClass, screenp, + NULL, 0); + XtAddCallback(rep, XtNcallback, ChangeScreenCallback, + (XtPointer)(long)i); + if (i == 0) { + screenb = XtVaCreateManagedWidget("screenB", menuButtonWidgetClass, + vtune, + XtNmenuName, "screenP", + XtNlabel, name, + NULL); + } + } + XtRealizeWidget(screenp); + + rep = XtCreateManagedWidget("up", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)UP); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("left", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)LEFT); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + XtCreateManagedWidget("monitor", simpleWidgetClass, vtune, NULL, 0); + rep = XtCreateManagedWidget("right", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)RIGHT); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("down", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)DOWN); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("wider", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)WIDER); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("narrower", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)NARROWER); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("shorter", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)SHORTER); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + rep = XtCreateManagedWidget("taller", repeaterWidgetClass, + vtune, NULL, 0); + XtAddCallback(rep, XtNstartCallback, StartAdjustMonitorCallback, NULL); + XtAddCallback(rep, XtNcallback, + AdjustMonitorCallback, (XtPointer)TALLER); + XtAddCallback(rep, XtNstopCallback, EndAdjustMonitorCallback, NULL); + + automatic = XtCreateManagedWidget("auto", toggleWidgetClass, vtune, NULL, 0); + XtAddCallback(automatic, XtNcallback, AutoCallback, NULL); + apply = XtCreateManagedWidget("apply", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(apply, XtNcallback, ApplyCallback, NULL); + restore = XtCreateManagedWidget("restore", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(restore, XtNcallback, RestoreCallback, NULL); + rep = XtCreateManagedWidget("update", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(rep, XtNcallback, UpdateCallback, NULL); + rep = XtCreateManagedWidget("test", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(rep, XtNcallback, TestCallback, NULL); + + form = XtCreateManagedWidget("form", formWidgetClass, vtune, NULL, 0); + for (i = 2; i < VSYNC + 1; i++) { + (void) XtCreateManagedWidget(names[i], labelWidgetClass, + form, NULL, 0); + values[i] = XtCreateManagedWidget(vnames[i], labelWidgetClass, + form, NULL, 0); + } + + add = XtCreateManagedWidget("add", commandWidgetClass, vtune, NULL, 0); + XtAddCallback(add, XtNcallback, AddModeCallback, NULL); + XtCreateManagedWidget("addto", labelWidgetClass, vtune, NULL, 0); + monitorb = XtCreateManagedWidget("ident", menuButtonWidgetClass, vtune, + NULL, 0); + XtCreateManagedWidget("as", labelWidgetClass, vtune, NULL, 0); + text = XtVaCreateManagedWidget("text", asciiTextWidgetClass, vtune, + XtNeditType, XawtextEdit, NULL); + + XtRealizeWidget(vtune); + + return (True); +} + +void +InitializeVidmodes(void) +{ + int i; + Display *display = XtDisplay(toplevel); + + computer.num_vidmodes = ScreenCount(display); + computer.vidmodes = (xf86cfgVidmode**) + XtMalloc(sizeof(xf86cfgVidmode*) * computer.num_vidmodes); + for (i = 0; i < computer.num_vidmodes; i++) { + + computer.vidmodes[i] = (xf86cfgVidmode*) + XtCalloc(1, sizeof(xf86cfgVidmode)); + computer.vidmodes[i]->screen = i; + } +} + +void +VideoModeConfigureStart(void) +{ + vidtune = computer.vidmodes[screenno]; + + XtSetSensitive(vtune, vidtune != NULL); + if (!XtIsManaged(vtune)) + XtManageChild(vtune); + else + XtMapWidget(vtune); + if (vidtune != NULL) { + Arg args[1]; + Boolean state; + XF86ConfMonitorPtr mon; + static char menuName[16]; + static int menuN; + + XtErrorFunc = XSetErrorHandler(VidmodeError); + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, True); + GetModeLine(True); + GetModes(); + + SetLabels(); + XtSetArg(args[0], XtNstate, &state); + XtGetValues(automatic, args, 1); + XtSetSensitive(apply, !state); + autoflag = state; + + if (monitor) + XtDestroyWidget(monitor); + XmuSnprintf(menuName, sizeof(menuName), "menuP%d", menuN); + menuN = !menuN; + monitor = XtCreatePopupShell(menuName, simpleMenuWidgetClass, + vtune, NULL, 0); + XtVaSetValues(monitorb, XtNmenuName, menuName, NULL); + + mon = XF86Config->conf_monitor_lst; + while (mon != NULL) { + Widget sme = XtCreateManagedWidget(mon->mon_identifier, + smeBSBObjectClass, + monitor, NULL, 0); + XtAddCallback(sme, XtNcallback, + SelectMonitorCallback, (XtPointer)mon); + + /* guess the monitor at a given screen and/or + * updates configuration if a monitor was removed from the + * configuration. + */ + if (XF86Config->conf_layout_lst) { + XF86ConfAdjacencyPtr adj = XF86Config->conf_layout_lst-> + lay_adjacency_lst; + + while (adj != NULL) { + if (adj->adj_screen != NULL) { + if (adj->adj_screen->scrn_monitor == mon && + adj->adj_scrnum >= 0 && + adj->adj_scrnum < ScreenCount(XtDisplay(toplevel))) { + if (computer.vidmodes[adj->adj_scrnum]->monitor == + NULL || computer.vidmodes[adj->adj_scrnum]-> + monitor == adj->adj_screen->scrn_monitor) { + computer.vidmodes[adj->adj_scrnum]->monitor = + adj->adj_screen->scrn_monitor; + break; + } + else + computer.vidmodes[adj->adj_scrnum]->monitor = + NULL; + } + } + adj = (XF86ConfAdjacencyPtr)(adj->list.next); + } + } + mon = (XF86ConfMonitorPtr)(mon->list.next); + } + SetLabelAndModeline(); + } +} + +void +VideoModeConfigureEnd(void) +{ + XtUnmapWidget(vtune); + if (vidtune != NULL) { + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, False); + XSetErrorHandler(XtErrorFunc); + } + vidtune = NULL; +} + +static void +SetLabelAndModeline(void) +{ + if (vidtune->monitor != NULL) { + char string[32]; + + XtVaSetValues(monitorb, XtNlabel, + vidtune->monitor->mon_identifier, NULL); + XtSetSensitive(add, True); + + if (modeline.htotal && modeline.vtotal) + XmuSnprintf(string, sizeof(string), "%dx%d@%d", + modeline.hdisplay, modeline.vdisplay, + (int)((double)dot_clock / (double)modeline.htotal * 1000.0 / + (double)modeline.vtotal)); + else + XmuSnprintf(string, sizeof(string), "%dx%d", + modeline.hdisplay, modeline.vdisplay); + XtVaSetValues(text, XtNstring, string, NULL); + } + else { + XtVaSetValues(monitorb, XtNlabel, "", NULL); + XtSetSensitive(add, False); + XtVaSetValues(text, XtNstring, "", NULL); + } +} + +/*ARGSUSED*/ +void +VidmodeRestoreAction(Widget w, XEvent *event, + String *params, Cardinal *num_params) +{ + if (vidtune != NULL) { + if (timeout != 0) + StopTestCallback(w, NULL, NULL); + else + RestoreCallback(w, NULL, NULL); + } +} + +static void +UpdateSyncRates(Bool update) +{ + if (modeline.htotal && modeline.vtotal) { + hsync_rate = (dot_clock * 1000) / modeline.htotal; + vsync_rate = (hsync_rate * 1000) / modeline.vtotal; + if (modeline.flags & V_INTERLACE) + vsync_rate *= 2; + else if (modeline.flags & V_DBLSCAN) + vsync_rate /= 2; + if (update) { + SetLabel(HSYNC, hsync_rate); + SetLabel(VSYNC, vsync_rate); + } + } +} + +static void +SetLabel(int ident, int value) +{ + Arg args[1]; + char label[256]; + + if (ident == FLAGS) { + int len = 0; + + *label = '\0'; + if (value & V_PHSYNC) + len += XmuSnprintf(label, sizeof(label), "%s", "+hsync"); + if (modeline.flags & V_NHSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "-hsync"); + if (value & V_PVSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "+vsync"); + if (value & V_NVSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "-vsync"); + if (value & V_INTERLACE) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "interlace"); + if (value & V_CSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "composite"); + if (value & V_PCSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "+csync"); + if (value & V_NCSYNC) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "-csync"); + if (value & V_DBLSCAN) + len += XmuSnprintf(label + len, sizeof(label), "%s%s", + len ? " " : "", "doublescan"); + + } + else if (ident == CLOCK || ident == HSYNC || ident == VSYNC) + XmuSnprintf(label, sizeof(label), "%6.2f", (float)value / 1000.0); + else + XmuSnprintf(label, sizeof(label), "%d", value); + + XtSetArg(args[0], XtNlabel, label); + XtSetValues(values[ident], args, 1); +} + +/*ARGSUSED*/ +static void +StartAdjustMonitorCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + repeater = w; +} + +static void +AdjustMonitorCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + if (repeater != w) + return; + switch ((long)client_data) { + case LEFT: + if (modeline.hsyncend + 4 < modeline.htotal) { + modeline.hsyncstart += 4; + modeline.hsyncend += 4; + SetLabel(HSYNCSTART, modeline.hsyncstart); + SetLabel(HSYNCEND, modeline.hsyncend); + } + else + XBell(XtDisplay(w), 80); + break; + case RIGHT: + if (modeline.hsyncstart - 4 > modeline.hdisplay) { + modeline.hsyncstart -= 4; + modeline.hsyncend -= 4; + SetLabel(HSYNCSTART, modeline.hsyncstart); + SetLabel(HSYNCEND, modeline.hsyncend); + } + else + XBell(XtDisplay(w), 80); + break; + case NARROWER: + modeline.htotal += 4; + SetLabel(HTOTAL, modeline.htotal); + UpdateSyncRates(True); + break; + case WIDER: + if (modeline.htotal - 4 > modeline.hsyncend) { + modeline.htotal -= 4; + SetLabel(HTOTAL, modeline.htotal); + UpdateSyncRates(True); + } + else + XBell(XtDisplay(w), 80); + break; + case UP: + if (modeline.vsyncend + 4 < modeline.vtotal) { + modeline.vsyncstart += 4; + modeline.vsyncend += 4; + SetLabel(VSYNCSTART, modeline.vsyncstart); + SetLabel(VSYNCEND, modeline.vsyncend); + } + else + XBell(XtDisplay(w), 80); + break; + case DOWN: + if (modeline.vsyncstart - 4 > modeline.vdisplay) { + modeline.vsyncstart -= 4; + modeline.vsyncend -= 4; + SetLabel(VSYNCSTART, modeline.vsyncstart); + SetLabel(VSYNCEND, modeline.vsyncend); + } + else + XBell(XtDisplay(w), 80); + break; + case SHORTER: + modeline.vtotal += 4; + SetLabel(VTOTAL, modeline.vtotal); + UpdateSyncRates(True); + break; + case TALLER: + if (modeline.vtotal - 4 > modeline.vsyncend) { + modeline.vtotal -= 4; + SetLabel(VTOTAL, modeline.vtotal); + UpdateSyncRates(True); + } + else + XBell(XtDisplay(w), 80); + break; + } + + if (autoflag) + ApplyCallback(w, call_data, client_data); +} + +/*ARGSUSED*/ +static void +EndAdjustMonitorCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + repeater = NULL; +} + +static Bool +GetModeLine(Bool save) +{ + if (XF86VidModeGetModeLine(XtDisplay(toplevel), vidtune->screen, + &dot_clock, &modeline)) { + if (save) + memcpy(&orig_modeline, &modeline, sizeof(XF86VidModeModeLine)); + UpdateSyncRates(False); + return (True); + } + + return (False); +} + +static void +CleanUp(Display *display) +{ + /* Make sure mode switching is not locked out at exit */ + XF86VidModeLockModeSwitch(display, vidtune->screen, False); + XFlush(display); +} + +static int +VidmodeError(Display *display, XErrorEvent *error) +{ + if ((error->error_code >= ErrorBase && + error->error_code < ErrorBase + XF86VidModeNumberErrors) || + error->error_code == BadValue) { + hitError = 1; + } + else { + CleanUp(display); + if (XtErrorFunc) + (*XtErrorFunc)(display, error); + } + return (0); +} + +/*ARGSUSED*/ +static void +ApplyCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + hitError = 0; + XF86VidModeModModeLine(XtDisplay(w), vidtune->screen, &modeline); + XSync(XtDisplay(w), False); + if (hitError) { + if (repeater != NULL) { + XtCallActionProc(repeater, "unset", NULL, NULL, 0); + XtCallActionProc(repeater, "stop", NULL, NULL, 0); + repeater = NULL; + } + XBell(XtDisplay(w), 80); + if (timeout) + StopTestCallback(w, NULL, NULL); + GetModeLine(False); + SetLabels(); + } +} + +/*ARGSUSED*/ +static void +AutoCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + autoflag = (Bool)(long)client_data; + XtSetSensitive(apply, !autoflag); +} + +static void +RestoreCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + memcpy(&modeline, &orig_modeline, sizeof(XF86VidModeModeLine)); + if (autoflag) + ApplyCallback(w, call_data, client_data); + SetLabels(); +} + +static void +SelectCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + XF86VidModeModeInfo *info = (XF86VidModeModeInfo*)call_data; + Arg args[1]; + Bool result; + + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, False); + result = XF86VidModeSwitchToMode(XtDisplay(toplevel), vidtune->screen, info); + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, True); + if (!result) + return; + + XtSetArg(args[0], XtNlabel, XtName(w)); + XtSetValues(mode, args, 1); + UpdateCallback(w, call_data, client_data); +} + +static void +SwitchCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + int direction = (long)call_data; + Arg args[1]; + Bool result; + char label[32]; + + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, False); + result = XF86VidModeSwitchMode(XtDisplay(toplevel), vidtune->screen, + direction); + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, True); + if (!result) + return; + + UpdateCallback(w, call_data, client_data); + + if (modeline.htotal && modeline.vtotal) + XmuSnprintf(label, sizeof(label), "%dx%d @ %d Hz", + modeline.hdisplay, modeline.vdisplay, + (int)((double)dot_clock / (double)modeline.htotal * 1000.0 / + (double)modeline.vtotal)); + else + XmuSnprintf(label, sizeof(label), "%dx%d", + modeline.hdisplay, modeline.vdisplay); + XtSetArg(args[0], XtNlabel, label); + XtSetValues(mode, args, 1); +} + +/*ARGSUSED*/ +static void +UpdateCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + GetModeLine(True); + SetLabels(); + SetLabelAndModeline(); +} + +static void +SetLabels(void) +{ + SetLabel(HSYNCSTART, modeline.hsyncstart); + SetLabel(VSYNCSTART, modeline.vsyncstart); + SetLabel(HSYNCEND, modeline.hsyncend); + SetLabel(VSYNCEND, modeline.vsyncend); + SetLabel(HTOTAL, modeline.htotal); + SetLabel(VTOTAL, modeline.vtotal); + SetLabel(FLAGS, modeline.flags); + SetLabel(CLOCK, dot_clock); + UpdateSyncRates(True); +} + +/*ARGSUSED*/ +static void +ChangeScreenCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + Arg args[1]; + + screenno = (long)call_data; + if (screenno > computer.num_vidmodes || screenno < 0 || + vidtune == computer.vidmodes[screenno]) + return; + + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, False); + vidtune = computer.vidmodes[screenno]; + XF86VidModeLockModeSwitch(XtDisplay(toplevel), vidtune->screen, True); + UpdateCallback(w, call_data, client_data); + GetModes(); + + XtSetArg(args[0], XtNlabel, XtName(w)); + XtSetValues(screenb, args, 1); + + SetLabelAndModeline(); +} + +/*ARGSUSED*/ +static void +SelectMonitorCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + vidtune->monitor = (XF86ConfMonitorPtr)(call_data); + SetLabelAndModeline(); +} + +/*ARGSUSED*/ +static void +AddVesaModeCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + xf86cfgVesaModeInfo *vesa = (xf86cfgVesaModeInfo*)call_data; + XF86VidModeModeInfo mode; + int num_infos = vidtune->num_infos; + + memcpy(&mode, &vesa->info, sizeof(XF86VidModeModeInfo)); + if (XF86VidModeAddModeLine(XtDisplay(toplevel), vidtune->screen, + &vesa->info, &mode)) { + XSync(XtDisplay(toplevel), False); + GetModes(); + } + else { + XBell(XtDisplayOfObject(w), 80); + return; + } + + if (vidtune && num_infos == vidtune->num_infos) { + /* XF86VidModeAddModeLine returned True, but no modeline was added */ + XBell(XtDisplayOfObject(w), 80); + if (vidtune->monitor && AddMode()) { + XF86ConfModeLinePtr mode; + char label[256], *ptr, *str; + + XmuSnprintf(label, sizeof(label), "%s", vesa->ident); + + /* format mode name to not have spaces */ + ptr = strchr(label, ')'); + if (ptr) + *++ptr = '\0'; + ptr = str = label; + while (*ptr) { + if (*ptr != ' ') + *str++ = *ptr; + ++ptr; + } + *str = '\0'; + + if (xf86findModeLine(label, vidtune->monitor->mon_modeline_lst) + != NULL && !ForceAddMode()) + return; + + mode = (XF86ConfModeLinePtr)XtCalloc(1, sizeof(XF86ConfModeLineRec)); + mode->ml_identifier = XtNewString(label); + mode->ml_clock = vesa->info.dotclock; + mode->ml_hdisplay = vesa->info.hdisplay; + mode->ml_hsyncstart = vesa->info.hsyncstart; + mode->ml_hsyncend = vesa->info.hsyncend; + mode->ml_htotal = vesa->info.htotal; + mode->ml_vdisplay = vesa->info.vdisplay; + mode->ml_vsyncstart = vesa->info.vsyncstart; + mode->ml_vsyncend = vesa->info.vsyncend; + mode->ml_vtotal = vesa->info.vtotal; +/* mode->ml_vscan = ???;*/ + mode->ml_flags = vesa->info.flags; + mode->ml_hskew = vesa->info.hskew; + vidtune->monitor->mon_modeline_lst = + xf86addModeLine(vidtune->monitor->mon_modeline_lst, mode); + } + } +} + +static void +GetModes(void) +{ + int i; + char label[32]; + Arg args[1]; + static char menuName[16]; + static int menuN; + + XFree(vidtune->infos); + XF86VidModeGetAllModeLines(XtDisplay(toplevel), vidtune->screen, + &vidtune->num_infos, &vidtune->infos); + + XmuSnprintf(menuName, sizeof(menuName), "menu%d", menuN); + menuN = !menuN; + if (menu) + XtDestroyWidget(menu); + menu = XtCreatePopupShell(menuName, simpleMenuWidgetClass, vtune, NULL, 0); + XtVaSetValues(mode, XtNmenuName, menuName, NULL); + for (i = 0; i < vidtune->num_infos; i++) { + Widget sme; + + if ((double)vidtune->infos[i]->htotal && + (double)vidtune->infos[i]->vtotal) + XmuSnprintf(label, sizeof(label), "%dx%d @ %d Hz", + vidtune->infos[i]->hdisplay, + vidtune->infos[i]->vdisplay, + (int)((double)vidtune->infos[i]->dotclock / + (double)vidtune->infos[i]->htotal * 1000.0 / + (double)vidtune->infos[i]->vtotal)); + else + XmuSnprintf(label, sizeof(label), "%dx%d", + vidtune->infos[i]->hdisplay, + vidtune->infos[i]->vdisplay); + sme = XtCreateManagedWidget(label, smeBSBObjectClass, menu, NULL, 0); + XtAddCallback(sme, XtNcallback, SelectCallback, + (XtPointer)vidtune->infos[i]); + } + + if (modeline.htotal && modeline.vtotal) + XmuSnprintf(label, sizeof(label), "%dx%d @ %d Hz", + modeline.hdisplay, modeline.vdisplay, + (int)((double)dot_clock / (double)modeline.htotal * 1000.0 / + (double)modeline.vtotal)); + else + XmuSnprintf(label, sizeof(label), "%dx%d", + modeline.hdisplay, modeline.vdisplay); + XtSetArg(args[0], XtNlabel, label); + XtSetValues(mode, args, 1); +} + +static int do_force, asking_force; + +static void +PopdownForce(Widget w, XtPointer user_data, XtPointer call_data) +{ + asking_force = 0; + XtPopdown(forceshell); + do_force = (long)user_data; +} + +static int +ForceAddMode(void) +{ + if (forceshell == NULL) { + Widget dialog; + + forceshell = XtCreatePopupShell("force", transientShellWidgetClass, + toplevel, NULL, 0); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, + forceshell, XtNvalue, NULL, NULL); + XawDialogAddButton(dialog, "yes", PopdownForce, (XtPointer)True); + XawDialogAddButton(dialog, "no", PopdownForce, (XtPointer)False); + XtRealizeWidget(forceshell); + XSetWMProtocols(DPY, XtWindow(forceshell), &wm_delete_window, 1); + } + + asking_force = 1; + + XtPopup(forceshell, XtGrabExclusive); + while (asking_force) + XtAppProcessEvent(XtWidgetToApplicationContext(forceshell), XtIMAll); + + return (do_force); +} + +static int do_add, asking_add; + +static void +PopdownAdd(Widget w, XtPointer user_data, XtPointer call_data) +{ + asking_add = 0; + XtPopdown(addshell); + do_add = (long)user_data; +} + +void +CancelAddModeAction(Widget w, XEvent *event, + String *params, Cardinal *num_params) +{ + if (asking_force) + PopdownForce(w, (XtPointer)False, NULL); + else if (asking_add) + PopdownAdd(w, (XtPointer)False, NULL); +} + +static int +AddMode(void) +{ + if (addshell == NULL) { + Widget dialog; + + addshell = XtCreatePopupShell("addMode", transientShellWidgetClass, + toplevel, NULL, 0); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, + addshell, XtNvalue, NULL, NULL); + XawDialogAddButton(dialog, "yes", PopdownAdd, (XtPointer)True); + XawDialogAddButton(dialog, "no", PopdownAdd, (XtPointer)False); + XtRealizeWidget(addshell); + XSetWMProtocols(DPY, XtWindow(addshell), &wm_delete_window, 1); + } + + asking_add = 1; + + XtPopup(addshell, XtGrabExclusive); + while (asking_add) + XtAppProcessEvent(XtWidgetToApplicationContext(addshell), XtIMAll); + + return (do_add); +} + +/*ARGSUSED*/ +static void +AddModeCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + if (vidtune && vidtune->monitor) { + char *label; + Arg args[1]; + XF86ConfModeLinePtr mode; + + XtSetArg(args[0], XtNstring, &label); + XtGetValues(text, args, 1); + if (*label == '\0') { + XBell(XtDisplay(w), 80); + return; + } + if (xf86findModeLine(label, vidtune->monitor->mon_modeline_lst) + != NULL && !ForceAddMode()) + return; + + mode = (XF86ConfModeLinePtr)XtCalloc(1, sizeof(XF86ConfModeLineRec)); + mode->ml_identifier = XtNewString(label); + mode->ml_clock = dot_clock; + mode->ml_hdisplay = modeline.hdisplay; + mode->ml_hsyncstart = modeline.hsyncstart; + mode->ml_hsyncend = modeline.hsyncend; + mode->ml_htotal = modeline.htotal; + mode->ml_vdisplay = modeline.vdisplay; + mode->ml_vsyncstart = modeline.vsyncstart; + mode->ml_vsyncend = modeline.vsyncend; + mode->ml_vtotal = modeline.vtotal; +/* mode->ml_vscan = ???;*/ + mode->ml_flags = modeline.flags; + mode->ml_hskew = modeline.hskew; + vidtune->monitor->mon_modeline_lst = + xf86addModeLine(vidtune->monitor->mon_modeline_lst, mode); + } + else + XBell(XtDisplay(w), 80); +} + +/*ARGSUSED*/ +static void +StopTestCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + XtRemoveTimeOut(timeout); + TestTimeout((XtPointer)w, NULL); +} + +/*ARGSUSED*/ +void +CancelTestModeAction(Widget w, XEvent *event, + String *params, Cardinal *num_params) +{ + StopTestCallback(w, NULL, NULL); +} + +static void +TestTimeout(XtPointer client_data, XtIntervalId* id) +{ + XF86VidModeModeLine mode; + + XtPopdown(testshell); + timeout = 0; + memcpy(&mode, &modeline, sizeof(XF86VidModeModeLine)); + memcpy(&modeline, &orig_modeline, sizeof(XF86VidModeModeLine)); + ApplyCallback((Widget)client_data, NULL, NULL); +/* if (hitError == 0)*/ + memcpy(&modeline, &mode, sizeof(XF86VidModeModeLine)); + SetLabels(); +} + +static void +TestCallback(Widget w, XtPointer call_data, XtPointer client_data) +{ + if (testshell == NULL) { + Widget dialog; + + testshell = XtCreatePopupShell("test", transientShellWidgetClass, + toplevel, NULL, 0); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, + testshell, XtNvalue, NULL, NULL); + XawDialogAddButton(dialog, "stop", StopTestCallback, NULL); + XtRealizeWidget(testshell); + XSetWMProtocols(DPY, XtWindow(testshell), &wm_delete_window, 1); + } + + XtPopup(testshell, XtGrabExclusive); + + XSync(XtDisplay(toplevel), False); + timeout = XtAppAddTimeOut(XtWidgetToApplicationContext(w), + /* the timeout probably shoud be converted to a resource */ + 4000, TestTimeout, (XtPointer)w); + ApplyCallback(w, call_data, client_data); +} |