diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:56 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:56 -0800 |
commit | fb518983907cf33ab8ee7e71ef79fe920b6b5a17 (patch) | |
tree | 16dd7342ea2734bcd6c0bafa23fae939af971f96 | |
parent | 429a78a02af06685581968d1be658f1fa33c2312 (diff) |
1.0-96261.0-9626
170 files changed, 32354 insertions, 3143 deletions
@@ -54,16 +54,16 @@ ifndef PKG_CONFIG PKG_CONFIG = pkg-config endif -ifndef X11R6_LIB_DIR +ifndef X11_LIB_DIRS ifeq ($(BUILD_OS)-$(BUILD_ARCH),Linux-x86_64) - X11R6_LIB_DIR = /usr/X11R6/lib64 + X11_LIB_DIRS = -L/usr/X11R6/lib64 else - X11R6_LIB_DIR = /usr/X11R6/lib + X11_LIB_DIRS = -L/usr/X11R6/lib endif endif -ifndef X11R6_INC_DIR - X11R6_INC_DIR = /usr/X11R6/include +ifndef X11_INC_DIRS + X11_INC_DIRS = -I/usr/X11R6/include endif # define local variables @@ -113,15 +113,18 @@ exec_prefix = $(prefix) bindir = $(exec_prefix)/bin mandir = $(exec_prefix)/share/man/man1 -X11R6_CFLAGS = -I $(X11R6_INC_DIR) +X11_CFLAGS = $(X11_INC_DIRS) GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk+-2.0) GTK_LDFLAGS := $(shell $(PKG_CONFIG) --libs gtk+-2.0) -X11R6_LIBS := -L $(X11R6_LIB_DIR) -Wl,-Bstatic -lXxf86vm -Wl,-Bdynamic -lX11 -lXext +X11_LIBS := $(X11_LIB_DIRS) -Wl,-Bstatic -lXxf86vm -Wl,-Bdynamic -lX11 -lXext XNVCTRL_LIB := src/libXNVCtrl/libXNVCtrl.a +XF86PARSER_LIB := src/XF86Config-parser/libXF86Config-parser.a +XF86PARSER_DIR := src/XF86Config-parser + CURDIR := $(shell pwd) RELATIVE_SRCDIRS = \ @@ -131,14 +134,17 @@ RELATIVE_SRCDIRS = \ src/xpm_data \ src/gtk+-2.x \ src/libXNVCtrl \ - src/libXNVCtrlAttributes + src/libXNVCtrlAttributes \ + src/XF86Config-parser \ + samples + SRCDIRS := $(addprefix $(CURDIR)/, $(RELATIVE_SRCDIRS)) INC_FLAGS := $(addprefix -I , $(RELATIVE_SRCDIRS)) -ALL_CFLAGS = $(CFLAGS) $(LOCAL_CFLAGS) $(X11R6_CFLAGS) $(GTK_CFLAGS) $(INC_FLAGS) -ALL_LDFLAGS = $(LD_RUN_FLAG) $(LDFLAGS) $(GTK_LDFLAGS) $(X11R6_LIBS) +ALL_CFLAGS = $(CFLAGS) $(LOCAL_CFLAGS) $(X11_CFLAGS) $(GTK_CFLAGS) $(INC_FLAGS) +ALL_LDFLAGS = $(LD_RUN_FLAG) $(LDFLAGS) $(GTK_LDFLAGS) $(X11_LIBS) CPPFLAGS = $(ALL_CFLAGS) @@ -154,18 +160,6 @@ STAMP_C = g_stamp.c MANPAGE = nvidia-settings.1 -# Define the files in the SAMPLES directory - -SAMPLES = \ - Makefile \ - nv-control-dpy.c \ - nv-control-dvc.c \ - nv-control-events.c \ - nv-control-info.c \ - nv-control-targets.c \ - nv-ddcci-client.c \ - nv-control-framelock.c \ - README # initialize SRC and EXTRA_DIST, then include each of the subdirectory # Makefiles so that they can append to SRC and EXTRA_DIST @@ -228,42 +222,32 @@ $(STAMP_C): $(filter-out $(OBJS_DIR)/$(STAMP_C:.c=.o), $(OBJS)) $(CC) $(CPPFLAGS) -E -dD $< | sed -e 's/^ $$//' > $@ indent -kr -nbbo -l96 -sob $@ +$(XF86PARSER_LIB): + $(MAKE) NV_CFLAGS='$(NV_CFLAGS)' -C $(XF86PARSER_DIR) -$(NVIDIA_SETTINGS): $(OBJS) $(XNVCTRL_LIB) - $(CC) $(OBJS) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(XNVCTRL_LIB) -o $@ +$(NVIDIA_SETTINGS): $(OBJS) $(XNVCTRL_LIB) $(XF86PARSER_LIB) + $(CC) $(OBJS) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(XNVCTRL_LIB) $(XF86PARSER_LIB) -o $@ -.PHONY: dist clean clobber +.PHONY: $(XF86PARSER_LIB) dist clean clobber dist: @ if [ -d $(NVIDIA_SETTINGS_DISTDIR) ]; then \ chmod 755 $(NVIDIA_SETTINGS_DISTDIR); \ fi - @ if [ -f $(NVIDIA_SETTINGS_DISTDIR).tar.gz ]; \ - then chmod 644 $(NVIDIA_SETTINGS_DISTDIR).tar.gz; \ + @ if [ -f $(NVIDIA_SETTINGS_DISTDIR).tar.gz ]; then \ + chmod 644 $(NVIDIA_SETTINGS_DISTDIR).tar.gz; \ fi rm -rf $(NVIDIA_SETTINGS_DISTDIR) $(NVIDIA_SETTINGS_DISTDIR).tar.gz mkdir -p $(NVIDIA_SETTINGS_DISTDIR_DIRS) - @ for i in $(SRC); do \ - b=`find . -name $$i`; \ - if [ $$b ]; then \ - cp $$b $(NVIDIA_SETTINGS_DISTDIR)/$$b ; \ - chmod 644 $(NVIDIA_SETTINGS_DISTDIR)/$$b ; \ - fi ; \ - done - @ for i in $(EXTRA_DIST); do \ - b=`find . -name $$i`; \ - if [ $$b ]; then \ - cp $$b $(NVIDIA_SETTINGS_DISTDIR)/$$b ; \ - chmod 644 $(NVIDIA_SETTINGS_DISTDIR)/$$b ; \ - fi ; \ - done - mkdir -p $(NVIDIA_SETTINGS_DISTDIR)/samples - @ for i in $(SAMPLES); do \ - cp samples/$$i $(NVIDIA_SETTINGS_DISTDIR)/samples/ ; \ - done - @ for i in COPYING Makefile doc/Makefile.inc `find src -name Makefile.inc`; do \ - cp $$i $(NVIDIA_SETTINGS_DISTDIR)/$$i ; \ - chmod 644 $(NVIDIA_SETTINGS_DISTDIR)/$$i ; \ + @ for inc_dir in $(RELATIVE_SRCDIRS) .; do \ + EXTRA_DIST=; \ + SRC=; \ + mkdir -p $(NVIDIA_SETTINGS_DISTDIR)/$$inc_dir; \ + for inc_file in `$(MAKE) --makefile $$inc_dir/Makefile.inc dist_list`; do \ + file="$$inc_dir/$$inc_file"; \ + cp $$file $(NVIDIA_SETTINGS_DISTDIR)/$$file; \ + chmod 644 $(NVIDIA_SETTINGS_DISTDIR)/$$file; \ + done; \ done tar czf $(NVIDIA_SETTINGS_DISTDIR).tar.gz $(NVIDIA_SETTINGS_DISTDIR) rm -rf $(NVIDIA_SETTINGS_DISTDIR) diff --git a/Makefile.inc b/Makefile.inc new file mode 100644 index 0000000..e3a8951 --- /dev/null +++ b/Makefile.inc @@ -0,0 +1,34 @@ +# +# nvidia-settings: A tool for configuring the NVIDIA X driver on Unix +# and Linux systems. +# +# Copyright (C) 2004 NVIDIA Corporation. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of Version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 +# of the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the: +# +# Free Software Foundation, Inc. +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# + +# +# Copyright and makefiles +# + +EXTRA_DIST += \ + Makefile.inc \ + Makefile \ + COPYING + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/doc/Makefile.inc b/doc/Makefile.inc index 564c2fa..253e3a6 100644 --- a/doc/Makefile.inc +++ b/doc/Makefile.inc @@ -26,6 +26,7 @@ # EXTRA_DIST += \ + Makefile.inc \ NV-CONTROL-API.txt \ FRAMELOCK.txt \ nvidia-settings-user-guide.txt \ @@ -37,3 +38,6 @@ doc/nvidia-settings.1: nvidia-settings.1.m4 $(M4) -D__HEADER__=$(AUTO_TEXT) \ -D__BUILD_OS__=$(BUILD_OS) \ $< > $@ + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/doc/nvidia-settings.1.m4 b/doc/nvidia-settings.1.m4 index 12fbe09..ae01609 100644 --- a/doc/nvidia-settings.1.m4 +++ b/doc/nvidia-settings.1.m4 @@ -9,12 +9,14 @@ __HEADER__ \\$2 \(la \\$1 \(ra\\$3 .. .if \n[.g] .mso www.tmac -.TH nvidia-settings 1 2006-03-17 "nvidia-settings 1.0" +.TH nvidia\-settings 1 2006-03-17 "nvidia\-settings 1.0" .SH NAME nvidia\-settings \- configure the NVIDIA graphics driver .SH SYNOPSIS .BI "nvidia\-settings [" "options" "]" .br +.BI "nvidia\-settings [" "options" "] \-\-no\-config" +.br .BI "nvidia\-settings [" "options" "] \-\-load\-config\-only" .br .BI "nvidia\-settings [" "options" "] {\-\-query=" attr " | \-\-assign=" attr = value "} ..." @@ -22,7 +24,9 @@ nvidia\-settings \- configure the NVIDIA graphics driver .BI "nvidia\-settings [" "options" "] \-\-glxinfo" .PP Options: -.BI "[-vh] [\-\-config=" configfile "] [\-c " ctrl-display ] +.BI "[-vh] [\-\-config=" configfile "] [\-c " ctrl-display "]" +.br +.I " \fB[\-\-verbose=\fP{\fIerrors \fP|\fI warnings \fP|\fI all\fP}\fB]" .PP .I attr has the form: @@ -59,7 +63,7 @@ Print usage information and exit. Use the configuration file .I config rather than the default -.I ~/.nvidia-settings-rc +.I ~/.nvidia\-settings\-rc .TP .BI "\-c, \-\-ctrl\-display=" ctrl-display Control the specified X display. @@ -71,10 +75,35 @@ If that is not given, then the .I $DISPLAY environment variable is used. .TP +.B \-n, \-\-no\-config +Do not load the configuration file. +This mode of operation is useful if +.B nvidia\-settings +has difficulties starting due to problems with applying settings in the configuration file. +.TP .B \-l, \-\-load\-config\-only Load the configuration file, send the values specified therein to the X server, and exit. This mode of operation is useful to place in your .xinitrc file, for example. .TP +.BI "\-V, \-\-verbose=" verbosity +Controls how much information is printed. +By default, the verbosity is +.B errors +and only error messages are printed. +.br + +.I verbosity +can be one of the following values: +.ti +5 +.B errors +- Print errors. +.ti +5 +.B warnings +- Print errors and warnings. +.ti +5 +.B all +- Print errors, warnings, and other information. +.TP .BI "\-a, \-\-assign=" assign The .I assign @@ -164,7 +193,7 @@ Print GLX Information for the X display and exit. .SS Contents 1. Layout of the nvidia\-settings GUI .br -2. How OpenGL Interacts with nvidia-settings +2. How OpenGL Interacts with nvidia\-settings .br 3. Loading Settings Automatically .br @@ -188,7 +217,7 @@ GUI. .PP The category list is organized in a tree: each X screen contains the relevant subcategories beneath it. Similarly, the Display Devices category for a screen contains all the enabled display devices beneath it. -Besides each X screen, the other top level category is "nvidia-settings Configuration", which configures behavior of the +Besides each X screen, the other top level category is "nvidia\-settings Configuration", which configures behavior of the .B nvidia\-settings application itself. .PP @@ -214,7 +243,7 @@ Notable exceptions are OpenGL options which are only read by OpenGL when an Open Details about the options on each page of .B nvidia\-settings are available in the help window. -.SS 2. How OpenGL Interacts with nvidia-settings +.SS 2. How OpenGL Interacts with nvidia\-settings .PP When an OpenGL application starts, it downloads the current values from the X driver, and then reads the environment (see .I APPENDIX E: OPENGL ENVIRONMENT VARIABLE SETTINGS @@ -256,7 +285,7 @@ After you have run once and have generated a configuration file, you can then run: .sp .ti +5 -nvidia-settings --load-config-only +nvidia\-settings \-\-load\-config\-only .sp at any time in the future to upload these settings to the X server again. For example, you might place the above command in your @@ -577,7 +606,8 @@ graphical interface. .TP .B nvidia\-settings \-\-load\-config\-only Loads the settings stored in -.I ~/.nvidia-settings-rc +.I ~/.nvidia\-settings\-rc +and exits. .TP .B nvidia\-settings \-\-query FSAA Query the value of the full-screen antialiasing setting. diff --git a/samples/Makefile.inc b/samples/Makefile.inc new file mode 100644 index 0000000..398fd03 --- /dev/null +++ b/samples/Makefile.inc @@ -0,0 +1,40 @@ +# +# nvidia-settings: A tool for configuring the NVIDIA X driver on Unix +# and Linux systems. +# +# Copyright (C) 2004 NVIDIA Corporation. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of Version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 +# of the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the: +# +# Free Software Foundation, Inc. +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# + +# +# Sample code +# + +EXTRA_DIST += \ + Makefile.inc \ + Makefile \ + README \ + nv-control-dvc.c \ + nv-control-dpy.c \ + nv-control-info.c \ + nv-control-events.c \ + nv-ddcci-client.c \ + nv-control-targets.c + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/samples/nv-control-dpy.c b/samples/nv-control-dpy.c index b37bfe7..f74d4ec 100644 --- a/samples/nv-control-dpy.c +++ b/samples/nv-control-dpy.c @@ -2,7 +2,7 @@ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix * and Linux systems. * - * Copyright (C) 2004 NVIDIA Corporation. + * Copyright (C) 2006 NVIDIA Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of Version 2 of the GNU General Public @@ -24,14 +24,17 @@ /* - * nv-control-dpy.c - NV-CONTROL client that demonstrates how to - * configure display devices using NV-CONTROL. + * nv-control-dpy.c - This sample NV-CONTROL client demonstrates how + * to configure display devices using NV-CONTROL. This client + * demonstrates many different pieces of display configuration + * functionality, controlled through commandline options. */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <X11/Xlib.h> @@ -39,45 +42,13 @@ #include "NVCtrlLib.h" - - -/* - * display_device_name() - return the display device name correspoding - * to the display device mask. - */ - -char *display_device_name(int mask) -{ - switch (mask) { - case (1 << 0): return "CRT-0"; break; - case (1 << 1): return "CRT-1"; break; - case (1 << 2): return "CRT-2"; break; - case (1 << 3): return "CRT-3"; break; - case (1 << 4): return "CRT-4"; break; - case (1 << 5): return "CRT-5"; break; - case (1 << 6): return "CRT-6"; break; - case (1 << 7): return "CRT-7"; break; - - case (1 << 8): return "TV-0"; break; - case (1 << 9): return "TV-1"; break; - case (1 << 10): return "TV-2"; break; - case (1 << 11): return "TV-3"; break; - case (1 << 12): return "TV-4"; break; - case (1 << 13): return "TV-5"; break; - case (1 << 14): return "TV-6"; break; - case (1 << 15): return "TV-7"; break; - - case (1 << 16): return "DFP-0"; break; - case (1 << 17): return "DFP-1"; break; - case (1 << 18): return "DFP-2"; break; - case (1 << 19): return "DFP-3"; break; - case (1 << 20): return "DFP-4"; break; - case (1 << 21): return "DFP-5"; break; - case (1 << 22): return "DFP-6"; break; - case (1 << 23): return "DFP-7"; break; - default: return "Unknown"; - } -} /* display_device_name() */ +static char *display_device_name(int mask); +static unsigned int display_device_mask(char *str); +static char *remove_whitespace(char *str); +static int count_bits(unsigned int mask); +static void parse_mode_string(char *modeString, char **modeName, int *mask); +static char *find_modeline(char *modeString, char *pModeLines, + int ModeLineLen); @@ -87,10 +58,11 @@ int main(int argc, char *argv[]) Display *dpy; Bool ret; int screen, display_devices, mask, major, minor, len, j; - char *str, *start; + char *str, *start, *str0, *str1; char *displayDeviceNames[8]; int nDisplayDevice; + /* * Open a display connection, and make sure the NV-CONTROL X * extension is present on the screen we want to use. @@ -98,7 +70,7 @@ int main(int argc, char *argv[]) dpy = XOpenDisplay(NULL); if (!dpy) { - fprintf(stderr, "Cannot open display '%s'.\n", XDisplayName(NULL)); + fprintf(stderr, "Cannot open display '%s'.\n\n", XDisplayName(NULL)); return 1; } @@ -106,42 +78,44 @@ int main(int argc, char *argv[]) if (!XNVCTRLIsNvScreen(dpy, screen)) { fprintf(stderr, "The NV-CONTROL X not available on screen " - "%d of '%s'.\n", screen, XDisplayName(NULL)); + "%d of '%s'.\n\n", screen, XDisplayName(NULL)); return 1; } ret = XNVCTRLQueryVersion(dpy, &major, &minor); if (ret != True) { - fprintf(stderr, "The NV-CONTROL X extension does not exist on '%s'.\n", - XDisplayName(NULL)); + fprintf(stderr, "The NV-CONTROL X extension does not exist " + "on '%s'.\n\n", XDisplayName(NULL)); return 1; } + + printf("\nUsing NV-CONTROL extension %d.%d on %s\n", + major, minor, XDisplayName(NULL)); + + /* + * query the connected display devices on this X screen and print + * basic information about each X screen + */ + ret = XNVCTRLQueryAttribute(dpy, screen, 0, - NV_CTRL_ENABLED_DISPLAYS, &display_devices); + NV_CTRL_CONNECTED_DISPLAYS, &display_devices); if (!ret) { - fprintf(stderr, "Failed to query the enabled Display Devices.\n"); + fprintf(stderr, "Failed to query the enabled Display Devices.\n\n"); return 1; } - /* print basic information about what display devices are present */ - - - printf("\n"); - printf("Using NV-CONTROL extension %d.%d on %s\n", - major, minor, XDisplayName(NULL)); - printf("Display Devices:\n"); + printf("Connected Display Devices:\n"); nDisplayDevice = 0; for (mask = 1; mask < (1 << 24); mask <<= 1) { - + if (display_devices & mask) { - XNVCTRLQueryStringAttribute - (dpy, screen, mask, - NV_CTRL_STRING_DISPLAY_DEVICE_NAME, - &str); + XNVCTRLQueryStringAttribute(dpy, screen, mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &str); displayDeviceNames[nDisplayDevice++] = str; @@ -149,50 +123,236 @@ int main(int argc, char *argv[]) display_device_name(mask), mask, str); } } - printf("\n"); - /* now, parse the commandline and perform the requested action */ + + /* + * perform the requested action, based on the specified + * commandline option + */ + + if (argc <= 1) goto printHelp; - if (argc <= 1) goto printHelp; + /* + * for each connected display device on this X screen, query the + * list of modelines in the mode pool using + * NV_CTRL_BINARY_DATA_MODELINES, then print the results + */ - if (strcmp(argv[1], "-l") == 0) { - - /* get list of modelines, per display device */ + if (strcmp(argv[1], "--print-modelines") == 0) { nDisplayDevice = 0; for (mask = 1; mask < (1 << 24); mask <<= 1) { - if (display_devices & mask) { - - XNVCTRLQueryBinaryData(dpy, screen, mask, - NV_CTRL_BINARY_DATA_MODELINES, - (void *) &str, &len); + if (!(display_devices & mask)) continue; + + ret = XNVCTRLQueryBinaryData(dpy, screen, mask, + NV_CTRL_BINARY_DATA_MODELINES, + (void *) &str, &len); - printf("Modelines for %s:\n", - displayDeviceNames[nDisplayDevice++]); + if (!ret) { + fprintf(stderr, "Failed to query ModeLines.\n\n"); + return 1; + } + + /* + * the returned data is in the form: + * + * "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0" + * + * so walk from one "\0" to the next to print each ModeLine. + */ + + printf("Modelines for %s:\n", + displayDeviceNames[nDisplayDevice++]); - start = str; - for (j = 0; j < len; j++) { - if (str[j] == '\0') { - printf(" %s\n", start); - start = &str[j+1]; + start = str; + for (j = 0; j < len; j++) { + if (str[j] == '\0') { + printf(" %s\n", start); + start = &str[j+1]; } - } + } + + XFree(str); + } + } + + + /* + * for each connected display device on this X screen, query the + * current modeline using NV_CTRL_STRING_CURRENT_MODELINE + */ + + else if (strcmp(argv[1], "--print-current-modeline") == 0) { + + nDisplayDevice = 0; + + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (!(display_devices & mask)) continue; + + ret = + XNVCTRLQueryStringAttribute(dpy, screen, mask, + NV_CTRL_STRING_CURRENT_MODELINE, + &str); - XFree(str); + if (!ret) { + fprintf(stderr, "Failed to query current ModeLine.\n\n"); + return 1; } + + printf("Current Modeline for %s:\n", + displayDeviceNames[nDisplayDevice++]); + printf(" %s\n\n", str); + } + } + + + /* + * add the specified modeline to the mode pool for the specified + * display device, using NV_CTRL_STRING_ADD_MODELINE + */ + + else if ((strcmp(argv[1], "--add-modeline") == 0) && + argv[2] && argv[3]) { + + mask = strtol(argv[2], NULL, 0); + + ret = XNVCTRLSetStringAttribute(dpy, + screen, + mask, + NV_CTRL_STRING_ADD_MODELINE, + argv[3]); + + if (!ret) { + fprintf(stderr, "Failed to add the modeline \"%s\" to %s's " + "mode pool.\n\n", argv[3], display_device_name(mask)); + return 1; + } + + printf("Added modeline \"%s\" to %s's mode pool.\n\n", + argv[3], display_device_name(mask)); + } + + + /* + * delete the specified modeline from the mode pool for the + * specified display device, using NV_CTRL_STRING_DELETE_MODELINE + */ + + else if ((strcmp(argv[1], "--delete-modeline") == 0) && + argv[2] && argv[3]) { + + mask = strtol(argv[2], NULL, 0); + + ret = XNVCTRLSetStringAttribute(dpy, + screen, + mask, + NV_CTRL_STRING_DELETE_MODELINE, + argv[3]); + + if (!ret) { + fprintf(stderr, "Failed to delete the mode \"%s\" from %s's " + "mode pool.\n\n", argv[3], display_device_name(mask)); + return 1; } - } else if (strcmp(argv[1], "-m") == 0) { + printf("Deleted modeline \"%s\" from %s's mode pool.\n\n", + argv[3], display_device_name(mask)); + } + + + /* + * generate a GTF modeline using NV_CTRL_STRING_OPERATION_GTF_MODELINE + */ + + else if ((strcmp(argv[1], "--generate-gtf-modeline") == 0) && + argv[2] && argv[3] && argv[4]) { + + char pGtfString[128]; + char *pOut; + + snprintf(pGtfString, 128, "width=%s, height=%s, refreshrate=%s", + argv[2], argv[3], argv[4]); + + ret = XNVCTRLStringOperation(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + 0, + NV_CTRL_STRING_OPERATION_GTF_MODELINE, + pGtfString, + &pOut); + + if (!ret) { + fprintf(stderr, "Failed to generate GTF ModeLine from " + "\"%s\".\n\n", pGtfString); + return 1; + } + + printf("GTF ModeLine from \"%s\": %s\n\n", pGtfString, pOut); + } + + + /* + * generate a CVT modeline using NV_CTRL_STRING_OPERATION_CVT_MODELINE + */ + + else if ((strcmp(argv[1], "--generate-cvt-modeline") == 0) && + argv[2] && argv[3] && argv[4] && argv[5]) { + + char pCvtString[128]; + char *pOut; + + snprintf(pCvtString, 128, "width=%s, height=%s, refreshrate=%s, " + "reduced-blanking=%s", + argv[2], argv[3], argv[4], argv[5]); + + ret = XNVCTRLStringOperation(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + 0, + NV_CTRL_STRING_OPERATION_CVT_MODELINE, + pCvtString, + &pOut); + + if (!ret) { + fprintf(stderr, "Failed to generate CVT ModeLine from " + "\"%s\".\n\n", pCvtString); + return 1; + } + + printf("CVT ModeLine from \"%s\": %s\n\n", pCvtString, pOut); + } + + + /* + * query the MetaModes for the X screen, using + * NV_CTRL_BINARY_DATA_METAMODES. + */ + + else if (strcmp(argv[1], "--print-metamodes") == 0) { /* get list of metamodes */ - XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a - NV_CTRL_BINARY_DATA_METAMODES, - (void *) &str, &len); + ret = XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a + NV_CTRL_BINARY_DATA_METAMODES, + (void *) &str, &len); + + if (!ret) { + fprintf(stderr, "Failed to query MetaModes.\n\n"); + return 1; + } + + /* + * the returned data is in the form: + * + * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" + * + * so walk from one "\0" to the next to print each MetaMode. + */ printf("MetaModes:\n"); @@ -205,24 +365,97 @@ int main(int argc, char *argv[]) } XFree(str); - - } else if ((strcmp(argv[1], "-M") == 0) && (argv[2])) { + } + + + /* + * query the currently in use MetaMode. Note that an alternative + * way to accomplish this is to use XRandR to query the current + * mode's refresh rate, and then match the refresh rate to the id + * reported in the returned NV_CTRL_BINARY_DATA_METAMODES data. + */ + + else if (strcmp(argv[1], "--print-current-metamode") == 0) { - ret = XNVCTRLSetStringAttribute(dpy, - screen, - 0, - NV_CTRL_STRING_ADD_METAMODE, - argv[2]); + ret = XNVCTRLQueryStringAttribute(dpy, screen, mask, + NV_CTRL_STRING_CURRENT_METAMODE, + &str); + + if (!ret) { + fprintf(stderr, "Failed to query the current MetaMode.\n\n"); + return 1; + } + + printf("current metamode: \"%s\"\n\n", str); + } + + + /* + * add the given MetaMode to X screen's list of MetaModes, using + * NV_CTRL_STRING_OPERATION_ADD_METAMODE; example MetaMode string: + * + * "nvidia-auto-select, nvidia-auto-select" + * + * The output string will contain "id=#" which indicates the + * unique identifier for this MetaMode. You can then use XRandR + * to switch to this mode by matching the identifier with the + * refresh rate reported via XRandR. + * + * For example: + * + * $ ./nv-control-dpy --add-metamode \ + * "nvidia-auto-select, nvidia-auto-select" + * + * Using NV-CONTROL extension 1.12 on :0 + * Connected Display Devices: + * CRT-0 (0x00000001): EIZO F931 + * CRT-1 (0x00000002): ViewSonic P815-4 + * + * Added MetaMode "nvidia-auto-select, nvidia-auto-select"; + * pOut: "id=52" + * + * $ xrandr -q + * SZ: Pixels Physical Refresh + * 0 3200 x 1200 ( 821mm x 302mm ) 51 52 + * *1 1600 x 600 ( 821mm x 302mm ) *50 + * Current rotation - normal + * Current reflection - none + * Rotations possible - normal + * Reflections possible - none + * + * $ xrandr -s 0 -r 52 + */ + + else if ((strcmp(argv[1], "--add-metamode") == 0) && (argv[2])) { + + char *pOut; + + ret = XNVCTRLStringOperation(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + 0, + NV_CTRL_STRING_OPERATION_ADD_METAMODE, + argv[2], + &pOut); if (!ret) { - fprintf(stderr, "Failed to add the MetaMode.\n"); + fprintf(stderr, "Failed to add the MetaMode \"%s\".\n\n", + argv[2]); return 1; } - printf("Uploaded MetaMode \"%s\"; magicID: %d\n", - argv[2], ret); + printf("Added MetaMode \"%s\"; pOut: \"%s\"\n\n", argv[2], pOut); + + XFree(pOut); + } + + + /* + * delete the given MetaMode from the X screen's list of + * MetaModes, using NV_CTRL_STRING_DELETE_METAMODE + */ - } else if ((strcmp(argv[1], "-D") == 0) && (argv[1])) { + else if ((strcmp(argv[1], "--delete-metamode") == 0) && (argv[1])) { ret = XNVCTRLSetStringAttribute(dpy, screen, @@ -231,51 +464,152 @@ int main(int argc, char *argv[]) argv[2]); if (!ret) { - fprintf(stderr, "Failed to delete the MetaMode.\n"); + fprintf(stderr, "Failed to delete the MetaMode.\n\n"); return 1; } - } else if (strcmp(argv[1], "-c") == 0) { + printf("Deleted MetaMode \"%s\".\n\n", argv[2]); + } + + + /* + * query the valid frequency ranges for each display device, using + * NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES and + * NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES + */ + + else if (strcmp(argv[1], "--get-valid-freq-ranges") == 0) { - ret = XNVCTRLQueryStringAttribute - (dpy, screen, mask, - NV_CTRL_STRING_CURRENT_METAMODE, - &str); + nDisplayDevice = 0; - if (!ret) { - fprintf(stderr, "Failed to query the current MetaMode.\n"); - return 1; + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (!(display_devices & mask)) continue; + + ret = XNVCTRLQueryStringAttribute + (dpy, screen, mask, + NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES, + &str0); + + if (!ret) { + fprintf(stderr, "Failed to query HorizSync for %s.\n\n", + display_device_name(mask)); + return 1; + } + + + ret = XNVCTRLQueryStringAttribute + (dpy, screen, mask, + NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES, + &str1); + + if (!ret) { + fprintf(stderr, "Failed to query VertRefresh for %s.\n\n", + display_device_name(mask)); + return 1; + } + + printf("frequency information for %s:\n", + displayDeviceNames[nDisplayDevice++]); + printf(" HorizSync : \"%s\"\n", str0); + printf(" VertRefresh : \"%s\"\n\n", str1); + + XFree(str0); + XFree(str1); } + } + + + /* + * attempt to build the modepool for each display device; this + * will fail for any display device that already has a modepool + */ + + else if (strcmp(argv[1], "--build-modepool") == 0) { - printf("current metamode: \"%s\"\n", str); + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (!(display_devices & mask)) continue; + + ret = XNVCTRLStringOperation + (dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + mask, + NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL, + argv[2], + &str0); + + if (!ret) { + fprintf(stderr, "Failed to build modepool for %s (it most " + "likely already has a modepool).\n\n", + display_device_name(mask)); + } else { + printf("Built modepool for %s.\n\n", + display_device_name(mask)); + } + } + } - } else if ((strcmp(argv[1], "-L") == 0) && argv[2] && argv[3]) { + + /* + * query the associated display devices on this X screen; these + * are the display devices that are available to the X screen for + * use by MetaModes. + */ + + else if (strcmp(argv[1], "--get-associated-dpys") == 0) { - ret = XNVCTRLSetStringAttribute(dpy, - screen, - strtol(argv[2], NULL, 0), - NV_CTRL_STRING_ADD_MODELINE, - argv[3]); + ret = XNVCTRLQueryAttribute(dpy, + screen, + 0, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + &mask); - if (!ret) { - fprintf(stderr, "Failed to add the modeline \"%s\".\n", argv[3]); + if (ret) { + printf("associated display device mask: 0x%08x\n\n", mask); + } else { + fprintf(stderr, "failed to query the associated display device " + "mask.\n\n"); return 1; } - - } else if ((strcmp(argv[1], "-d") == 0) && argv[2] && argv[3]) { - ret = XNVCTRLSetStringAttribute(dpy, - screen, - strtol(argv[2], NULL, 0), - NV_CTRL_STRING_DELETE_MODELINE, - argv[3]); + } + + + /* + * assign the associated display device mask for this X screen; + * these are the display devices that are available to the X + * screen for use by MetaModes. + */ + + else if ((strcmp(argv[1], "--set-associated-dpys") == 0) && (argv[2])) { + + mask = strtol(argv[2], NULL, 0); + + ret = XNVCTRLSetAttributeAndGetStatus + (dpy, + screen, + 0, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + mask); - if (!ret) { - fprintf(stderr, "Failed to delete the mode \"%s\".\n", argv[3]); + if (ret) { + printf("set the associated display device mask to 0x%08x\n\n", + mask); + } else { + fprintf(stderr, "failed to set the associated display device " + "mask to 0x%08x\n\n", mask); return 1; } - - } else if (strcmp(argv[1], "-g") == 0) { + } + + + /* + * query information about the GPUs in the system + */ + + else if (strcmp(argv[1], "--query-gpus") == 0) { int num_gpus, num_screens, i; unsigned int *pData; @@ -283,17 +617,20 @@ int main(int argc, char *argv[]) printf("GPU Information:\n"); /* Get the number of gpus in the system */ - ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, &num_gpus); + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, + &num_gpus); if (!ret) { - fprintf(stderr, "Failed to query number of gpus\n"); + fprintf(stderr, "Failed to query number of gpus.\n\n"); return 1; } - printf("\n"); printf(" number of GPUs: %d\n", num_gpus); /* List the X screen number of all X screens driven by each gpu */ + for (i = 0; i < num_gpus; i++) { + ret = XNVCTRLQueryTargetBinaryData (dpy, NV_CTRL_TARGET_TYPE_GPU, @@ -302,16 +639,17 @@ int main(int argc, char *argv[]) NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU, (unsigned char **) &pData, &len); + if (!ret) { fprintf(stderr, "Failed to query list of X Screens\n"); return 1; } printf(" number of X screens using GPU %d: %d\n", i, pData[0]); - + /* List X Screen number of all X Screens driven by this GPU. */ - - printf(" X screens using GPU %d: ", i); + + printf(" Indices of X screens using GPU %d: ", i); for (j = 1; j <= pData[0]; j++) { printf(" %d", pData[j]); @@ -326,19 +664,22 @@ int main(int argc, char *argv[]) * where as querying the screen count information from * NV-CONTROL will return the number of underlying X Screens. */ + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, &num_screens); if (!ret) { - fprintf(stderr, "Failed to query number of X Screens\n"); + fprintf(stderr, "Failed to query number of X Screens\n\n"); return 1; } printf("\n"); - printf(" number of X screens (ScreenCount): %d\n", ScreenCount(dpy)); - printf("\n"); - printf(" number of X screens (NV-CONTROL): %d\n", num_screens); + printf(" number of X screens (ScreenCount): %d\n", + ScreenCount(dpy)); + printf(" number of X screens (NV-CONTROL): %d\n\n", + num_screens); for (i = 0; i < num_screens; i++) { + ret = XNVCTRLQueryTargetBinaryData (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, @@ -347,16 +688,18 @@ int main(int argc, char *argv[]) NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, (unsigned char **) &pData, &len); + if (!ret) { - fprintf(stderr, "Failed to query list of gpus\n"); + fprintf(stderr, "Failed to query list of gpus\n\n"); return 1; } - printf(" number of GPUs used by X screen %d: %d\n", i, pData[0]); + printf(" number of GPUs used by X screen %d: %d\n", i, + pData[0]); /* List gpu number of all gpus driven by this X screen */ - printf(" GPUs used by X screen %d: ", i); + printf(" Indices of GPUs used by X screen %d: ", i); for (j = 1; j <= pData[0]; j++) { printf(" %d", pData[j]); } @@ -364,26 +707,771 @@ int main(int argc, char *argv[]) } printf("\n"); - - } else { + + } + + + /* + * probe for any newly connected display devices + */ + + else if (strcmp(argv[1], "--probe-dpys") == 0) { + + int num_gpus, i; + + printf("Display Device Probed Information:\n\n"); + + /* Get the number of gpus in the system */ - printHelp: + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, + &num_gpus); + + if (!ret) { + fprintf(stderr, "Failed to query number of gpus\n\n"); + return 1; + } + + printf(" number of GPUs: %d\n", num_gpus); + + /* Probe and list the Display devices */ + + for (i = 0; i < num_gpus; i++) { + + /* Get the gpu name */ + + ret = XNVCTRLQueryTargetStringAttribute + (dpy, NV_CTRL_TARGET_TYPE_GPU, i, 0, + NV_CTRL_STRING_PRODUCT_NAME, &str); + + if (!ret) { + fprintf(stderr, "Failed to query gpu name\n\n"); + return 1; + } + + /* Probe the GPU for new/old display devices */ + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_GPU, i, + 0, + NV_CTRL_PROBE_DISPLAYS, + &display_devices); + + if (!ret) { + fprintf(stderr, "Failed to probe the enabled Display " + "Devices on GPU-%d (%s).\n\n", i, str); + return 1; + } + + printf(" display devices on GPU-%d (%s):\n", i, str); + XFree(str); + + /* Report results */ + + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (display_devices & mask) { + + XNVCTRLQueryTargetStringAttribute + (dpy, NV_CTRL_TARGET_TYPE_GPU, i, mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &str); + + printf(" %s (0x%08x): %s\n", + display_device_name(mask), mask, str); + } + } + + printf("\n"); + } - printf("usage:\n"); - printf("-l: print the modelines in the ModePool " - "for each Display Device.\n"); - printf("-L [dpy mask] [modeline]: add new modeline.\n"); - printf("-d [dpy mask] [modename]: delete modeline with modename\n"); - printf("-m: print the current MetaModes\n"); - printf("-M [metamode]: add the specified MetaMode to the " - "server's list of MetaModes.\n"); - printf("-D [metamode]: delete the specified MEtaMode from the " - "server's list of MetaModes.\n"); - printf("-c: print the current MetaMode\n"); - printf("-g: print GPU information\n"); printf("\n"); } + + + /* + * query the TwinViewXineramaInfoOrder + */ + + else if (strcmp(argv[1], "--query-twinview-xinerama-info-order") == 0) { + + ret = XNVCTRLQueryTargetStringAttribute + (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, + NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER, &str); + + if (!ret) { + fprintf(stderr, "Failed to query " + "TwinViewXineramaInfoOrder.\n\n"); + return 1; + } + + printf("TwinViewXineramaInfoOrder: %s\n\n", str); + } + + + /* + * assign the TwinViewXineramaInfoOrder + */ + + else if ((strcmp(argv[1], "--assign-twinview-xinerama-info-order")== 0) + && argv[2]) { + + ret = XNVCTRLSetStringAttribute + (dpy, + screen, + 0, + NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER, + argv[2]); + + if (!ret) { + fprintf(stderr, "Failed to assign " + "TwinViewXineramaInfoOrder = \"%s\".\n\n", argv[2]); + return 1; + } + + printf("assigned TwinViewXineramaInfoOrder: \"%s\"\n\n", + argv[2]); + } + + + /* + * use NV_CTRL_MAX_SCREEN_WIDTH and NV_CTRL_MAX_SCREEN_HEIGHT to + * query the maximum screen dimensions on each GPU in the system + */ + + else if (strcmp(argv[1], "--max-screen-size") == 0) { + + int num_gpus, i, width, height; + + /* Get the number of gpus in the system */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, + &num_gpus); + if (!ret) { + fprintf(stderr, "Failed to query number of gpus.\n\n"); + return 1; + } + + for (i = 0; i < num_gpus; i++) { + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_GPU, + i, + 0, + NV_CTRL_MAX_SCREEN_WIDTH, + &width); + + if (!ret) { + fprintf(stderr, "Failed to query the maximum screen " + "width on GPU-%d\n\n", i); + return 1; + } + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_GPU, + i, + 0, + NV_CTRL_MAX_SCREEN_HEIGHT, + &height); + + if (!ret) { + fprintf(stderr, "Failed to query the maximum screen " + "height on GPU-%d.\n\n", i); + return 1; + } + + printf("GPU-%d: maximum X screen size: %d x %d.\n\n", + i, width, height); + } + } + + + /* + * demonstrate how to use NV-CONTROL to query what modelines are + * used by the MetaModes of the X screen: we first query all the + * MetaModes, parse out the display device names and mode names, + * and then lookup the modelines associated with those mode names + * on those display devices + * + * this could be implemented much more efficiently, but + * demonstrates the general idea + */ + + else if (strcmp(argv[1], "--print-used-modelines") == 0) { + + char *pMetaModes, *pModeLines[8], *tmp, *modeString; + char *modeLine, *modeName, *noWhiteSpace; + int MetaModeLen, ModeLineLen[8]; + unsigned int thisMask; + + /* first, we query the MetaModes on this X screen */ + + XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a + NV_CTRL_BINARY_DATA_METAMODES, + (void *) &pMetaModes, &MetaModeLen); + + /* + * then, we query the ModeLines for each display device on + * this X screen; we'll need these later + */ + + nDisplayDevice = 0; + + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (!(display_devices & mask)) continue; + + XNVCTRLQueryBinaryData(dpy, screen, mask, + NV_CTRL_BINARY_DATA_MODELINES, + (void *) &str, &len); + + pModeLines[nDisplayDevice] = str; + ModeLineLen[nDisplayDevice] = len; + + nDisplayDevice++; + } + + /* now, parse each MetaMode */ + + str = start = pMetaModes; + + for (j = 0; j < MetaModeLen; j++) { + + /* + * if we found the end of a line, treat the string from + * start to str[j] as a MetaMode + */ + + if ((str[j] == '\0') && (str[j+1] != '\0')) { + + printf("MetaMode: %s\n", start); + + /* + * remove any white space from the string to make + * parsing easier + */ + + noWhiteSpace = remove_whitespace(start); + + /* + * the MetaMode may be preceded with "token=value" + * pairs, separated by the main MetaMode with "::"; if + * "::" exists in the string, skip past it + */ + + tmp = strstr(noWhiteSpace, "::"); + if (tmp) { + tmp += 2; + } else { + tmp = noWhiteSpace; + } + + /* split the MetaMode string by comma */ + + for (modeString = strtok(tmp, ","); + modeString; + modeString = strtok(NULL, ",")) { + + /* + * retrieve the modeName and display device mask + * for this segment of the Metamode + */ + + parse_mode_string(modeString, &modeName, &thisMask); + + /* lookup the modeline that matches */ + + nDisplayDevice = 0; + + if (thisMask) { + for (mask = 1; mask < (1 << 24); mask <<= 1) { + if (!(display_devices & mask)) continue; + if (thisMask & mask) break; + nDisplayDevice++; + } + } + + + modeLine = find_modeline(modeName, + pModeLines[nDisplayDevice], + ModeLineLen[nDisplayDevice]); + + printf(" %s: %s\n", + display_device_name(thisMask), modeLine); + } + + printf("\n"); + + free(noWhiteSpace); + + /* move to the next MetaMode */ + + start = &str[j+1]; + } + } + } + + + /* + * demonstrate how to programmatically transition into TwinView + * using NV-CONTROL and XRandR; the process is roughly: + * + * - probe for new display devices + * + * - if we found any new display devices, create a mode pool for + * the new display devices + * + * - associate any new display devices to the X screen, so that + * they are available for MetaMode assignment. + * + * - add a new MetaMode + * + * We have skipped error checking, and checking for things like if + * we are already using multiple display devices, but this gives + * the general idea. + */ + + else if (strcmp(argv[1], "--dynamic-twinview") == 0) { + + char *pOut; + int id; + + /* + * first, probe for new display devices; while + * NV_CTRL_CONNECTED_DISPLAYS reports what the NVIDIA X driver + * believes is currently connected to the GPU, + * NV_CTRL_PROBE_DISPLAYS forces the driver to redetect what + * is connected. + */ + + XNVCTRLQueryAttribute(dpy, + screen, + 0, + NV_CTRL_PROBE_DISPLAYS, + &display_devices); + + /* + * if we don't have atleast two display devices, there is + * nothing to do + */ + + printf("probed display device mask: 0x%08x\n\n", display_devices); + + if (count_bits(display_devices) < 2) { + printf("only one display device found; cannot enable " + "TwinView.\n\n"); + return 1; + } + + + /* + * next, make sure all display devices have a modepool; a more + * sophisticated client could use + * NV_CTRL_BINARY_DATA_MODELINES to query if a pool of + * modelines already exist on each display device we care + * about. + */ + + for (mask = 1; mask < (1 << 24); mask <<= 1) { + + if (!(display_devices & mask)) continue; + + XNVCTRLStringOperation(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + mask, + NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL, + NULL, + NULL); + } + + printf("all display devices should now have a mode pool.\n\n"); + + + /* + * associate all the probed display devices to the X screen; + * this makes the display devices available for MetaMode + * assignment + */ + + ret = + XNVCTRLSetAttributeAndGetStatus(dpy, + screen, + 0, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + display_devices); + + if (!ret) { + printf("unable to assign the associated display devices to " + "0x%08x.\n\n", display_devices); + return 1; + } + + printf("associated display devices 0x%08x.\n\n", display_devices); + + + /* + * next, we add a new MetaMode; a more sophisticated client + * would actually select a modeline from + * NV_CTRL_BINARY_DATA_MODELINES on each display device, but + * for demonstration purposes, we assume that + * "nvidia-auto-select" is a valid mode on each display + * device. + */ + + pOut = NULL; + + ret = XNVCTRLStringOperation(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, + 0, + NV_CTRL_STRING_OPERATION_ADD_METAMODE, + "nvidia-auto-select, nvidia-auto-select", + &pOut); + + if (!ret || !pOut) { + printf("failed to add MetaMode; this may be because the MetaMode " + "already exists for this X screen.\n\n"); + return 1; + } + + /* + * retrieve the id of the added MetaMode from the return + * string; a more sophisticated client should do actual + * parsing of the returned string, which is defined to be a + * comma-separated list of "token=value" pairs as output. + * Currently, the only output token is "id", which indicates + * the id that was assigned to the MetaMode. + */ + + sscanf(pOut, "id=%d", &id); + + XFree(pOut); + + + /* + * we have added a new MetaMode for this X screen, and we know + * it's id. The last step is to use the XRandR extension to + * switch to this mode; see the Xrandr(3) manpage for details. + * + * For demonstration purposes, just use the xrandr commandline + * utility to switch to the mode with the refreshrate that + * matches the id. + */ + + printf("The id of the new MetaMode is %d; use xrandr to " + "switch to it.\n\n", id); + } + + + /* + * print help information + */ + + else { + + printHelp: + + printf("\nnv-control-dpy [options]:\n\n"); + + + printf(" ModeLine options:\n\n"); + + printf(" --print-modelines: print the modelines in the mode pool " + "for each Display Device.\n\n"); + + printf(" --print-current-modeline: print the current modeline " + "for each Display Device.\n\n"); + + printf(" --add-modeline [dpy mask] [modeline]: " + "add new modeline.\n\n"); + + printf(" --delete-modeline [dpy mask] [modename]: " + "delete modeline with modename.\n\n"); + + printf(" --generate-gtf-modeline [width] [height] [refreshrate]:" + " use the GTF formula" + " to generate a modeline for the specified parameters.\n\n"); + + printf(" --generate-cvt-modeline [width] [height] [refreshrate]" + " [reduced-blanking]: use the CVT formula" + " to generate a modeline for the specified parameters.\n\n"); + + + printf(" MetaMode options:\n\n"); + + printf(" --print-metamodes: print the current MetaModes for the " + "X screen\n\n"); + + printf(" --add-metamode [metamode]: add the specified " + "MetaMode to the X screen's list of MetaModes.\n\n"); + + printf(" --delete-metamode [metamode]: delete the specified MetaMode " + "from the X screen's list of MetaModes.\n\n"); + + printf(" --print-current-metamode: print the current MetaMode.\n\n"); + + + printf(" Misc options:\n\n"); + + printf(" --get-valid-freq-ranges: query the valid frequency " + "information for each display device.\n\n"); + + printf(" --build-modepool: build a modepool for any display device " + "that does not already have one.\n\n"); + + printf(" --get-associated-dpys: query the associated display device " + "mask for this X screen\n\n"); + + printf(" --set-associated-dpys [mask]: set the associated display " + "device mask for this X screen\n\n"); + + printf(" --query-gpus: print GPU information and relationship to " + "X screens.\n\n"); + + printf(" --probe-dpys: probe GPUs for new display devices\n\n"); + + printf(" --query-twinview-xinerama-info-order: query the " + "TwinViewXineramaInfoOrder.\n\n"); + + printf(" --assign-twinview-xinerama-info-order [order]: assign the " + "TwinViewXineramaInfoOrder.\n\n"); + + printf(" --max-screen-size: query the maximum screen size " + "on all GPUs in the system\n\n"); + + printf(" --print-used-modelines: print the modeline for each display " + "device for each MetaMode on the X screen.\n\n"); + + printf(" --dynamic-twinview: demonstrates the process of " + "dynamically transitioning into TwinView.\n\n"); + } return 0; } + + + +/*****************************************************************************/ +/* utility functions */ +/*****************************************************************************/ + + +/* + * display_device_name() - return the display device name correspoding + * to the specified display device mask. + */ + +static char *display_device_name(int mask) +{ + switch (mask) { + case (1 << 0): return "CRT-0"; break; + case (1 << 1): return "CRT-1"; break; + case (1 << 2): return "CRT-2"; break; + case (1 << 3): return "CRT-3"; break; + case (1 << 4): return "CRT-4"; break; + case (1 << 5): return "CRT-5"; break; + case (1 << 6): return "CRT-6"; break; + case (1 << 7): return "CRT-7"; break; + + case (1 << 8): return "TV-0"; break; + case (1 << 9): return "TV-1"; break; + case (1 << 10): return "TV-2"; break; + case (1 << 11): return "TV-3"; break; + case (1 << 12): return "TV-4"; break; + case (1 << 13): return "TV-5"; break; + case (1 << 14): return "TV-6"; break; + case (1 << 15): return "TV-7"; break; + + case (1 << 16): return "DFP-0"; break; + case (1 << 17): return "DFP-1"; break; + case (1 << 18): return "DFP-2"; break; + case (1 << 19): return "DFP-3"; break; + case (1 << 20): return "DFP-4"; break; + case (1 << 21): return "DFP-5"; break; + case (1 << 22): return "DFP-6"; break; + case (1 << 23): return "DFP-7"; break; + default: return "Unknown"; + } + +} /* display_device_name() */ + + + +/* + * display_device_mask() - given a display device name, translate to + * the display device mask + */ + +static unsigned int display_device_mask(char *str) +{ + if (strcmp(str, "CRT-0") == 0) return (1 << 0); + if (strcmp(str, "CRT-1") == 0) return (1 << 1); + if (strcmp(str, "CRT-2") == 0) return (1 << 2); + if (strcmp(str, "CRT-3") == 0) return (1 << 3); + if (strcmp(str, "CRT-4") == 0) return (1 << 4); + if (strcmp(str, "CRT-5") == 0) return (1 << 5); + if (strcmp(str, "CRT-6") == 0) return (1 << 6); + if (strcmp(str, "CRT-7") == 0) return (1 << 7); + + if (strcmp(str, "TV-0") == 0) return (1 << 8); + if (strcmp(str, "TV-1") == 0) return (1 << 9); + if (strcmp(str, "TV-2") == 0) return (1 << 10); + if (strcmp(str, "TV-3") == 0) return (1 << 11); + if (strcmp(str, "TV-4") == 0) return (1 << 12); + if (strcmp(str, "TV-5") == 0) return (1 << 13); + if (strcmp(str, "TV-6") == 0) return (1 << 14); + if (strcmp(str, "TV-7") == 0) return (1 << 15); + + if (strcmp(str, "DFP-0") == 0) return (1 << 16); + if (strcmp(str, "DFP-1") == 0) return (1 << 17); + if (strcmp(str, "DFP-2") == 0) return (1 << 18); + if (strcmp(str, "DFP-3") == 0) return (1 << 19); + if (strcmp(str, "DFP-4") == 0) return (1 << 20); + if (strcmp(str, "DFP-5") == 0) return (1 << 21); + if (strcmp(str, "DFP-6") == 0) return (1 << 22); + if (strcmp(str, "DFP-7") == 0) return (1 << 23); + + return 0; + +} /* display_device_mask() */ + + + +/* + * remove_whitespace() - return an allocated copy of the given string, + * with any whitespace removed + */ + +static char *remove_whitespace(char *str) +{ + int len; + char *ret, *s, *d; + + len = strlen(str); + + ret = malloc(len+1); + + for (s = str, d = ret; *s; s++) { + if (!isspace(*s)) { + *d = *s; + d++; + } + } + + *d = '\0'; + + return ret; + +} /* remove_whitespace() */ + + + +/* + * count the number of bits set in the specified mask + */ + +static int count_bits(unsigned int mask) +{ + int n = 0; + + while (mask) { + n++; + mask &= (mask - 1) ; + } + + return n; + +} /* count_bits() */ + + + +/* + * parse_mode_string() - extract the modeName and the display device + * mask for the per-display device MetaMode string in 'modeString' + */ + +static void parse_mode_string(char *modeString, char **modeName, int *mask) +{ + char *colon, *s, tmp; + + colon = strchr(modeString, ':'); + + if (colon) { + + *colon = '\0'; + *mask = display_device_mask(modeString); + *colon = ':'; + + modeString = colon + 1; + } else { + *mask = 0; + } + + /* + * find the modename; trim off any panning domain or + * offsets + */ + + for (s = modeString; *s; s++) { + if (*s == '@') break; + if ((*s == '+') && isdigit(s[1])) break; + if ((*s == '-') && isdigit(s[1])) break; + } + + tmp = *s; + *s = '\0'; + *modeName = strdup(modeString); + *s = tmp; + +} /* parse_mode_string() */ + + + +/* + * find_modeline() - search the pModeLines list of ModeLines for the + * mode named 'modeName'; return a pointer to the matching ModeLine, + * or NULL if no match is found + */ + +static char *find_modeline(char *modeName, char *pModeLines, int ModeLineLen) +{ + char *start, *beginQuote, *endQuote; + int j, match = 0; + + start = pModeLines; + + for (j = 0; j < ModeLineLen; j++) { + if (pModeLines[j] == '\0') { + + /* + * the modeline will contain the modeName in quotes; find + * the begin and end of the quoted modeName, so that we + * can compare it to modeName + */ + + beginQuote = strchr(start, '"'); + endQuote = beginQuote ? strchr(beginQuote+1, '"') : NULL; + + if (beginQuote && endQuote) { + *endQuote = '\0'; + + match = (strcmp(modeName, beginQuote+1) == 0); + + *endQuote = '"'; + + /* + * if we found a match, return a pointer to the start + * of this modeLine + */ + + if (match) return start; + } + + start = &pModeLines[j+1]; + } + } + + return NULL; + +} /* find_modeline() */ diff --git a/samples/nv-control-events.c b/samples/nv-control-events.c index a709220..5b8a618 100644 --- a/samples/nv-control-events.c +++ b/samples/nv-control-events.c @@ -42,7 +42,7 @@ int main(void) Display *dpy; Bool ret; int event_base, error_base; - int num_screens, num_gpus, num_framelocks, i; + int num_screens, num_gpus, num_framelocks, num_vcscs, i; int sources; XEvent event; XNVCtrlAttributeChangedEvent *nvevent; @@ -101,6 +101,17 @@ int main(void) return 1; } + /* Query number of VCSC (Visual Computing System Controllers) devices */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_VCSC, + &num_vcscs); + if (ret != True) { + fprintf(stderr, "Failed to query the number of Visual Computing " + "System Controllers devices on '%s'.\n", + XDisplayName(NULL)); + return 1; + } + /* * register to receive NV-CONTROL events: whenever any NV-CONTROL * attribute is changed by an NV-CONTROL client, any other client @@ -217,6 +228,24 @@ int main(void) sources++; } + /* Register to receive on all VCSC targets */ + + for (i = 0; i < num_vcscs; i++ ) { + + ret = XNVCtrlSelectTargetNotify(dpy, NV_CTRL_TARGET_TYPE_VCSC, + i, TARGET_ATTRIBUTE_CHANGED_EVENT, + True); + if (ret != True) { + printf("- Unable to register to receive NV-CONTROL VCSC " + "target events for VCSC %d on '%s'.\n", + i, XDisplayName(NULL)); + continue; + } + + printf("+ Listening to TARGET_ATTRIBUTE_CHANGE_EVENTs on VCSC " + "%d.\n", i); + sources++; + } /* * Report the number of sources (things that we have registered to @@ -292,6 +321,7 @@ static const char *target2str(int n) case NV_CTRL_TARGET_TYPE_X_SCREEN: return "X Screen"; break; case NV_CTRL_TARGET_TYPE_GPU: return "GPU"; break; case NV_CTRL_TARGET_TYPE_FRAMELOCK: return "Frame Lock"; break; + case NV_CTRL_TARGET_TYPE_VCSC: return "VCSC"; break; default: return "Unknown"; } @@ -356,6 +386,7 @@ static const char *attr2str(int n) case NV_CTRL_GPU_2D_CLOCK_FREQS: return "gpu 2d clock frequencies"; break; case NV_CTRL_GPU_3D_CLOCK_FREQS: return "gpu 3d clock frequencies"; break; case NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS: return "gpu optimal clock frequencies"; break; + case NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION: return "gpu optimal clock frequency detection"; break; case NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE: return "gpu optimal clock frequency detection state"; break; /* XXX DDCCI stuff */ diff --git a/samples/nv-control-framelock.c b/samples/nv-control-framelock.c deleted file mode 100644 index 2e251ee..0000000 --- a/samples/nv-control-framelock.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix - * and Linux systems. - * - * Copyright (C) 2006 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of Version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 - * of the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307, USA - * - */ - - -/* - * nv-control-framelock.c - NV-CONTROL client that demonstrates how to - * interact with the frame lock capabilities on an X Server. - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <X11/Xlib.h> - -#include "NVCtrl.h" -#include "NVCtrlLib.h" - - -/* - * do_help() - * - * Prints some help on how to use this app. - * - */ -static void do_help(void) -{ - printf("usage:\n"); - printf("-q: query system frame lock information.\n"); - printf("-e: enable frame lock on system.\n"); - printf("-d: disable frame lock on system.\n"); - printf("\n"); - -} /* do_help()*/ - - - -/* - * do_query() - * - * Prints information for all frame lock (g-sync) devices found on - * the given X server. - * - */ -static void do_query(Display *dpy) -{ - Bool ret; - int num_framelocks; - int framelock; - int gpu; - int mask; - char *name; - - int *data; - int len; - int i; - - int enabled; - - - /* Query the number of frame lock devices on the server */ - - ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, - &num_framelocks); - if (!ret) { - printf("Failed to query number of frame lock devices!\n"); - return; - } - printf("Found %d frame lock device(s) on server.\n", num_framelocks); - if ( !num_framelocks ) { - return; - } - - /* Display information for all frame lock devices found */ - - for (framelock = 0; framelock < num_framelocks; framelock++) { - - printf("\n"); - printf("- Frame Lock Board %d :\n", framelock); - - /* Query the GPUs connected to this frame lock device */ - - ret = XNVCTRLQueryTargetBinaryData - (dpy, - NV_CTRL_TARGET_TYPE_FRAMELOCK, - framelock, // target_id - 0, // display_mask - NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, - (unsigned char **) &data, - &len); - if (!ret) { - printf(" - Failed to query list of GPUs!\n"); - continue; - } - - /* Display information for all GPUs connected to frame lock device */ - - if ( !data[0] ) { - printf(" - No GPUs found!\n"); - } else { - printf(" - Found %d GPU(s).\n", data[0]); - } - - for (i = 1; i <= data[0]; i++) { - gpu = data[i]; - - /* Query GPU product name */ - - ret = XNVCTRLQueryTargetStringAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_STRING_PRODUCT_NAME, - &name); - if (!ret) { - printf(" - Failed to query GPU %d product name.\n", gpu); - continue; - } - printf(" - GPU %d (%s) :\n", gpu, name); - - /* Query GPU sync state */ - - printf(" - Sync : "); - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SYNC, - &enabled); - if (!ret) { - printf("Failed to query sync state.\n"); - } else { - printf("%sabled\n", enabled ? "En" : "Dis"); - } - - /* Query GPU displays */ - - printf(" - Displays Mask : "); - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_ENABLED_DISPLAYS, - &mask); - if (!ret) { - printf("Failed to query enabled displays.\n"); - } else { - printf("0x%08u\n", mask); - } - - /* Query GPU server (master) */ - - printf(" - Server Mask : "); - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_MASTER, - &mask); - if (!ret) { - printf("Failed to query server mask.\n"); - } else { - printf("0x%08u\n", mask); - } - - /* Query GPU clients (slaves) */ - - printf(" - Clients Mask : "); - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SLAVES, - &mask); - if (!ret) { - printf("Failed to query clients mask.\n"); - } else { - printf("0x%08u\n", mask); - } - - } /* Done disabling GPUs */ - - } /* Done disabling Frame Lock Devices */ - -} /* do_query() */ - - - -/* - * do_enable() - * - * Enables frame lock on the X Server by setting the first capable/available - * display device as the frame lock server (master) and setting all other - * display devices as clients (slaves). - * - * NOTE: It is up to the user to ensure that each display device is set with - * the same refresh rate (mode timings). - * - */ -static void do_enable(Display *dpy) -{ - Bool ret; - int num_framelocks; - int framelock; - int gpu; - unsigned int mask; - - int *data; - int len; - int i; - - int enabled; - int masterable; - int pick_server = 1; - int server_set = 0; - - - /* Query the number of frame lock devices to enable */ - - ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, - &num_framelocks); - if (!ret) { - printf("Failed to query number of frame lock devices!\n"); - return; - } - printf("Found %d frame lock device(s) on server.\n", num_framelocks); - if ( !num_framelocks ) { - return; - } - - /* Enable frame lock on all GPUs connected to each frame lock device */ - - for (framelock = 0; framelock < num_framelocks; framelock++) { - - printf("\n"); - printf("- Frame Lock Board %d :\n", framelock); - - /* Query the GPUs connected to this frame lock device */ - - ret = XNVCTRLQueryTargetBinaryData - (dpy, - NV_CTRL_TARGET_TYPE_FRAMELOCK, - framelock, // target_id - 0, // display_mask - NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, - (unsigned char **) &data, - &len); - if (!ret) { - printf(" - Failed to query list of GPUs!\n"); - continue; - } - - /* Enable frame lock on all GPUs connected to the frame lock device */ - - if ( !data[0] ) { - printf(" - No GPUs found!\n"); - } else { - printf(" - Found %d GPU(s).\n", data[0]); - } - - for (i = 1; i <= data[0]; i++) { - gpu = data[i]; - - printf(" - Enabling G-Sync Device %d - GPU %d... ", - framelock, gpu); - - /* Make sure frame lock is disabled */ - - XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SYNC, - &enabled); - if (enabled != NV_CTRL_FRAMELOCK_SYNC_DISABLE) { - printf("Frame lock already enabled!\n"); - continue; - } - - /* Get the list of displays to enable */ - - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_ENABLED_DISPLAYS, - &mask); - if (!ret) { - printf("Failed to query enabled displays!\n"); - continue; - } - - /* Query if this GPU can be set as master */ - - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - mask, // display_mask - NV_CTRL_FRAMELOCK_MASTERABLE, - &masterable); - if (!ret) { - printf("Failed to query masterable!\n"); - continue; - } - - /* Clear the master setting if any */ - - if (masterable == NV_CTRL_FRAMELOCK_MASTERABLE_TRUE) { - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_MASTER, - 0); - } - - /* Clear the slaves setting if any */ - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SLAVES, - 0); - - printf("\n"); - - /* Pick the first available/capable display device as master */ - - if (pick_server && - masterable == NV_CTRL_FRAMELOCK_MASTERABLE_TRUE) { - - /* Just pick the first enabled display */ - - unsigned int master = (1<<31); - while (master && !(master & mask)) { - master >>= 1; - } - - if (master) { - mask &= ~master; - - /* Make sure we're not using the House Sync signal. */ - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_FRAMELOCK, - framelock, // target_id - 0, // display_mask - NV_CTRL_USE_HOUSE_SYNC, - NV_CTRL_USE_HOUSE_SYNC_FALSE); - - /* Set the master */ - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_MASTER, - master); - - printf(" - Set Server Display : 0x%08u\n", master); - pick_server = 0; - server_set = 1; - } - } - - /* Set rest of enabled display devices as clients (slaves) */ - - if (mask) { - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SLAVES, - mask); - printf(" - Set Client Display(s) : 0x%08u\n", mask); - } - - /* Enable frame lock */ - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SYNC, - NV_CTRL_FRAMELOCK_SYNC_ENABLE); - XFlush(dpy); - printf(" - Frame Lock Sync Enabled.\n"); - - /* If we just enabled the server, also toggle the test signal - * to guarentee accuracy of the universal frame count (as - * returned by the glXQueryFrameCountNV() function in the - * GLX_NV_swap_group extension). - */ - if (server_set) { - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_TEST_SIGNAL, - NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE); - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_TEST_SIGNAL, - NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE); - - printf(" - Frame Lock Test Signal Toggled.\n"); - server_set = 0; - } - - } /* Done enabling GPUs */ - - } /* Done enabling framelocks */ -} - - - -static void do_disable(Display *dpy) -{ - Bool ret; - int num_framelocks; - int framelock; - int gpu; - - int *data; - int len; - int i; - - /* Query the number of frame lock devices to disable */ - - ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, - &num_framelocks); - if (!ret) { - printf("Failed to query number of frame lock devices!\n"); - return; - } - printf("Found %d frame lock device(s) on server.\n", num_framelocks); - if ( !num_framelocks ) { - return; - } - - /* Disable frame lock on all GPUs connected to each frame lock device */ - - for (framelock = 0; framelock < num_framelocks; framelock++) { - - printf("\n"); - printf("- Frame Lock Board %d :\n", framelock); - - /* Query the GPUs connected to this frame lock device */ - - ret = XNVCTRLQueryTargetBinaryData - (dpy, - NV_CTRL_TARGET_TYPE_FRAMELOCK, - framelock, // target_id - 0, // display_mask - NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, - (unsigned char **) &data, - &len); - if (!ret) { - printf(" - Failed to query list of GPUs!\n"); - continue; - } - - /* Disable frame lock on all GPUs connected to the frame lock device */ - - if ( !data[0] ) { - printf(" - No GPUs found!\n"); - } else { - printf(" - Found %d GPU(s).\n", data[0]); - } - - for (i = 1; i <= data[0]; i++) { - gpu = data[i]; - - printf(" - Disabling G-Sync Device %d - GPU %d... ", - framelock, gpu); - - XNVCTRLSetTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_FRAMELOCK_SYNC, - NV_CTRL_FRAMELOCK_SYNC_DISABLE); - XFlush(dpy); - printf("Done.\n"); - - } /* Done disabling GPUs */ - - } /* Done disabling Frame Lock Devices */ - -} /* do_disable() */ - - - -int main(int argc, char *argv[]) -{ - Display *dpy; - Bool ret; - int major, minor; - - /* - * Open a display connection, and make sure the NV-CONTROL X - * extension is present on the screen we want to use. - */ - - dpy = XOpenDisplay(NULL); - if (!dpy) { - printf("Cannot open display '%s'.\n", XDisplayName(NULL)); - return 1; - } - - /* Query the NV-CONTROL version */ - - ret = XNVCTRLQueryVersion(dpy, &major, &minor); - if (ret != True) { - printf("The NV-CONTROL X extension does not exist on '%s'.\n", - XDisplayName(NULL)); - return 1; - } - - /* Print some information */ - - printf("Using NV-CONTROL extension %d.%d on %s\n\n", - major, minor, XDisplayName(NULL)); - - /* Do what the user wants */ - - if (argc <= 1 || (strcmp(argv[1], "-q") == 0)) { - do_query(dpy); - - } else if (strcmp(argv[1], "-e") == 0) { - do_enable(dpy); - - } else if (strcmp(argv[1], "-d") == 0) { - do_disable(dpy); - - } else { - do_help(); - } - - return 0; -} diff --git a/samples/nv-control-targets.c b/samples/nv-control-targets.c index 4d97c58..bdee17c 100644 --- a/samples/nv-control-targets.c +++ b/samples/nv-control-targets.c @@ -89,6 +89,7 @@ int main(int argc, char *argv[]) int major, minor; int num_gpus, num_screens, num_gsyncs; + int num_vcscs; int gpu, screen; int display_devices, mask; int *pData; @@ -171,6 +172,20 @@ int main(int argc, char *argv[]) printf(" number of Frame Lock Devices: %d\n", num_gsyncs); + /* Get the number of Visual Computing System Controller devices in + * the system + */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_VCSC, + &num_vcscs); + if (!ret) { + fprintf(stderr, "Failed to query number of VCSCs\n"); + return 1; + } + printf(" number of Visual Computing System Controllers: %d\n", + num_vcscs); + + /* display information about all GPUs */ for (gpu = 0; gpu < num_gpus; gpu++) { diff --git a/src/Makefile.inc b/src/Makefile.inc index 7c3e745..1e0f2a8 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -36,6 +36,7 @@ SRC += \ glxinfo.c EXTRA_DIST += \ + Makefile.inc \ command-line.h \ config-file.h \ msg.h \ @@ -43,3 +44,6 @@ EXTRA_DIST += \ query-assign.h \ nvgetopt.h \ glxinfo.h + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/XF86Config-parser/Configint.h b/src/XF86Config-parser/Configint.h new file mode 100644 index 0000000..f91c6ee --- /dev/null +++ b/src/XF86Config-parser/Configint.h @@ -0,0 +1,212 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2002 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * These definitions are used through out the configuration file parser, but + * they should not be visible outside of the parser. + */ + +#ifndef _Configint_h_ +#define _Configint_h_ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stddef.h> +#include "xf86Parser.h" + +typedef struct +{ + int num; /* returned number */ + char *str; /* private copy of the return-string */ + double realnum; /* returned number as a real */ +} +LexRec, *LexPtr; + + +#include "configProcs.h" +#include <stdlib.h> + +#define TEST_FREE(a) \ + if (a) { \ + free (a); \ + a = NULL; \ + } + + +#define PARSE_PROLOGUE(typeptr,typerec) \ + typeptr ptr; \ + if ((ptr = (typeptr) calloc(1, sizeof(typerec))) == NULL) { \ + return NULL; \ + } \ + memset(ptr, 0, sizeof(typerec)); + + +#define HANDLE_LIST(field,func,type) \ +{ \ + type p = func(); \ + if (p == NULL) \ + { \ + CLEANUP (ptr); \ + return (NULL); \ + } else { \ + ptr->field = (type) \ + xconfigAddListItem((GenericListPtr) ptr->field, \ + (GenericListPtr) p); \ + } \ +} + + +#define Error(a,b) \ + do { \ + xconfigErrorMsg(ParseErrorMsg, a, b); \ + CLEANUP (ptr); \ + return NULL; \ + } while (0) \ + +/* + * These are defines for error messages to promote consistency. + * error messages are preceded by the line number, section and file name, + * so these messages should be about the specific keyword and syntax in error. + * To help limit namespace polution, end each with _MSG. + * limit messages to 70 characters if possible. + */ + +#define BAD_OPTION_MSG \ +"The Option keyword requires 1 or 2 quoted strings to follow it." +#define INVALID_KEYWORD_MSG \ +"\"%s\" is not a valid keyword in this section." +#define INVALID_SECTION_MSG \ +"\"%s\" is not a valid section name." +#define UNEXPECTED_EOF_MSG \ +"Unexpected EOF. Missing EndSection keyword?" +#define QUOTE_MSG \ +"The %s keyword requires a quoted string to follow it." +#define NUMBER_MSG \ +"The %s keyword requires a number to follow it." +#define POSITIVE_INT_MSG \ +"The %s keyword requires a positive integer to follow it." +#define ZAXISMAPPING_MSG \ +"The ZAxisMapping keyword requires 2 positive numbers or X or Y to follow it." +#define AUTOREPEAT_MSG \ +"The AutoRepeat keyword requires 2 numbers (delay and rate) to follow it." +#define XLEDS_MSG \ +"The XLeds keyword requries one or more numbers to follow it." +#define DACSPEED_MSG \ +"The DacSpeed keyword must be followed by a list of up to %d numbers." +#define DISPLAYSIZE_MSG \ +"The DisplaySize keyword must be followed by the width and height in mm." +#define HORIZSYNC_MSG \ +"The HorizSync keyword must be followed by a list of numbers or ranges." +#define VERTREFRESH_MSG \ +"The VertRefresh keyword must be followed by a list of numbers or ranges." +#define VIEWPORT_MSG \ +"The Viewport keyword must be followed by an X and Y value." +#define VIRTUAL_MSG \ +"The Virtual keyword must be followed by a width and height value." +#define WEIGHT_MSG \ +"The Weight keyword must be followed by red, green and blue values." +#define BLACK_MSG \ +"The Black keyword must be followed by red, green and blue values." +#define WHITE_MSG \ +"The White keyword must be followed by red, green and blue values." +#define SCREEN_MSG \ +"The Screen keyword must be followed by an optional number, a screen name\n" \ +"\tin quotes, and optional position/layout information." +#define INVALID_SCR_MSG \ +"Invalid Screen line." +#define INPUTDEV_MSG \ +"The InputDevice keyword must be followed by an input device name in quotes." +#define INACTIVE_MSG \ +"The Inactive keyword must be followed by a Device name in quotes." +#define UNDEFINED_SCREEN_MSG \ +"Undefined Screen \"%s\" referenced by ServerLayout \"%s\"." +#define UNDEFINED_MONITOR_MSG \ +"Undefined Monitor \"%s\" referenced by Screen \"%s\"." +#define UNDEFINED_MODES_MSG \ +"Undefined Modes Section \"%s\" referenced by Monitor \"%s\"." +#define UNDEFINED_DEVICE_MSG \ +"Undefined Device \"%s\" referenced by Screen \"%s\"." +#define UNDEFINED_ADAPTOR_MSG \ +"Undefined VideoAdaptor \"%s\" referenced by Screen \"%s\"." +#define ADAPTOR_REF_TWICE_MSG \ +"VideoAdaptor \"%s\" already referenced by Screen \"%s\"." +#define UNDEFINED_DEVICE_LAY_MSG \ +"Undefined Device \"%s\" referenced by ServerLayout \"%s\"." +#define UNDEFINED_INPUT_MSG \ +"Undefined InputDevice \"%s\" referenced by ServerLayout \"%s\"." +#define NO_IDENT_MSG \ +"This section must have an Identifier line." +#define ONLY_ONE_MSG \ +"This section must have only one of either %s line." +#define UNDEFINED_DRIVER_MSG \ +"Device section \"%s\" must have a Driver line." +#define UNDEFINED_INPUTDRIVER_MSG \ +"InputDevice section \"%s\" must have a Driver line." +#define INVALID_GAMMA_MSG \ +"gamma correction value(s) expected\n either one value or three r/g/b values." +#define GROUP_MSG \ +"The Group keyword must be followed by either a group name in quotes or\n" \ +"\ta numerical group id." +#define MULTIPLE_MSG \ +"Multiple \"%s\" lines." + +/* Warning messages */ +#define OBSOLETE_MSG \ +"Ignoring obsolete keyword \"%s\"." +#define MOVED_TO_FLAGS_MSG \ +"Keyword \"%s\" is now an Option flag in the ServerFlags section." + +#endif /* _Configint_h_ */ diff --git a/src/XF86Config-parser/DRI.c b/src/XF86Config-parser/DRI.c new file mode 100644 index 0000000..9936830 --- /dev/null +++ b/src/XF86Config-parser/DRI.c @@ -0,0 +1,152 @@ +/* DRI.c -- DRI Section in XF86Config file + * Created: Fri Mar 19 08:40:22 1999 by faith@precisioninsight.com + * Revised: Thu Jun 17 16:08:05 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * 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 (including the next + * paragraph) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + * + */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec DRITab[] = +{ + {ENDSECTION, "endsection"}, + {GROUP, "group"}, + {BUFFERS, "buffers"}, + {MODE, "mode"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeBuffersList + +XConfigBuffersPtr +xconfigParseBuffers (void) +{ + int token; + PARSE_PROLOGUE (XConfigBuffersPtr, XConfigBuffersRec) + + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error("Buffers count expected", NULL); + ptr->count = val.num; + + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error("Buffers size expected", NULL); + ptr->size = val.num; + + if ((token = xconfigGetSubToken (&(ptr->comment))) == STRING) { + ptr->flags = val.str; + if ((token = xconfigGetToken (NULL)) == COMMENT) + ptr->comment = xconfigAddComment(ptr->comment, val.str); + else + xconfigUnGetToken(token); + } + + return ptr; +} + +#undef CLEANUP + +#define CLEANUP xconfigFreeDRI + +XConfigDRIPtr +xconfigParseDRISection (void) +{ + int token; + PARSE_PROLOGUE (XConfigDRIPtr, XConfigDRIRec); + + /* Zero is a valid value for this. */ + ptr->group = -1; + while ((token = xconfigGetToken (DRITab)) != ENDSECTION) { + switch (token) + { + case GROUP: + if ((token = xconfigGetSubToken (&(ptr->comment))) == STRING) + ptr->group_name = val.str; + else if (token == NUMBER) + ptr->group = val.num; + else + Error (GROUP_MSG, NULL); + break; + case MODE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Mode"); + ptr->mode = val.num; + break; + case BUFFERS: + HANDLE_LIST (buffers, xconfigParseBuffers, + XConfigBuffersPtr); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintDRISection (FILE * cf, XConfigDRIPtr ptr) +{ + /* we never need the DRI section for the NVIDIA driver */ + + return; +} + +void +xconfigFreeDRI (XConfigDRIPtr ptr) +{ + if (ptr == NULL) + return; + + xconfigFreeBuffersList (ptr->buffers); + TEST_FREE (ptr->comment); + free (ptr); +} + +void +xconfigFreeBuffersList (XConfigBuffersPtr ptr) +{ + XConfigBuffersPtr prev; + + while (ptr) { + TEST_FREE (ptr->flags); + TEST_FREE (ptr->comment); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + diff --git a/src/XF86Config-parser/Device.c b/src/XF86Config-parser/Device.c new file mode 100644 index 0000000..a4c3f62 --- /dev/null +++ b/src/XF86Config-parser/Device.c @@ -0,0 +1,498 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +#include <ctype.h> + +extern LexRec val; + +static +XConfigSymTabRec DeviceTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {VENDOR, "vendorname"}, + {BOARD, "boardname"}, + {CHIPSET, "chipset"}, + {RAMDAC, "ramdac"}, + {DACSPEED, "dacspeed"}, + {CLOCKS, "clocks"}, + {OPTION, "option"}, + {VIDEORAM, "videoram"}, + {BIOSBASE, "biosbase"}, + {MEMBASE, "membase"}, + {IOBASE, "iobase"}, + {CLOCKCHIP, "clockchip"}, + {CHIPID, "chipid"}, + {CHIPREV, "chiprev"}, + {CARD, "card"}, + {DRIVER, "driver"}, + {BUSID, "busid"}, + {TEXTCLOCKFRQ, "textclockfreq"}, + {IRQ, "irq"}, + {SCREEN, "screen"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeDeviceList + +XConfigDevicePtr +xconfigParseDeviceSection (void) +{ + int i; + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigDevicePtr, XConfigDeviceRec) + + /* Zero is a valid value for these */ + ptr->chipid = -1; + ptr->chiprev = -1; + ptr->irq = -1; + ptr->screen = -1; + while ((token = xconfigGetToken (DeviceTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case VENDOR: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Vendor"); + ptr->vendor = val.str; + break; + case BOARD: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Board"); + ptr->board = val.str; + break; + case CHIPSET: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Chipset"); + ptr->chipset = val.str; + break; + case CARD: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Card"); + ptr->card = val.str; + break; + case DRIVER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Driver"); + ptr->driver = val.str; + break; + case RAMDAC: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Ramdac"); + ptr->ramdac = val.str; + break; + case DACSPEED: + for (i = 0; i < CONF_MAXDACSPEEDS; i++) + ptr->dacSpeeds[i] = 0; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + { + Error (DACSPEED_MSG, CONF_MAXDACSPEEDS); + } + else + { + ptr->dacSpeeds[0] = (int) (val.realnum * 1000.0 + 0.5); + for (i = 1; i < CONF_MAXDACSPEEDS; i++) + { + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->dacSpeeds[i] = (int) + (val.realnum * 1000.0 + 0.5); + else + { + xconfigUnGetToken (token); + break; + } + } + } + break; + case VIDEORAM: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "VideoRam"); + ptr->videoram = val.num; + break; + case BIOSBASE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "BIOSBase"); + ptr->bios_base = val.num; + break; + case MEMBASE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "MemBase"); + ptr->mem_base = val.num; + break; + case IOBASE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "IOBase"); + ptr->io_base = val.num; + break; + case CLOCKCHIP: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "ClockChip"); + ptr->clockchip = val.str; + break; + case CHIPID: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "ChipID"); + ptr->chipid = val.num; + break; + case CHIPREV: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "ChipRev"); + ptr->chiprev = val.num; + break; + + case CLOCKS: + token = xconfigGetSubToken(&(ptr->comment)); + for( i = ptr->clocks; + token == NUMBER && i < CONF_MAXCLOCKS; i++ ) { + ptr->clock[i] = (int)(val.realnum * 1000.0 + 0.5); + token = xconfigGetSubToken(&(ptr->comment)); + } + ptr->clocks = i; + xconfigUnGetToken (token); + break; + case TEXTCLOCKFRQ: + if ((token = xconfigGetSubToken(&(ptr->comment))) != NUMBER) + Error (NUMBER_MSG, "TextClockFreq"); + ptr->textclockfreq = (int)(val.realnum * 1000.0 + 0.5); + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case BUSID: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "BusID"); + ptr->busid = val.str; + break; + case IRQ: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (QUOTE_MSG, "IRQ"); + ptr->irq = val.num; + break; + case SCREEN: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Screen"); + ptr->screen = val.num; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintDeviceSection (FILE * cf, XConfigDevicePtr ptr) +{ + int i; + + while (ptr) + { + fprintf (cf, "Section \"Device\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + if (ptr->driver) + fprintf (cf, " Driver \"%s\"\n", ptr->driver); + if (ptr->vendor) + fprintf (cf, " VendorName \"%s\"\n", ptr->vendor); + if (ptr->board) + fprintf (cf, " BoardName \"%s\"\n", ptr->board); + if (ptr->chipset) + fprintf (cf, " ChipSet \"%s\"\n", ptr->chipset); + if (ptr->card) + fprintf (cf, " Card \"%s\"\n", ptr->card); + if (ptr->ramdac) + fprintf (cf, " RamDac \"%s\"\n", ptr->ramdac); + if (ptr->dacSpeeds[0] > 0 ) { + fprintf (cf, " DacSpeed "); + for (i = 0; i < CONF_MAXDACSPEEDS + && ptr->dacSpeeds[i] > 0; i++ ) + fprintf (cf, "%g ", (double) (ptr->dacSpeeds[i])/ 1000.0 ); + fprintf (cf, "\n"); + } + if (ptr->videoram) + fprintf (cf, " VideoRam %d\n", ptr->videoram); + if (ptr->bios_base) + fprintf (cf, " BiosBase 0x%lx\n", ptr->bios_base); + if (ptr->mem_base) + fprintf (cf, " MemBase 0x%lx\n", ptr->mem_base); + if (ptr->io_base) + fprintf (cf, " IOBase 0x%lx\n", ptr->io_base); + if (ptr->clockchip) + fprintf (cf, " ClockChip \"%s\"\n", ptr->clockchip); + if (ptr->chipid != -1) + fprintf (cf, " ChipId 0x%x\n", ptr->chipid); + if (ptr->chiprev != -1) + fprintf (cf, " ChipRev 0x%x\n", ptr->chiprev); + + xconfigPrintOptionList(cf, ptr->options, 1); + if (ptr->clocks > 0 ) { + fprintf (cf, " Clocks "); + for (i = 0; i < ptr->clocks; i++ ) + fprintf (cf, "%.1f ", (double)ptr->clock[i] / 1000.0 ); + fprintf (cf, "\n"); + } + if (ptr->textclockfreq) { + fprintf (cf, " TextClockFreq %.1f\n", + (double)ptr->textclockfreq / 1000.0); + } + if (ptr->busid) + fprintf (cf, " BusID \"%s\"\n", ptr->busid); + if (ptr->screen > -1) + fprintf (cf, " Screen %d\n", ptr->screen); + if (ptr->irq >= 0) + fprintf (cf, " IRQ %d\n", ptr->irq); + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigFreeDeviceList (XConfigDevicePtr ptr) +{ + XConfigDevicePtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->vendor); + TEST_FREE (ptr->board); + TEST_FREE (ptr->chipset); + TEST_FREE (ptr->card); + TEST_FREE (ptr->driver); + TEST_FREE (ptr->ramdac); + TEST_FREE (ptr->clockchip); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +int +xconfigValidateDevice (XConfigPtr p) +{ + XConfigDevicePtr device = p->devices; + + if (!device) { + xconfigErrorMsg(ValidationErrorMsg, "At least one Device section " + "is required."); + return (FALSE); + } + + while (device) { + if (!device->driver) { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_DRIVER_MSG, + device->identifier); + return (FALSE); + } + device = device->next; + } + return (TRUE); +} + +XConfigDevicePtr +xconfigFindDevice (const char *ident, XConfigDevicePtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + + +/* + * Determine what bus type the busID string represents. The start of the + * bus-dependent part of the string is returned as retID. + */ + +static int isPci(const char* busID, const char **retID) +{ + char *p, *s; + int ret = FALSE; + + /* If no type field, Default to PCI */ + if (isdigit(busID[0])) { + if (retID) + *retID = busID; + return TRUE; + } + + s = strdup(busID); + p = strtok(s, ":"); + if (p == NULL || *p == 0) { + free(s); + return FALSE; + } + if (!xconfigNameCompare(p, "pci") || !xconfigNameCompare(p, "agp")) { + if (retID) + *retID = busID + strlen(p) + 1; + ret = TRUE; + } + free(s); + return ret; +} + + +/* + * Parse a BUS ID string, and return the PCI bus parameters if it was + * in the correct format for a PCI bus id. + */ + +int xconfigParsePciBusString(const char *busID, + int *bus, int *device, int *func) +{ + /* + * The format is assumed to be "bus[@domain]:device[:func]", where domain, + * bus, device and func are decimal integers. domain and func may be + * omitted and assumed to be zero, although doing this isn't encouraged. + */ + + char *p, *s, *d; + const char *id; + int i; + + if (!isPci(busID, &id)) + return FALSE; + + s = strdup(id); + p = strtok(s, ":"); + if (p == NULL || *p == 0) { + free(s); + return FALSE; + } + d = strpbrk(p, "@"); + if (d != NULL) { + *(d++) = 0; + for (i = 0; d[i] != 0; i++) { + if (!isdigit(d[i])) { + free(s); + return FALSE; + } + } + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *bus = atoi(p); + if (d != NULL && *d != 0) + *bus += atoi(d) << 8; + p = strtok(NULL, ":"); + if (p == NULL || *p == 0) { + free(s); + return FALSE; + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *device = atoi(p); + *func = 0; + p = strtok(NULL, ":"); + if (p == NULL || *p == 0) { + free(s); + return TRUE; + } + for (i = 0; p[i] != 0; i++) { + if (!isdigit(p[i])) { + free(s); + return FALSE; + } + } + *func = atoi(p); + free(s); + return TRUE; +} + diff --git a/src/XF86Config-parser/Extensions.c b/src/XF86Config-parser/Extensions.c new file mode 100644 index 0000000..7482a6d --- /dev/null +++ b/src/XF86Config-parser/Extensions.c @@ -0,0 +1,102 @@ +/* + * Copyright 2004 Red Hat Inc., Raleigh, North Carolina. + * + * All Rights Reserved. + * + * 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 on 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 (including the + * next paragraph) 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * 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. + */ + +/* + * Authors: + * Kevin E. Martin <kem@redhat.com> + * + */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec ExtensionsTab[] = +{ + {ENDSECTION, "endsection"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeExtensions + +XConfigExtensionsPtr +xconfigParseExtensionsSection (void) +{ + int token; + + PARSE_PROLOGUE (XConfigExtensionsPtr, XConfigExtensionsRec); + + while ((token = xconfigGetToken (ExtensionsTab)) != ENDSECTION) { + switch (token) { + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintExtensionsSection (FILE * cf, XConfigExtensionsPtr ptr) +{ + XConfigOptionPtr p; + + if (ptr == NULL || ptr->options == NULL) + return; + + p = ptr->options; + fprintf (cf, "Section \"Extensions\"\n"); + if (ptr->comment) fprintf (cf, "%s", ptr->comment); + xconfigPrintOptionList(cf, p, 1); + fprintf (cf, "EndSection\n\n"); +} + +void +xconfigFreeExtensions (XConfigExtensionsPtr ptr) +{ + if (ptr == NULL) + return; + + xconfigOptionListFree (ptr->options); + TEST_FREE (ptr->comment); + free (ptr); +} diff --git a/src/XF86Config-parser/Files.c b/src/XF86Config-parser/Files.c new file mode 100644 index 0000000..6493cd1 --- /dev/null +++ b/src/XF86Config-parser/Files.c @@ -0,0 +1,281 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include <strings.h> + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec FilesTab[] = +{ + {ENDSECTION, "endsection"}, + {FONTPATH, "fontpath"}, + {RGBPATH, "rgbpath"}, + {MODULEPATH, "modulepath"}, + {INPUTDEVICES, "inputdevices"}, + {LOGFILEPATH, "logfile"}, + {-1, ""}, +}; + +static char * +prependRoot (char *pathname) +{ + return pathname; +} + +#define CLEANUP xconfigFreeFiles + +XConfigFilesPtr +xconfigParseFilesSection (void) +{ + int i, j; + int k, l; + char *str; + int token; + PARSE_PROLOGUE (XConfigFilesPtr, XConfigFilesRec) + + while ((token = xconfigGetToken (FilesTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case FONTPATH: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "FontPath"); + j = FALSE; + str = prependRoot (val.str); + if (ptr->fontpath == NULL) + { + ptr->fontpath = malloc (1); + ptr->fontpath[0] = '\0'; + i = strlen (str) + 1; + } + else + { + i = strlen (ptr->fontpath) + strlen (str) + 1; + if (ptr->fontpath[strlen (ptr->fontpath) - 1] != ',') + { + i++; + j = TRUE; + } + } + ptr->fontpath = realloc (ptr->fontpath, i); + if (j) + strcat (ptr->fontpath, ","); + + strcat (ptr->fontpath, str); + free (val.str); + break; + case RGBPATH: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "RGBPath"); + ptr->rgbpath = val.str; + break; + case MODULEPATH: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "ModulePath"); + l = FALSE; + str = prependRoot (val.str); + if (ptr->modulepath == NULL) + { + ptr->modulepath = malloc (1); + ptr->modulepath[0] = '\0'; + k = strlen (str) + 1; + } + else + { + k = strlen (ptr->modulepath) + strlen (str) + 1; + if (ptr->modulepath[strlen (ptr->modulepath) - 1] != ',') + { + k++; + l = TRUE; + } + } + ptr->modulepath = realloc (ptr->modulepath, k); + if (l) + strcat (ptr->modulepath, ","); + + strcat (ptr->modulepath, str); + free (val.str); + break; + case INPUTDEVICES: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "InputDevices"); + l = FALSE; + str = prependRoot (val.str); + if (ptr->inputdevs == NULL) + { + ptr->inputdevs = malloc (1); + ptr->inputdevs[0] = '\0'; + k = strlen (str) + 1; + } + else + { + k = strlen (ptr->inputdevs) + strlen (str) + 1; + if (ptr->inputdevs[strlen (ptr->inputdevs) - 1] != ',') + { + k++; + l = TRUE; + } + } + ptr->inputdevs = realloc (ptr->inputdevs, k); + if (l) + strcat (ptr->inputdevs, ","); + + strcat (ptr->inputdevs, str); + free (val.str); + break; + case LOGFILEPATH: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "LogFile"); + ptr->logfile = val.str; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintFileSection (FILE * cf, XConfigFilesPtr ptr) +{ + char *p, *s; + + if (ptr == NULL) + return; + + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->logfile) + fprintf (cf, " LogFile \"%s\"\n", ptr->logfile); + if (ptr->rgbpath) + fprintf (cf, " RgbPath \"%s\"\n", ptr->rgbpath); + if (ptr->modulepath) + { + s = ptr->modulepath; + p = index (s, ','); + while (p) + { + *p = '\000'; + fprintf (cf, " ModulePath \"%s\"\n", s); + *p = ','; + s = p; + s++; + p = index (s, ','); + } + fprintf (cf, " ModulePath \"%s\"\n", s); + } + if (ptr->inputdevs) + { + s = ptr->inputdevs; + p = index (s, ','); + while (p) + { + *p = '\000'; + fprintf (cf, " InputDevices \"%s\"\n", s); + *p = ','; + s = p; + s++; + p = index (s, ','); + } + fprintf (cf, " InputDevices \"%s\"\n", s); + } + if (ptr->fontpath) + { + s = ptr->fontpath; + p = index (s, ','); + while (p) + { + *p = '\000'; + fprintf (cf, " FontPath \"%s\"\n", s); + *p = ','; + s = p; + s++; + p = index (s, ','); + } + fprintf (cf, " FontPath \"%s\"\n", s); + } +} + +void +xconfigFreeFiles (XConfigFilesPtr p) +{ + if (p == NULL) + return; + + TEST_FREE (p->logfile); + TEST_FREE (p->rgbpath); + TEST_FREE (p->modulepath); + TEST_FREE (p->inputdevs); + TEST_FREE (p->fontpath); + TEST_FREE (p->comment); + + free (p); +} diff --git a/src/XF86Config-parser/Flags.c b/src/XF86Config-parser/Flags.c new file mode 100644 index 0000000..21413c9 --- /dev/null +++ b/src/XF86Config-parser/Flags.c @@ -0,0 +1,560 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" +#include <math.h> + +extern LexRec val; + +static XConfigSymTabRec ServerFlagsTab[] = +{ + {ENDSECTION, "endsection"}, + {NOTRAPSIGNALS, "notrapsignals"}, + {DONTZAP, "dontzap"}, + {DONTZOOM, "dontzoom"}, + {DISABLEVIDMODE, "disablevidmodeextension"}, + {ALLOWNONLOCAL, "allownonlocalxvidtune"}, + {DISABLEMODINDEV, "disablemodindev"}, + {MODINDEVALLOWNONLOCAL, "allownonlocalmodindev"}, + {ALLOWMOUSEOPENFAIL, "allowmouseopenfail"}, + {OPTION, "option"}, + {BLANKTIME, "blanktime"}, + {STANDBYTIME, "standbytime"}, + {SUSPENDTIME, "suspendtime"}, + {OFFTIME, "offtime"}, + {DEFAULTLAYOUT, "defaultserverlayout"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeFlags + +XConfigFlagsPtr +xconfigParseFlagsSection (void) +{ + int token; + PARSE_PROLOGUE (XConfigFlagsPtr, XConfigFlagsRec) + + while ((token = xconfigGetToken (ServerFlagsTab)) != ENDSECTION) + { + int hasvalue = FALSE; + int strvalue = FALSE; + int tokentype; + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + /* + * these old keywords are turned into standard generic options. + * we fall through here on purpose + */ + case DEFAULTLAYOUT: + strvalue = TRUE; + case BLANKTIME: + case STANDBYTIME: + case SUSPENDTIME: + case OFFTIME: + hasvalue = TRUE; + case NOTRAPSIGNALS: + case DONTZAP: + case DONTZOOM: + case DISABLEVIDMODE: + case ALLOWNONLOCAL: + case DISABLEMODINDEV: + case MODINDEVALLOWNONLOCAL: + case ALLOWMOUSEOPENFAIL: + { + int i = 0; + while (ServerFlagsTab[i].token != -1) + { + char *tmp; + + if (ServerFlagsTab[i].token == token) + { + char *valstr = NULL; + /* can't use strdup because it calls malloc */ + tmp = xconfigStrdup (ServerFlagsTab[i].name); + if (hasvalue) + { + tokentype = xconfigGetSubToken(&(ptr->comment)); + if (strvalue) { + if (tokentype != STRING) + Error (QUOTE_MSG, tmp); + valstr = val.str; + } else { + if (tokentype != NUMBER) + Error (NUMBER_MSG, tmp); + valstr = malloc(16); + if (valstr) + sprintf(valstr, "%d", val.num); + } + } + ptr->options = xconfigAddNewOption + (ptr->options, tmp, valstr); + } + i++; + } + } + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintServerFlagsSection (FILE * f, XConfigFlagsPtr flags) +{ + XConfigOptionPtr p; + + if ((!flags) || (!flags->options)) + return; + p = flags->options; + fprintf (f, "Section \"ServerFlags\"\n"); + if (flags->comment) + fprintf (f, "%s", flags->comment); + xconfigPrintOptionList(f, p, 1); + fprintf (f, "EndSection\n\n"); +} + +static XConfigOptionPtr +addNewOption2 (XConfigOptionPtr head, char *name, char *val, int used) +{ + XConfigOptionPtr new, old = NULL; + + /* Don't allow duplicates */ + if (head != NULL && (old = xconfigFindOption(head, name)) != NULL) { + TEST_FREE(old->name); + TEST_FREE(old->val); + new = old; + } else { + new = calloc (1, sizeof (XConfigOptionRec)); + new->next = NULL; + } + new->name = name; + new->val = val; + new->used = used; + + if (old == NULL) + return ((XConfigOptionPtr) xconfigAddListItem ((GenericListPtr) head, + (GenericListPtr) new)); + else + return head; +} + +XConfigOptionPtr +xconfigAddNewOption (XConfigOptionPtr head, char *name, char *val) +{ + return addNewOption2(head, name, val, 0); +} + +void +xconfigFreeFlags (XConfigFlagsPtr flags) +{ + if (flags == NULL) + return; + xconfigOptionListFree (flags->options); + TEST_FREE(flags->comment); + free (flags); +} + +XConfigOptionPtr +xconfigOptionListDup (XConfigOptionPtr opt) +{ + XConfigOptionPtr newopt = NULL; + + while (opt) + { + newopt = xconfigAddNewOption(newopt, xconfigStrdup(opt->name), + xconfigStrdup(opt->val)); + newopt->used = opt->used; + if (opt->comment) + newopt->comment = xconfigStrdup(opt->comment); + opt = opt->next; + } + return newopt; +} + +void +xconfigOptionListFree (XConfigOptionPtr opt) +{ + XConfigOptionPtr prev; + + while (opt) + { + TEST_FREE (opt->name); + TEST_FREE (opt->val); + TEST_FREE (opt->comment); + prev = opt; + opt = opt->next; + free (prev); + } +} + +char * +xconfigOptionName(XConfigOptionPtr opt) +{ + if (opt) + return opt->name; + return 0; +} + +char * +xconfigOptionValue(XConfigOptionPtr opt) +{ + if (opt) + return opt->val; + return 0; +} + +XConfigOptionPtr +xconfigNewOption(char *name, char *value) +{ + XConfigOptionPtr opt; + + opt = calloc(1, sizeof (XConfigOptionRec)); + if (!opt) + return NULL; + + opt->used = 0; + opt->next = 0; + opt->name = name; + opt->val = value; + + return opt; +} + +XConfigOptionPtr +xconfigRemoveOption(XConfigOptionPtr list, XConfigOptionPtr opt) +{ + XConfigOptionPtr prev = NULL; + XConfigOptionPtr p = list; + + while (p) { + if (p == opt) { + if (prev) prev->next = opt->next; + if (list == opt) list = opt->next; + + TEST_FREE(opt->name); + TEST_FREE(opt->val); + TEST_FREE(opt->comment); + free(opt); + break; + } + prev = p; + p = p->next; + } + + return list; +} + +XConfigOptionPtr +xconfigNextOption(XConfigOptionPtr list) +{ + if (!list) + return NULL; + return list->next; +} + +/* + * this function searches the given option list for the named option and + * returns a pointer to the option rec if found. If not found, it returns + * NULL + */ + +XConfigOptionPtr +xconfigFindOption (XConfigOptionPtr list, const char *name) +{ + while (list) + { + if (xconfigNameCompare (list->name, name) == 0) + return (list); + list = list->next; + } + return (NULL); +} + +/* + * this function searches the given option list for the named option. If + * found and the option has a parameter, a pointer to the parameter is + * returned. If the option does not have a parameter an empty string is + * returned. If the option is not found, a NULL is returned. + */ + +char * +xconfigFindOptionValue (XConfigOptionPtr list, const char *name) +{ + XConfigOptionPtr p = xconfigFindOption (list, name); + + if (p) + { + if (p->val) + return (p->val); + else + return ""; + } + return (NULL); +} + +/* + * this function searches the given option list for the named option. If + * found and the the value of the option is set to "1", "ON", "YES" or + * "TRUE", 1 is returned. Otherwise, 0 is returned. + */ + +int +xconfigFindOptionBoolean (XConfigOptionPtr list, const char *name) +{ + XConfigOptionPtr p = xconfigFindOption (list, name); + + if (p && p->val) + { + if ( strcasecmp(p->val, "1") == 0 || + strcasecmp(p->val, "ON") == 0 || + strcasecmp(p->val, "YES") == 0 || + strcasecmp(p->val, "TRUE") == 0 ) + { + return 1; + } + } + return 0; +} + +XConfigOptionPtr +xconfigOptionListCreate( const char **options, int count, int used ) +{ + XConfigOptionPtr p = NULL; + char *t1, *t2; + int i; + + if (count == -1) + { + for (count = 0; options[count]; count++) + ; + } + if( (count % 2) != 0 ) + { + xconfigErrorMsg(InternalErrorMsg, "xconfigOptionListCreate: count must " + "be an even number.\n"); + return (NULL); + } + for (i = 0; i < count; i += 2) + { + /* can't use strdup because it calls malloc */ + t1 = malloc (sizeof (char) * + (strlen (options[i]) + 1)); + strcpy (t1, options[i]); + t2 = malloc (sizeof (char) * + (strlen (options[i + 1]) + 1)); + strcpy (t2, options[i + 1]); + p = addNewOption2 (p, t1, t2, used); + } + + return (p); +} + +/* the 2 given lists are merged. If an option with the same name is present in + * both, the option from the user list - specified in the second argument - + * is used. The end result is a single valid list of options. Duplicates + * are freed, and the original lists are no longer guaranteed to be complete. + */ +XConfigOptionPtr +xconfigOptionListMerge (XConfigOptionPtr head, XConfigOptionPtr tail) +{ + XConfigOptionPtr a, b, ap = NULL, bp = NULL; + + a = tail; + b = head; + while (tail && b) { + if (xconfigNameCompare (a->name, b->name) == 0) { + if (b == head) + head = a; + else + bp->next = a; + if (a == tail) + tail = a->next; + else + ap->next = a->next; + a->next = b->next; + b->next = NULL; + xconfigOptionListFree (b); + b = a->next; + bp = a; + a = tail; + ap = NULL; + } else { + ap = a; + if (!(a = a->next)) { + a = tail; + bp = b; + b = b->next; + ap = NULL; + } + } + } + + if (head) { + for (a = head; a->next; a = a->next) + ; + a->next = tail; + } else + head = tail; + + return (head); +} + +char * +xconfigULongToString(unsigned long i) +{ + char *s; + int l; + + l = (int)(ceil(log10((double)i) + 2.5)); + s = malloc(l); + if (!s) + return NULL; + sprintf(s, "%lu", i); + return s; +} + +XConfigOptionPtr +xconfigParseOption(XConfigOptionPtr head) +{ + XConfigOptionPtr option, cnew, old; + char *name, *comment = NULL; + int token; + + if ((token = xconfigGetSubToken(&comment)) != STRING) { + xconfigErrorMsg(ParseErrorMsg, BAD_OPTION_MSG); + if (comment) + free(comment); + return (head); + } + + name = val.str; + if ((token = xconfigGetSubToken(&comment)) == STRING) { + option = xconfigNewOption(name, val.str); + option->comment = comment; + if ((token = xconfigGetToken(NULL)) == COMMENT) + option->comment = xconfigAddComment(option->comment, val.str); + else + xconfigUnGetToken(token); + } + else { + option = xconfigNewOption(name, NULL); + option->comment = comment; + if (token == COMMENT) + option->comment = xconfigAddComment(option->comment, val.str); + else + xconfigUnGetToken(token); + } + + old = NULL; + + /* Don't allow duplicates */ + if (head != NULL && (old = xconfigFindOption(head, name)) != NULL) { + cnew = old; + free(option->name); + TEST_FREE(option->val); + TEST_FREE(option->comment); + free(option); + } + else + cnew = option; + + if (old == NULL) + return ((XConfigOptionPtr)xconfigAddListItem((GenericListPtr)head, + (GenericListPtr)cnew)); + + return (head); +} + +void +xconfigPrintOptionList(FILE *fp, XConfigOptionPtr list, int tabs) +{ + int i; + + if (!list) + return; + while (list) { + for (i = 0; i < tabs; i++) + fprintf(fp, " "); + if (list->val) + fprintf(fp, "Option \"%s\" \"%s\"", list->name, list->val); + else + fprintf(fp, "Option \"%s\"", list->name); + if (list->comment) + fprintf(fp, "%s", list->comment); + else + fputc('\n', fp); + list = list->next; + } +} diff --git a/src/XF86Config-parser/Generate.c b/src/XF86Config-parser/Generate.c new file mode 100644 index 0000000..d61771a --- /dev/null +++ b/src/XF86Config-parser/Generate.c @@ -0,0 +1,1330 @@ +/* + * nvidia-xconfig: A tool for manipulating X config files, + * specifically for use by the NVIDIA Linux graphics driver. + * + * Copyright (C) 2005 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + * + * Generate.c + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> + + +#include "xf86Parser.h" +#include "Configint.h" + +#define MOUSE_IDENTIFER "Mouse0" +#define KEYBOARD_IDENTIFER "Keyboard0" + +#define SCREEN_IDENTIFIER "Screen%d" +#define DEVICE_IDENTIFIER "Device%d" +#define MONITOR_IDENTIFIER "Monitor%d" + + +static int is_file(const char *filename); + +static void add_files(GenerateOptions *gop, XConfigPtr config); +static void add_font_path(GenerateOptions *gop, XConfigPtr config); +static void add_modules(GenerateOptions *gop, XConfigPtr config); + +static XConfigDevicePtr +add_device(XConfigPtr config, int bus, int slot, char *boardname, int count); + +static void add_layout(GenerateOptions *gop, XConfigPtr config); + +static void add_inputref(XConfigPtr config, XConfigLayoutPtr layout, + char *name, char *coreKeyword); + +/* + * xconfigGenerate() - generate a new XConfig from scratch + */ + +XConfigPtr xconfigGenerate(GenerateOptions *gop) +{ + XConfigPtr config; + + config = xconfigAlloc(sizeof(XConfigRec)); + + /* add files, fonts, and modules */ + + add_files(gop, config); + add_font_path(gop, config); + add_modules(gop, config); + + /* add the keyboard and mouse */ + + xconfigAddKeyboard(gop, config); + xconfigAddMouse(gop, config); + + /* add the layout */ + + add_layout(gop, config); + + return config; + +} /* xconfigGenerate() */ + + + +/* + * xconfigGenerateAddScreen() - add a new screen to the config; bus + * and slot can be -1 to be ignored; boardname can be NULL to be + * ignored; count is used when building the identifier name, eg + * '"Screen%d", count'. Note that this does not append the screen to + * any layout's adjacency list. + */ + +XConfigScreenPtr xconfigGenerateAddScreen(XConfigPtr config, + int bus, int slot, + char *boardname, int count) +{ + XConfigScreenPtr screen, s; + XConfigDevicePtr device; + XConfigMonitorPtr monitor; + + monitor = xconfigAddMonitor(config, count); + device = add_device(config, bus, slot, boardname, count); + + screen = xconfigAlloc(sizeof(XConfigScreenRec)); + + screen->identifier = xconfigAlloc(32); + snprintf(screen->identifier, 32, SCREEN_IDENTIFIER, count); + + screen->device_name = xconfigStrdup(device->identifier); + screen->device = device; + + screen->monitor_name = xconfigStrdup(monitor->identifier); + screen->monitor = monitor; + + screen->defaultdepth = 24; + + screen->displays = xconfigAddDisplay(screen->displays, + screen->defaultdepth); + + /* append to the end of the screen list */ + + if (!config->screens) { + config->screens = screen; + } else { + for (s = config->screens; s->next; s = s->next); + s->next = screen; + } + + return screen; + +} /* xconfigGenerateAddScreen() */ + + + +/* + * assign_screen_adjacencies() - setup all the adjacency information + * for the X screens in the given layout. Nothing fancy here: just + * position all the screens horizontally, moving from left to right. + */ + +void xconfigGenerateAssignScreenAdjacencies(XConfigLayoutPtr layout) +{ + XConfigAdjacencyPtr adj, prev = NULL; + + for (adj = layout->adjacencies; adj; adj = adj->next) { + + if (prev) { + adj->where = CONF_ADJ_RIGHTOF; + adj->refscreen = xconfigStrdup(prev->screen_name); + } else { + adj->x = adj->y = -1; + } + + /* make sure all the obsolete positioning is empty */ + + adj->top = NULL; + adj->top_name = NULL; + adj->bottom = NULL; + adj->bottom_name = NULL; + adj->left = NULL; + adj->left_name = NULL; + adj->right = NULL; + adj->right_name = NULL; + + prev = adj; + } + +} /* xconfigGenerateAssignScreenAdjacencies() */ + + + +/*********************************************************************/ + + + +/* + * is_file() + */ + +static int is_file(const char *filename) +{ + return (access(filename, F_OK) == 0); + +} /* is_file() */ + + +/* + * find_libdir() - attempt to find the X server library path; this is + * either + * + * `pkg-config --variable=libdir xorg-server` + * + * or + * + * [X PROJECT ROOT]/lib + */ + +static char *find_libdir(GenerateOptions *gop) +{ + struct stat stat_buf; + FILE *stream = NULL; + char *s, *libdir = NULL; + + /* + * run the pkg-config command and read the output; if the output + * is a directory, then return that as the libdir + */ + + stream = popen("pkg-config --variable=libdir xorg-server", "r"); + + if (stream) { + char buf[256]; + + buf[0] = '\0'; + + while (1) { + if (fgets(buf, 255, stream) == NULL) break; + + if (buf[0] != '\0') { + + /* truncate any newline */ + + s = strchr(buf, '\n'); + if (s) *s = '\0'; + + if ((stat(buf, &stat_buf) == 0) && + (S_ISDIR(stat_buf.st_mode))) { + + libdir = xconfigStrdup(buf); + break; + } + } + } + + pclose(stream); + + if (libdir) return libdir; + } + + /* otherwise, just fallback to [X PROJECT ROOT]/lib */ + + return xconfigStrcat(gop->x_project_root, "/lib", NULL); + +} /* find_libdir() */ + + + +/* + * add_files() - + */ + +static void add_files(GenerateOptions *gop, XConfigPtr config) +{ + char *libdir = find_libdir(gop); + + config->files = xconfigAlloc(sizeof(XConfigFilesRec)); + config->files->rgbpath = xconfigStrcat(libdir, "/X11/rgb", NULL); + + free(libdir); + +} /* add_files() */ + + +/* + * add_font_path() - scan through the __font_paths[] array, + * temporarily chop off the ":unscaled" appendage, and check for the + * file "fonts.dir" in the directory. If fonts.dir exists, append the + * path to config->files->fontpath. + */ + +static void add_font_path(GenerateOptions *gop, XConfigPtr config) +{ + int i, ret; + char *path, *p, *orig, *fonts_dir, *libdir; + + /* + * The below font path has been constructed from various examples + * and uses some suggests from the Font De-uglification HOWTO + */ + + static const char *__font_paths[] = { + "LIBDIR/X11/fonts/local/", + "LIBDIR/X11/fonts/misc/:unscaled", + "LIBDIR/X11/fonts/100dpi/:unscaled", + "LIBDIR/X11/fonts/75dpi/:unscaled", + "LIBDIR/X11/fonts/misc/", + "LIBDIR/X11/fonts/Type1/", + "LIBDIR/X11/fonts/CID/", + "LIBDIR/X11/fonts/Speedo/", + "LIBDIR/X11/fonts/100dpi/", + "LIBDIR/X11/fonts/75dpi/", + "LIBDIR/X11/fonts/cyrillic/", + "LIBDIR/X11/fonts/TTF/", + "LIBDIR/X11/fonts/truetype/", + "LIBDIR/X11/fonts/TrueType/", + "LIBDIR/X11/fonts/Type1/sun/", + "LIBDIR/X11/fonts/F3bitmaps/", + "/usr/local/share/fonts/ttfonts", + "/usr/share/fonts/default/Type1", + "/usr/lib/openoffice/share/fonts/truetype", + NULL + }; + + /* + * if a font server is running, set the font path to that + * + * XXX should we check the port the font server is using? + */ +#if defined(NV_SUNOS) + ret = system("ps -e -o fname | grep -v grep | egrep \"^xfs$\" > /dev/null"); +#elif defined(NV_BSD) + ret = system("ps -e -o comm | grep -v grep | egrep \"^xfs$\" > /dev/null"); +#else + ret = system("ps -C xfs 2>&1 > /dev/null"); +#endif + if (WEXITSTATUS(ret) == 0) { + config->files->fontpath = xconfigStrdup("unix/:7100"); + } else { + + /* get the X server libdir */ + + libdir = find_libdir(gop); + + for (i = 0; __font_paths[i]; i++) { + path = xconfigStrdup(__font_paths[i]); + + /* replace LIBDIR with libdir */ + + if (strncmp(path, "LIBDIR", 6) == 0) { + p = xconfigStrcat(libdir, path + 6, NULL); + free(path); + path = p; + } + + /* temporarily chop off any ":unscaled" appendage */ + + p = strchr(path, ':'); + if (p) *p = '\0'; + + /* skip this entry if the fonts.dir does not exist */ + + fonts_dir = xconfigStrcat(path, "/fonts.dir", NULL); + if (!is_file(fonts_dir)) { + /* does not exist */ + free(path); + free(fonts_dir); + continue; + } + free(fonts_dir); + + /* add the ":unscaled" back */ + + if (p) *p = ':'; + + /* + * either use this path as the fontpath, or append to the + * existing fontpath + */ + + if (config->files->fontpath) { + orig = config->files->fontpath; + config->files->fontpath = xconfigStrcat(orig, ",", path, NULL); + free(orig); + free(path); + } else { + config->files->fontpath = path; + } + } + + /* free the libdir string */ + + free(libdir); + } +} /* add_font_path() */ + + + +/* + * add_modules() + */ + +static void add_modules(GenerateOptions *gop, XConfigPtr config) +{ + XConfigLoadPtr l = NULL; + + config->modules = xconfigAlloc(sizeof(XConfigModuleRec)); + + l = xconfigAddNewLoadDirective(l, xconfigStrdup("dbe"), + XCONFIG_LOAD_MODULE, NULL, FALSE); + l = xconfigAddNewLoadDirective(l, xconfigStrdup("extmod"), + XCONFIG_LOAD_MODULE, NULL, FALSE); + l = xconfigAddNewLoadDirective(l, xconfigStrdup("type1"), + XCONFIG_LOAD_MODULE, NULL, FALSE); +#if defined(NV_SUNOS) + l = xconfigAddNewLoadDirective(l, xconfigStrdup("IA"), + XCONFIG_LOAD_MODULE, NULL, FALSE); + l = xconfigAddNewLoadDirective(l, xconfigStrdup("bitstream"), + XCONFIG_LOAD_MODULE, NULL, FALSE); +#else + l = xconfigAddNewLoadDirective(l, xconfigStrdup("freetype"), + XCONFIG_LOAD_MODULE, NULL, FALSE); +#endif + l = xconfigAddNewLoadDirective(l, xconfigStrdup("glx"), + XCONFIG_LOAD_MODULE, NULL, FALSE); + + config->modules->loads = l; + +} /* add_modules() */ + + + +/* + * xconfigAddMonitor() - + * + * XXX pass EDID values into this... + */ + +XConfigMonitorPtr xconfigAddMonitor(XConfigPtr config, int count) +{ + XConfigMonitorPtr monitor, m; + XConfigOptionPtr opt = NULL; + + /* XXX need to query resman for the EDID */ + + monitor = xconfigAlloc(sizeof(XConfigMonitorRec)); + + monitor->identifier = xconfigAlloc(32); + snprintf(monitor->identifier, 32, MONITOR_IDENTIFIER, count); + monitor->vendor = xconfigStrdup("Unknown"); /* XXX */ + monitor->modelname = xconfigStrdup("Unknown"); /* XXX */ + + /* XXX check EDID for freq ranges */ + + monitor->n_hsync = 1; + monitor->hsync[0].lo = 30.0; + monitor->hsync[0].hi = 110.0; + + monitor->n_vrefresh = 1; + monitor->vrefresh[0].lo = 50.0; + monitor->vrefresh[0].hi = 150.0; + + opt = xconfigAddNewOption(opt, xconfigStrdup("DPMS"), NULL); + + monitor->options = opt; + + /* append to the end of the monitor list */ + + if (!config->monitors) { + config->monitors = monitor; + } else { + for (m = config->monitors; m->next; m = m->next); + m->next = monitor; + } + + return monitor; + +} /* xconfigAddMonitor() */ + + + +/* + * add_device() + */ + +static XConfigDevicePtr +add_device(XConfigPtr config, int bus, int slot, char *boardname, int count) +{ + XConfigDevicePtr device, d; + + device = xconfigAlloc(sizeof(XConfigDeviceRec)); + + device->identifier = xconfigAlloc(32); + snprintf(device->identifier, 32, DEVICE_IDENTIFIER, count); + device->driver = xconfigStrdup("nvidia"); + device->vendor = xconfigStrdup("NVIDIA Corporation"); + + if (bus != -1 && slot != -1) { + device->busid = xconfigAlloc(32); + snprintf(device->busid, 32, "PCI:%d:%d:0", bus, slot); + } + + if (boardname) device->board = xconfigStrdup(boardname); + + device->chipid = -1; + device->chiprev = -1; + device->irq = -1; + device->screen = -1; + + /* append to the end of the device list */ + + if (!config->devices) { + config->devices = device; + } else { + for (d = config->devices; d->next; d = d->next); + d->next = device; + } + + return device; + +} /* add_device() */ + + + +XConfigDisplayPtr xconfigAddDisplay(XConfigDisplayPtr head, const int depth) +{ + XConfigDisplayPtr display; + XConfigModePtr mode = NULL; + + mode = xconfigAddMode(mode, "640x480"); + mode = xconfigAddMode(mode, "800x600"); + mode = xconfigAddMode(mode, "1024x768"); + mode = xconfigAddMode(mode, "1280x1024"); + mode = xconfigAddMode(mode, "1600x1200"); + + display = xconfigAlloc(sizeof(XConfigDisplayRec)); + display->depth = depth; + display->modes = mode; + display->frameX0 = -1; + display->frameY0 = -1; + display->black.red = -1; + display->white.red = -1; + + display->next = head; + + return display; +} + + + +/* + * add_layout() - add a layout section to the XConfigPtr + */ + +static void add_layout(GenerateOptions *gop, XConfigPtr config) +{ + XConfigLayoutPtr layout; + XConfigAdjacencyPtr adj; + XConfigScreenPtr screen; + + /* assume 1 X screen */ + + screen = xconfigGenerateAddScreen(config, -1, -1, NULL, 0); + + /* create layout */ + + layout = xconfigAlloc(sizeof(XConfigLayoutRec)); + + layout->identifier = xconfigStrdup("Layout0"); + + adj = xconfigAlloc(sizeof(XConfigAdjacencyRec)); + + adj->scrnum = 0; + adj->screen = screen; + adj->screen_name = xconfigStrdup(screen->identifier); + + layout->adjacencies = adj; + + xconfigGenerateAssignScreenAdjacencies(layout); + + add_inputref(config, layout, MOUSE_IDENTIFER, "CorePointer"); + add_inputref(config, layout, KEYBOARD_IDENTIFER, "CoreKeyboard"); + + layout->next = config->layouts; + config->layouts = layout; + +} /* add_layout() */ + + + +/* + * add_inputref() - add a new XConfigInputrefPtr to the given layout + */ + +static void add_inputref(XConfigPtr config, XConfigLayoutPtr layout, + char *name, char *coreKeyword) +{ + XConfigInputrefPtr inputRef; + + inputRef = xconfigAlloc(sizeof(XConfigInputrefRec)); + inputRef->input_name = xconfigStrdup(name); + inputRef->input = xconfigFindInput(inputRef->input_name, config->inputs); + inputRef->options = + xconfigAddNewOption(NULL, xconfigStrdup(coreKeyword), NULL); + inputRef->next = layout->inputs; + layout->inputs = inputRef; + +} /* add_inputref() */ + + + +/*********************************************************************/ + +/* + * Mouse detection + */ + + +typedef struct { + char *shortname; /* commandline name */ + char *name; /* mouse name */ + char *gpmproto; /* protocol used by gpm */ + char *Xproto; /* XFree86 Protocol */ + char *device; /* /dev/ file */ + int emulate3; /* Emulate3Buttons */ +} MouseEntry; + + +/* + * This table is based on data contained in + * /usr/lib/python2.2/site-packages/rhpl/mouse.py on Red Hat Fedora + * core 1. That file contains the following copyright: + * + * + * + * mouse.py: mouse configuration data + * + * Copyright 1999-2002 Red Hat, Inc. + * + * This software may be freely redistributed under the terms of the GNU + * library public license. + * + * You should have received a copy of the GNU Library Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +static const MouseEntry __mice[] = { + /* shortname name gpm protocol X protocol device emulate3 */ + { "alpsps/2", "ALPS - GlidePoint (PS/2)", "ps/2", "GlidePointPS/2", "psaux", TRUE }, + { "ascii", "ASCII - MieMouse (serial)", "ms3", "IntelliMouse", "ttyS", FALSE }, + { "asciips/2", "ASCII - MieMouse (PS/2)", "ps/2", "NetMousePS/2", "psaux", TRUE }, + { "atibm", "ATI - Bus Mouse", "Busmouse", "BusMouse", "atibm", TRUE }, + { "generic", "Generic - 2 Button Mouse (serial)", "Microsoft", "Microsoft", "ttyS", TRUE }, + { "generic3", "Generic - 3 Button Mouse (serial)", "Microsoft", "Microsoft", "ttyS", FALSE }, + { "genericps/2", "Generic - 2 Button Mouse (PS/2)", "ps/2", "PS/2", "psaux", TRUE }, + { "generic3ps/2", "Generic - 3 Button Mouse (PS/2)", "ps/2", "PS/2", "psaux", FALSE }, + { "genericwheelps/2", "Generic - Wheel Mouse (PS/2)", "imps2", "IMPS/2", "psaux", FALSE }, + { "genericusb", "Generic - 2 Button Mouse (USB)", "imps2", "IMPS/2", "input/mice", TRUE }, + { "generic3usb", "Generic - 3 Button Mouse (USB)", "imps2", "IMPS/2", "input/mice", FALSE }, + { "genericwheelusb", "Generic - Wheel Mouse (USB)", "imps2", "IMPS/2", "input/mice", FALSE }, + { "geniusnm", "Genius - NetMouse (serial)", "ms3", "IntelliMouse", "ttyS", TRUE }, + { "geniusnmps/2", "Genius - NetMouse (PS/2)", "netmouse", "NetMousePS/2", "psaux", TRUE }, + { "geniusprops/2", "Genius - NetMouse Pro (PS/2)", "netmouse", "NetMousePS/2", "psaux", TRUE }, + { "geniusscrollps/2", "Genius - NetScroll (PS/2)", "netmouse", "NetScrollPS/2", "psaux", TRUE }, + { "geniusscrollps/2+", "Genius - NetScroll+ (PS/2)", "netmouse", "NetMousePS/2", "psaux", FALSE }, + { "thinking", "Kensington - Thinking Mouse (serial)", "Microsoft", "ThinkingMouse", "ttyS", TRUE }, + { "thinkingps/2", "Kensington - Thinking Mouse (PS/2)", "ps/2", "ThinkingMousePS/2", "psaux", TRUE }, + { "logitech", "Logitech - C7 Mouse (serial, old C7 type)", "Logitech", "Logitech", "ttyS", FALSE }, + { "logitechcc", "Logitech - CC Series (serial)", "logim", "MouseMan", "ttyS", FALSE }, + { "logibm", "Logitech - Bus Mouse", "Busmouse", "BusMouse", "logibm", FALSE }, + { "logimman", "Logitech - MouseMan/FirstMouse (serial)", "MouseMan", "MouseMan", "ttyS", FALSE }, + { "logimmanps/2", "Logitech - MouseMan/FirstMouse (PS/2)", "ps/2", "PS/2", "psaux", FALSE }, + { "logimman+", "Logitech - MouseMan+/FirstMouse+ (serial)", "pnp", "IntelliMouse", "ttyS", FALSE }, + { "logimman+ps/2", "Logitech - MouseMan+/FirstMouse+ (PS/2)", "ps/2", "MouseManPlusPS/2", "psaux", FALSE }, + { "logimmusb", "Logitech - MouseMan Wheel (USB)", "ps/2", "IMPS/2", "input/mice", FALSE }, + { "logimmusboptical", "Logitech - Cordless Optical Mouse (USB)", "ps/2", "IMPS/2", "input/mice", FALSE }, + { "microsoft", "Microsoft - Compatible Mouse (serial)", "Microsoft", "Microsoft", "ttyS", TRUE }, + { "msnew", "Microsoft - Rev 2.1A or higher (serial)", "pnp", "Auto", "ttyS", TRUE }, + { "msintelli", "Microsoft - IntelliMouse (serial)", "ms3", "IntelliMouse", "ttyS", FALSE }, + { "msintellips/2", "Microsoft - IntelliMouse (PS/2)", "imps2", "IMPS/2", "psaux", FALSE }, + { "msintelliusb", "Microsoft - IntelliMouse (USB)", "ps/2", "IMPS/2", "input/mice", FALSE }, + { "msintelliusboptical","Microsoft - IntelliMouse Optical (USB)", "ps/2", "IMPS/2", "input/mice", FALSE }, + { "msbm", "Microsoft - Bus Mouse", "Busmouse", "BusMouse", "inportbm", TRUE }, + { "mousesystems", "Mouse Systems - Mouse (serial)", "MouseSystems", "MouseSystems", "ttyS", TRUE }, + { "mmseries", "MM - Series (serial)", "MMSeries", "MMSeries", "ttyS", TRUE }, + { "mmhittab", "MM - HitTablet (serial)", "MMHitTab", "MMHittab", "ttyS", TRUE }, + { "sun", "Sun - Mouse", "sun", "sun", "sunmouse", FALSE }, + { NULL, NULL, NULL, NULL, NULL, FALSE }, +}; + + + +/* + * This table maps between the mouse protocol name used for gpm and + * for the X server "protocol" mouse option. + */ + +typedef struct { + char *gpmproto; + char *Xproto; +} ProtocolEntry; + +static const ProtocolEntry __protocols[] = { + /* gpm protocol X protocol */ + { "ms3", "IntelliMouse" }, + { "Busmouse", "BusMouse" }, + { "Microsoft", "Microsoft" }, + { "imps2", "IMPS/2" }, + { "netmouse", "NetMousePS/2" }, + { "Logitech", "Logitech" }, + { "logim", "MouseMan" }, + { "MouseMan", "MouseMan" }, + { "ps/2", "PS/2" }, + { "pnp", "Auto" }, + { "MouseSystems", "MouseSystems" }, + { "MMSeries", "MMSeries" }, + { "MMHitTab", "MMHittab" }, + { "sun", "sun" }, + { NULL, NULL }, +}; + + +/* + * gpm_proto_to_X_proto() - map from gpm mouse protocol to X mouse + * protocol + */ + +static char* gpm_proto_to_X_proto(const char *gpm) +{ + int i; + + for (i = 0; __protocols[i].gpmproto; i++) { + if (strcmp(gpm, __protocols[i].gpmproto) == 0) { + return __protocols[i].Xproto; + } + } + return NULL; + +} /* gpm_proto_to_X_proto() */ + + + +/* + * find_mouse_entry() - scan the __mice[] table for the entry that + * corresponds to the specified value; return a pointer to the + * matching entry in the table, if any. + */ + +static const MouseEntry *find_mouse_entry(char *value) +{ + int i; + + if (!value) return NULL; + + for (i = 0; __mice[i].name; i++) { + if (strcmp(value, __mice[i].shortname) == 0) { + return &__mice[i]; + } + } + return NULL; + +} /* find_mouse_entry() */ + + + +/* + * find_closest_mouse_entry() - scan the __mice[] table for the entry that + * matches all of the specified values; any of the values can be NULL, + * in which case we do not use them as part of the comparison. Note + * that device is compared case sensitive, proto is compared case + * insensitive, and emulate3 is just a boolean. + */ + +static const MouseEntry *find_closest_mouse_entry(const char *device, + const char *proto, + const char *emulate3_str) +{ + int i; + int emulate3 = FALSE; + + /* + * translate the emulate3 string into a boolean we can use below + * for comparison + */ + + if ((emulate3_str) && + ((strcasecmp(emulate3_str, "yes") == 0) || + (strcasecmp(emulate3_str, "true") == 0) || + (strcasecmp(emulate3_str, "1") == 0))) { + emulate3 = TRUE; + } + + /* + * skip the "/dev/" part of the device filename + */ + + if (device && (strncmp(device, "/dev/", 5) == 0)) { + device += 5; /* strlen("/dev/") */ + } + + for (i = 0; __mice[i].name; i++) { + if ((device) && (strcmp(device, __mice[i].device) != 0)) continue; + if ((proto) && (strcasecmp(proto, __mice[i].Xproto)) != 0) continue; + if ((emulate3_str) && (emulate3 != __mice[i].emulate3)) continue; + return &__mice[i]; + } + + return NULL; + +} /* find_closest_mouse_entry() */ + + + +/* + * find_config_entry() - scan the specified filename for the specified + * keyword; return the value that the keyword is assigned to, or NULL + * if any error occurs. + */ + +static char *find_config_entry(const char *filename, const char *keyword) +{ + int fd = -1; + char *data = NULL; + char *value = NULL; + char *buf = NULL; + char *tmp, *start, *c, *end; + struct stat stat_buf; + size_t len; + + if ((fd = open(filename, O_RDONLY)) == -1) goto done; + + if (fstat(fd, &stat_buf) == -1) goto done; + + if ((data = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, + fd, 0)) == (void *) -1) goto done; + + /* + * create a sysmem copy of the buffer, so that we can explicitly + * NULL terminate it + */ + + buf = malloc(stat_buf.st_size + 1); + + if (!buf) goto done; + + memcpy(buf, data, stat_buf.st_size); + buf[stat_buf.st_size] = '\0'; + + /* search for the keyword */ + + start = buf; + + while (TRUE) { + tmp = strstr(start, keyword); + if (!tmp) goto done; + + /* + * make sure this line is not commented out: search back from + * tmp: if we hit a "#" before a newline, then this line is + * commented out and we should search again + */ + + c = tmp; + while ((c >= start) && (*c != '\n') && (*c != '#')) c--; + + if (*c == '#') { + /* keyword was commented out... search again */ + start = tmp+1; + } else { + /* keyword is not commented out */ + break; + } + } + + start = tmp + strlen(keyword); + end = strchr(start, '\n'); + if (!end) goto done; + + /* there must be something between the start and the end */ + + if (start == end) goto done; + + /* take what is between as the value */ + + len = end - start; + value = xconfigAlloc(len + 1); + strncpy(value, start, len); + value[len] = '\0'; + + /* if the first and last characters are quotation marks, remove them */ + + if ((value[0] == '\"') && (value[len-1] == '\"')) { + tmp = xconfigAlloc(len - 1); + strncpy(tmp, value + 1, len - 2); + tmp[len-2] = '\0'; + free(value); + value = tmp; + } + + done: + + if (buf) free(buf); + if (data) munmap(data, stat_buf.st_size); + if (fd != -1) close(fd); + + return value; + +} /* find_config_entry() */ + + + +/* + * xconfigGeneratePrintPossibleMice() - print the mouse table to stdout + */ + +void xconfigGeneratePrintPossibleMice(void) +{ + int i; + + printf("%-25s%-35s\n\n", "Short Name", "Name"); + + for (i = 0; __mice[i].name; i++) { + printf("%-25s%-35s\n", __mice[i].shortname, __mice[i].name); + } + + printf("\n"); + +} /* xconfigGeneratePrintPossibleMice() */ + + + +/* + * xconfigAddMouse() - determine the mouse type, and then add an + * XConfigInputRec with the appropriate options. + * + * - if the user specified on the commandline, use that + * + * - if /etc/sysconfig/mouse exists and contains valid data, use + * that + * + * - if /etc/conf.d/gpm exists and contains valid data, use that + * + * - infer the settings from the commandline options gpm is using XXX? + * + * - default to "auto" on /dev/mouse + */ + +int xconfigAddMouse(GenerateOptions *gop, XConfigPtr config) +{ + const MouseEntry *entry = NULL; + XConfigInputPtr input; + XConfigOptionPtr opt = NULL; + char *device_path, *comment = "default"; + + /* if the user specified on the commandline, use that */ + + if (gop->mouse) { + entry = find_mouse_entry(gop->mouse); + if (entry) { + comment = "commandline input"; + } else { + xconfigErrorMsg(WarnMsg, "Unable to find mouse \"%s\".", + gop->mouse); + } + } + + /* + * if /etc/sysconfig/mouse exists, and contains valid data, use + * that + */ + + if (!entry) { + char *protocol, *device, *emulate3; + + device = find_config_entry("/etc/sysconfig/mouse", "DEVICE="); + protocol = find_config_entry("/etc/sysconfig/mouse", "XMOUSETYPE="); + emulate3 = find_config_entry("/etc/sysconfig/mouse", "XEMU3="); + + if (device || protocol || emulate3) { + entry = find_closest_mouse_entry(device, protocol, emulate3); + if (entry) { + comment = "data in \"/etc/sysconfig/mouse\""; + } + } + } + + /* if /etc/conf.d/gpm exists and contains valid data, use that */ + + if (!entry) { + char *protocol, *device; + + protocol = find_config_entry("/etc/conf.d/gpm", "MOUSE="); + device = find_config_entry("/etc/conf.d/gpm", "MOUSEDEV="); + + if (protocol && device) { + MouseEntry *e = xconfigAlloc(sizeof(MouseEntry)); + e->shortname = "custom"; + e->name = "inferred from /etc/conf.d/gpm"; + e->gpmproto = protocol; + e->Xproto = gpm_proto_to_X_proto(protocol); + e->device = device + strlen("/dev/"); + e->emulate3 = FALSE; // XXX? + entry = e; + comment = "data in \"/etc/conf.d/gpm\""; + } + } + + /* + * XXX we could try to infer the settings from the commandline + * options gpm is using + */ + + if (!entry) { + /* XXX implement me */ + } + + /* at this point, we must have a mouse entry */ + + if (!entry) { + MouseEntry *e = xconfigAlloc(sizeof(MouseEntry)); + e->Xproto = "auto"; + +#if defined(NV_BSD) + e->device = "sysmouse"; +#else + if (access("/dev/psaux", F_OK) == 0) { + e->device = "psaux"; + } else if (access("/dev/input/mice", F_OK) == 0) { + e->device = "input/mice"; + } else { + e->device = "mouse"; + } +#endif + e->emulate3 = FALSE; + entry = e; + } + + /* add a new mouse input section */ + + input = xconfigAlloc(sizeof(XConfigInputRec)); + + input->comment = xconfigStrcat(" # generated from ", + comment, "\n", NULL); + input->identifier = xconfigStrdup("Mouse0"); + input->driver = xconfigStrdup("mouse"); + + device_path = xconfigStrcat("/dev/", entry->device, NULL); + + opt = xconfigAddNewOption(opt, xconfigStrdup("Protocol"), + xconfigStrdup(entry->Xproto)); + opt = xconfigAddNewOption(opt, xconfigStrdup("Device"), device_path); + opt = xconfigAddNewOption(opt, xconfigStrdup("Emulate3Buttons"), + entry->emulate3 ? + xconfigStrdup("yes") : xconfigStrdup("no")); + + /* + * This will make wheel mice work, and non-wheel mice should + * ignore ZAxisMapping + */ + + opt = xconfigAddNewOption(opt, xconfigStrdup("ZAxisMapping"), + xconfigStrdup("4 5")); + + input->options = opt; + + input->next = config->inputs; + config->inputs = input; + + return TRUE; + +} /* xconfigAddMouse() */ + + + + + +/*********************************************************************/ + +/* + * keyboard detection + */ + +typedef struct { + char *keytable; + char *name; + char *layout; /* XkbLayout */ + char *model; /* XkbModel */ + char *variant; /* XkbVariant */ + char *options; /* XkbOptions */ +} KeyboardEntry; + + +/* + * This table is based on data contained in + * /usr/lib/python2.2/site-packages/rhpl/keyboard_models.py on Red Hat + * Fedora core 1. That file contains the following copyright: + * + * + * keyboard_models.py - keyboard model list + * + * Brent Fox <bfox@redhat.com> + * Mike Fulbright <msf@redhat.com> + * Jeremy Katz <katzj@redhat.com> + * + * Copyright 2002 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +static const KeyboardEntry __keyboards[] = { + + /* keytable name layout model variant options */ + + { "be-latin1", "Belgian (be-latin1)", "be", "pc105", NULL, NULL }, + { "bg", "Bulgarian", "bg,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "br-abnt2", "Brazilian (ABNT2)", "br", "abnt2", NULL, NULL }, + { "cf", "French Canadian", "ca_enhanced", "pc105", NULL, NULL }, + { "croat", "Croatian", "hr", "pc105", NULL, NULL }, + { "cz-us-qwertz", "Czechoslovakian (qwertz)", "cz,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "cz-lat2", "Czechoslovakian", "cz_qwerty", "pc105", NULL, NULL }, + { "de", "German", "de", "pc105", NULL, NULL }, + { "de-latin1", "German (latin1)", "de", "pc105", NULL, NULL }, + { "de-latin1-nodeadkeys", "German (latin1 w/ no deadkeys)", "de", "pc105", "nodeadkeys", NULL }, + { "dvorak", "Dvorak", "dvorak", "pc105", NULL, NULL }, + { "dk", "Danish", "dk", "pc105", NULL, NULL }, + { "dk-latin1", "Danish (latin1)", "dk", "pc105", NULL, NULL }, + { "es", "Spanish", "es", "pc105", NULL, NULL }, + { "et", "Estonian", "ee", "pc105", NULL, NULL }, + { "fi", "Finnish", "fi", "pc105", NULL, NULL }, + { "fi-latin1", "Finnish (latin1)", "fi", "pc105", NULL, NULL }, + { "fr", "French", "fr", "pc105", NULL, NULL }, + { "fr-latin0", "French (latin0)", "fr", "pc105", NULL, NULL }, + { "fr-latin1", "French (latin1)", "fr", "pc105", NULL, NULL }, + { "fr-pc", "French (pc)", "fr", "pc105", NULL, NULL }, + { "fr_CH", "Swiss French", "fr_CH", "pc105", NULL, NULL }, + { "fr_CH-latin1", "Swiss French (latin1)", "fr_CH", "pc105", NULL, NULL }, + { "gr", "Greek", "us,el", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "hu", "Hungarian", "hu", "pc105", NULL, NULL }, + { "hu101", "Hungarian (101 key)", "hu", "pc105", NULL, NULL }, + { "is-latin1", "Icelandic", "is", "pc105", NULL, NULL }, + { "it", "Italian", "it", "pc105", NULL, NULL }, + { "it-ibm", "Italian (IBM)", "it", "pc105", NULL, NULL }, + { "it2", "Italian (it2)", "it", "pc105", NULL, NULL }, + { "jp106", "Japanese", "jp", "jp106", NULL, NULL }, + { "la-latin1", "Latin American", "la", "pc105", NULL, NULL }, + { "mk-utf", "Macedonian", "mk,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "no", "Norwegian", "no", "pc105", NULL, NULL }, + { "pl", "Polish", "pl", "pc105", NULL, NULL }, + { "pt-latin1", "Portuguese", "pt", "pc105", NULL, NULL }, + { "ro_win", "Romanian", "ro", "pc105", NULL, NULL }, + { "ru", "Russian", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "ru-cp1251", "Russian (cp1251)", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "ru-ms", "Russian (Microsoft)", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "ru1", "Russian (ru1)", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "ru2", "Russian (ru2)", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "ru_win", "Russian (win)", "ru,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "speakup", "Speakup", "us", "pc105", NULL, NULL }, + { "speakup-lt", "Speakup (laptop)", "us", "pc105", NULL, NULL }, + { "sv-latin1", "Swedish", "se", "pc105", NULL, NULL }, + { "sg", "Swiss German", "de_CH", "pc105", NULL, NULL }, + { "sg-latin1", "Swiss German (latin1)", "de_CH", "pc105", NULL, NULL }, + { "sk-qwerty", "Slovakian", "sk_qwerty", "pc105", NULL, NULL }, + { "slovene", "Slovenian", "si", "pc105", NULL, NULL }, + { "trq", "Turkish", "tr", "pc105", NULL, NULL }, + { "uk", "United Kingdom", "gb", "pc105", NULL, NULL }, + { "ua", "Ukrainian", "ua,us", "pc105", NULL, "grp:shift_toggle,grp_led:scroll" }, + { "us-acentos", "U.S. International", "us_intl", "pc105", NULL, NULL }, + { "us", "U.S. English", "us", "pc105", NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL, NULL }, +}; + + + +/* + * find_keyboard_entry() - scan the __keyboards[] table for the entry that + * corresponds to the specified value; return a pointer to the + * matching entry in the table, if any. + */ + +static const KeyboardEntry *find_keyboard_entry(char *value) +{ + int i; + + if (!value) return NULL; + + for (i = 0; __keyboards[i].name; i++) { + if (strcmp(value, __keyboards[i].keytable) == 0) { + return &__keyboards[i]; + } + } + return NULL; + +} /* find_keyboard_entry() */ + + + +/* + * xconfigGeneratePrintPossibleKeyboards() - print the keyboard table + */ + +void xconfigGeneratePrintPossibleKeyboards(void) +{ + int i; + + printf("%-25s%-35s\n\n", "Short Name", "Name"); + + for (i = 0; __keyboards[i].name; i++) { + printf("%-25s%-35s\n", __keyboards[i].keytable, __keyboards[i].name); + } + + printf("\n"); + +} /* xconfigGeneratePrintPossibleKeyboards() */ + + + +/* + * xconfigAddKeyboard() - determine the keyboard type, and then add an + * XConfigInputRec with the appropriate options. + * + * How to detect the keyboard: + * + * - if the user specified on the command line, use that + * + * - if /etc/sysconfig/keyboard exists, and contains a valid + * KEYTABLE entry, use that + */ + +int xconfigAddKeyboard(GenerateOptions *gop, XConfigPtr config) +{ + char *value, *comment = "default"; + const KeyboardEntry *entry = NULL; + + XConfigInputPtr input; + XConfigOptionPtr opt = NULL; + + /* + * if the user specified on the command line, use that + */ + + if (gop->keyboard) { + entry = find_keyboard_entry(gop->keyboard); + if (entry) { + comment = "commandline input"; + } else { + xconfigErrorMsg(WarnMsg, "Unable to find keyboard \"%s\".", + gop->keyboard); + } + } + + /* + * if /etc/sysconfig/keyboard exists, and contains a valid + * KEYTABLE entry, use that + */ + + if (!entry) { + value = find_config_entry("/etc/sysconfig/keyboard", "KEYTABLE="); + entry = find_keyboard_entry(value); + if (value) { + free(value); + } + if (entry) { + comment = "data in \"/etc/sysconfig/keyboard\""; + } + } + + /* add a new keyboard input section */ + + input = xconfigAlloc(sizeof(XConfigInputRec)); + + input->comment = xconfigStrcat(" # generated from ", + comment, "\n", NULL); + input->identifier = xconfigStrdup("Keyboard0"); + + /* + * determine which keyboard driver should be used (either "kbd" or + * "keyboard"); if the user specified a keyboard driver use that; + * if 'ROOT/lib/modules/input/kbd_drv.(o|so)' exists, use "kbd"; + * otherwise, use "keyboard". + * On Solaris, use the default "keyboard" + */ + + if (gop->keyboard_driver) { + input->driver = gop->keyboard_driver; + } else { +#if defined(NV_SUNOS) || defined(NV_BSD) + input->driver = xconfigStrdup("keyboard"); +#else + if (gop->xserver == X_IS_XORG) { + input->driver = xconfigStrdup("kbd"); + } else { + input->driver = xconfigStrdup("keyboard"); + } +#endif + } + + /* + * set additional keyboard options, based on the Keyboard table + * entry we found above + */ + + if (entry && entry->layout) + opt = xconfigAddNewOption(opt, + xconfigStrdup("XkbLayout"), + xconfigStrdup(entry->layout)); + if (entry && entry->model) + opt = xconfigAddNewOption(opt, + xconfigStrdup("XkbModel"), + xconfigStrdup(entry->model)); + if (entry && entry->variant) + opt = xconfigAddNewOption(opt, + xconfigStrdup("XkbVariant"), + xconfigStrdup(entry->variant)); + if (entry && entry->options) + opt = xconfigAddNewOption(opt, + xconfigStrdup("XkbOptions"), + xconfigStrdup(entry->options)); + + input->options = opt; + + input->next = config->inputs; + config->inputs = input; + + return TRUE; + +} /* xconfigAddKeyboard() */ diff --git a/src/XF86Config-parser/Input.c b/src/XF86Config-parser/Input.c new file mode 100644 index 0000000..1665600 --- /dev/null +++ b/src/XF86Config-parser/Input.c @@ -0,0 +1,424 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static +XConfigSymTabRec InputTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {OPTION, "option"}, + {DRIVER, "driver"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeInputList + +XConfigInputPtr +xconfigParseInputSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigInputPtr, XConfigInputRec) + + while ((token = xconfigGetToken (InputTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case DRIVER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Driver"); + ptr->driver = val.str; + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintInputSection (FILE * cf, XConfigInputPtr ptr) +{ + while (ptr) + { + fprintf (cf, "Section \"InputDevice\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + if (ptr->driver) + fprintf (cf, " Driver \"%s\"\n", ptr->driver); + xconfigPrintOptionList(cf, ptr->options, 1); + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigFreeInputList (XConfigInputPtr ptr) +{ + XConfigInputPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->driver); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +int +xconfigValidateInput (XConfigPtr p) +{ + XConfigInputPtr input = p->inputs; + +#if 0 /* Enable this later */ + if (!input) { + xconfigErrorMsg(ValidationErrorMsg, "At least one InputDevice section " + "is required."); + return (FALSE); + } +#endif + + while (input) { + if (!input->driver) { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_INPUTDRIVER_MSG, + input->identifier); + return (FALSE); + } + input = input->next; + } + return (TRUE); +} + +XConfigInputPtr +xconfigFindInput (const char *ident, XConfigInputPtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +XConfigInputPtr +xconfigFindInputByDriver (const char *driver, XConfigInputPtr p) +{ + while (p) + { + if (xconfigNameCompare (driver, p->driver) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + + + +static int getCoreInputDevice(GenerateOptions *gop, + XConfigPtr config, + XConfigLayoutPtr layout, + const int mouse, + const char *coreKeyword, + const char *implicitDriverName, + const char *defaultDriver0, + const char *defaultDriver1, + const char *foundMsg0, + const char *foundMsg1) +{ + XConfigInputPtr input, core = NULL; + XConfigInputrefPtr inputRef; + int found, firstTry; + const char *found_msg = NULL; + + /* + * First check if the core input device has been specified in the + * active ServerLayout. If more than one is specified, remove the + * core attribute from the later ones. + */ + + for (inputRef = layout->inputs; inputRef; inputRef = inputRef->next) { + XConfigOptionPtr opt1 = NULL, opt2 = NULL; + + input = inputRef->input; + + opt1 = xconfigFindOption(input->options, coreKeyword); + opt2 = xconfigFindOption(inputRef->options, coreKeyword); + + if (opt1 || opt2) { + if (!core) { + core = input; + } else { + if (opt1) input->options = + xconfigRemoveOption(input->options, opt1); + if (opt2) inputRef->options = + xconfigRemoveOption(inputRef->options, opt2); + xconfigErrorMsg(WarnMsg, "Duplicate %s devices; removing %s " + "attribute from \"%s\"\n", + coreKeyword, coreKeyword, input->identifier); + } + } + } + + /* + * XXX XFree86 allows the commandline to override the core input + * devices; let's not bother with that, here. + */ + + /* + * if we didn't find a core input device above in the + * serverLayout, scan through the config's entire input list and + * pick the first one with the coreKeyword. + */ + + if (!core) { + for (input = config->inputs; input; input = input->next) { + if (xconfigFindOption(input->options, coreKeyword)) { + core = input; + found_msg = foundMsg0; + break; + } + } + } + + /* + * if we didn't find a core input device above, then select the + * first input with the correct driver + */ + + firstTry = TRUE; + + tryAgain: + + if (!core) { + input = xconfigFindInput(implicitDriverName, config->inputs); + if (!input && defaultDriver0) { + input = xconfigFindInputByDriver(defaultDriver0, config->inputs); + } + if (!input && defaultDriver1) { + input = xconfigFindInputByDriver(defaultDriver1, config->inputs); + } + if (input) { + core = input; + found_msg = foundMsg1; + } + } + + /* + * if we didn't find a core input device above, then that means we + * don't have any input devices of this type; try to add a new + * input device of this type, and then try again to find a core + * input device + */ + + if (!core && firstTry) { + firstTry = FALSE; + + xconfigErrorMsg(WarnMsg, "Unable to find %s in X configuration; " + "attempting to add new %s section.", + coreKeyword, coreKeyword); + + if (mouse) { + xconfigAddMouse(gop, config); + } else { + xconfigAddKeyboard(gop, config); + } + goto tryAgain; + } + + /* + * if we *still* can't find a core input device, print a warning + * message and give up; hopefully the X server's builtin config + * will do. + */ + + if (!core) { + xconfigErrorMsg(WarnMsg, "Unable to determine %s; will rely on X " + "server's built-in default configuration.", + coreKeyword); + + /* don't return FALSE here -- we don't want nvidia-xconfig to fail */ + + return TRUE; + } + + + /* + * make sure the core input device is in the layout's input list + */ + + found = FALSE; + for (inputRef = layout->inputs; inputRef; inputRef = inputRef->next) { + if (inputRef->input == core) { + found = TRUE; + break; + } + } + if (!found) { + inputRef = calloc(1, sizeof(XConfigInputrefRec)); + inputRef->input = core; + inputRef->input_name = strdup(core->identifier); + inputRef->next = layout->inputs; + layout->inputs = inputRef; + } + + /* + * make sure the core input device has the core keyword set + */ + + for (inputRef = layout->inputs; inputRef; inputRef = inputRef->next) { + if (inputRef->input == core) { + XConfigOptionPtr opt1 = NULL, opt2 = NULL; + + opt1 = xconfigFindOption(inputRef->input->options, coreKeyword); + opt2 = xconfigFindOption(inputRef->options, coreKeyword); + + if (!opt1 && !opt2) { + inputRef->options = xconfigAddNewOption(inputRef->options, + strdup(coreKeyword), + NULL); + } + break; + } + } + + if (found_msg) { + xconfigErrorMsg(WarnMsg, "The %s device was not specified explicitly " + "in the layout; using the %s.\n", coreKeyword, found_msg); + } + + return TRUE; +} + + + +/* + * xconfigCheckCoreInputDevices() - check that the specified layout has a + * corePointer and coreKeyboard. If it does not have them, they will + * be added from the current list of input devices. + */ + +int xconfigCheckCoreInputDevices(GenerateOptions *gop, + XConfigPtr config, + XConfigLayoutPtr layout) +{ + int ret; + + ret = getCoreInputDevice(gop, + config, + layout, + TRUE, + "CorePointer", + CONF_IMPLICIT_POINTER, + "mouse", NULL, + "first CorePointer in the config input list", + "first mouse device"); + + if (!ret) return FALSE; + + ret = getCoreInputDevice(gop, + config, + layout, + FALSE, + "CoreKeyboard", + CONF_IMPLICIT_KEYBOARD, + "keyboard", "kbd", + "first CoreKeyboard in the config input list", + "first keyboard device"); + if (!ret) return FALSE; + + return TRUE; +} diff --git a/src/XF86Config-parser/Keyboard.c b/src/XF86Config-parser/Keyboard.c new file mode 100644 index 0000000..26bbb73 --- /dev/null +++ b/src/XF86Config-parser/Keyboard.c @@ -0,0 +1,304 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" +#include "ctype.h" + +extern LexRec val; + +static XConfigSymTabRec KeyboardTab[] = +{ + {ENDSECTION, "endsection"}, + {KPROTOCOL, "protocol"}, + {AUTOREPEAT, "autorepeat"}, + {XLEDS, "xleds"}, + {PANIX106, "panix106"}, + {XKBKEYMAP, "xkbkeymap"}, + {XKBCOMPAT, "xkbcompat"}, + {XKBTYPES, "xkbtypes"}, + {XKBKEYCODES, "xkbkeycodes"}, + {XKBGEOMETRY, "xkbgeometry"}, + {XKBSYMBOLS, "xkbsymbols"}, + {XKBDISABLE, "xkbdisable"}, + {XKBRULES, "xkbrules"}, + {XKBMODEL, "xkbmodel"}, + {XKBLAYOUT, "xkblayout"}, + {XKBVARIANT, "xkbvariant"}, + {XKBOPTIONS, "xkboptions"}, + /* The next two have become ServerFlags options */ + {VTINIT, "vtinit"}, + {VTSYSREQ, "vtsysreq"}, + /* Obsolete keywords */ + {SERVERNUM, "servernumlock"}, + {LEFTALT, "leftalt"}, + {RIGHTALT, "rightalt"}, + {RIGHTALT, "altgr"}, + {SCROLLLOCK_TOK, "scrolllock"}, + {RIGHTCTL, "rightctl"}, + {-1, ""}, +}; + +/* Obsolete */ +static XConfigSymTabRec KeyMapTab[] = +{ + {CONF_KM_META, "meta"}, + {CONF_KM_COMPOSE, "compose"}, + {CONF_KM_MODESHIFT, "modeshift"}, + {CONF_KM_MODELOCK, "modelock"}, + {CONF_KM_SCROLLLOCK, "scrolllock"}, + {CONF_KM_CONTROL, "control"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeInputList + +XConfigInputPtr +xconfigParseKeyboardSection (void) +{ + char *s, *s1, *s2; + int l; + int token, ntoken; + PARSE_PROLOGUE (XConfigInputPtr, XConfigInputRec) + + while ((token = xconfigGetToken (KeyboardTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case KPROTOCOL: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Protocol"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("Protocol"), + val.str); + break; + case AUTOREPEAT: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (AUTOREPEAT_MSG, NULL); + s1 = xconfigULongToString(val.num); + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (AUTOREPEAT_MSG, NULL); + s2 = xconfigULongToString(val.num); + l = strlen(s1) + 1 + strlen(s2) + 1; + s = malloc(l); + sprintf(s, "%s %s", s1, s2); + free(s1); + free(s2); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("AutoRepeat"), s); + break; + case XLEDS: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (XLEDS_MSG, NULL); + s = xconfigULongToString(val.num); + l = strlen(s) + 1; + while ((token = xconfigGetSubToken(&(ptr->comment))) == NUMBER) + { + s1 = xconfigULongToString(val.num); + l += (1 + strlen(s1)); + s = realloc(s, l); + strcat(s, " "); + strcat(s, s1); + free(s1); + } + xconfigUnGetToken (token); + break; + case SERVERNUM: + xconfigErrorMsg(ParseWarningMsg, OBSOLETE_MSG, + xconfigTokenString()); + break; + case LEFTALT: + case RIGHTALT: + case SCROLLLOCK_TOK: + case RIGHTCTL: + xconfigErrorMsg(ParseWarningMsg, OBSOLETE_MSG, + xconfigTokenString()); + break; + ntoken = xconfigGetToken (KeyMapTab); + switch (ntoken) + { + case EOF_TOKEN: + xconfigErrorMsg(ParseErrorMsg, UNEXPECTED_EOF_MSG); + CLEANUP (ptr); + return (NULL); + break; + + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + break; + case VTINIT: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "VTInit"); + xconfigErrorMsg(ParseWarningMsg, MOVED_TO_FLAGS_MSG, "VTInit"); + break; + case VTSYSREQ: + xconfigErrorMsg(ParseWarningMsg, + MOVED_TO_FLAGS_MSG, "VTSysReq"); + break; + case XKBDISABLE: + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbDisable"), + NULL); + break; + case XKBKEYMAP: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBKeymap"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbKeymap"), + val.str); + break; + case XKBCOMPAT: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBCompat"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbCompat"), + val.str); + break; + case XKBTYPES: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBTypes"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbTypes"), + val.str); + break; + case XKBKEYCODES: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBKeycodes"); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbKeycodes"), + val.str); + break; + case XKBGEOMETRY: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBGeometry"); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbGeometry"), + val.str); + break; + case XKBSYMBOLS: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBSymbols"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbSymbols"), + val.str); + break; + case XKBRULES: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBRules"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbRules"), + val.str); + break; + case XKBMODEL: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBModel"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbModel"), + val.str); + break; + case XKBLAYOUT: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBLayout"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbLayout"), + val.str); + break; + case XKBVARIANT: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBVariant"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbVariant"), + val.str); + break; + case XKBOPTIONS: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "XKBOptions"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("XkbOptions"), + val.str); + break; + case PANIX106: + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("Panix106"), + NULL); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + ptr->identifier = xconfigStrdup(CONF_IMPLICIT_KEYBOARD); + ptr->driver = xconfigStrdup("keyboard"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("CoreKeyboard"), NULL); + + return ptr; +} + diff --git a/src/XF86Config-parser/Layout.c b/src/XF86Config-parser/Layout.c new file mode 100644 index 0000000..1e62d26 --- /dev/null +++ b/src/XF86Config-parser/Layout.c @@ -0,0 +1,607 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" +#include <string.h> + +extern LexRec val; + +static XConfigSymTabRec LayoutTab[] = +{ + {ENDSECTION, "endsection"}, + {SCREEN, "screen"}, + {IDENTIFIER, "identifier"}, + {INACTIVE, "inactive"}, + {INPUTDEVICE, "inputdevice"}, + {OPTION, "option"}, + {-1, ""}, +}; + +static XConfigSymTabRec AdjTab[] = +{ + {RIGHTOF, "rightof"}, + {LEFTOF, "leftof"}, + {ABOVE, "above"}, + {BELOW, "below"}, + {RELATIVE, "relative"}, + {ABSOLUTE, "absolute"}, + {-1, ""}, +}; + + +static int addImpliedLayout(XConfigPtr config, const char *screenName); + + +#define CLEANUP xconfigFreeLayoutList + +XConfigLayoutPtr +xconfigParseLayoutSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigLayoutPtr, XConfigLayoutRec) + + while ((token = xconfigGetToken (LayoutTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case INACTIVE: + { + XConfigInactivePtr iptr; + + iptr = calloc (1, sizeof (XConfigInactiveRec)); + iptr->next = NULL; + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (INACTIVE_MSG, NULL); + iptr->device_name = val.str; + ptr->inactives = (XConfigInactivePtr) + xconfigAddListItem((GenericListPtr) ptr->inactives, + (GenericListPtr) iptr); + } + break; + case SCREEN: + { + XConfigAdjacencyPtr aptr; + int absKeyword = 0; + + aptr = calloc (1, sizeof (XConfigAdjacencyRec)); + aptr->next = NULL; + aptr->scrnum = -1; + aptr->where = CONF_ADJ_OBSOLETE; + aptr->x = 0; + aptr->y = 0; + aptr->refscreen = NULL; + if ((token = xconfigGetSubToken (&(ptr->comment))) == NUMBER) + aptr->scrnum = val.num; + else + xconfigUnGetToken (token); + token = xconfigGetSubToken(&(ptr->comment)); + if (token != STRING) + Error (SCREEN_MSG, NULL); + aptr->screen_name = val.str; + + token = xconfigGetSubTokenWithTab(&(ptr->comment), AdjTab); + switch (token) + { + case RIGHTOF: + aptr->where = CONF_ADJ_RIGHTOF; + break; + case LEFTOF: + aptr->where = CONF_ADJ_LEFTOF; + break; + case ABOVE: + aptr->where = CONF_ADJ_ABOVE; + break; + case BELOW: + aptr->where = CONF_ADJ_BELOW; + break; + case RELATIVE: + aptr->where = CONF_ADJ_RELATIVE; + break; + case ABSOLUTE: + aptr->where = CONF_ADJ_ABSOLUTE; + absKeyword = 1; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + xconfigUnGetToken (token); + token = xconfigGetSubToken(&(ptr->comment)); + if (token == STRING) + aptr->where = CONF_ADJ_OBSOLETE; + else + aptr->where = CONF_ADJ_ABSOLUTE; + } + switch (aptr->where) + { + case CONF_ADJ_ABSOLUTE: + if (absKeyword) + token = xconfigGetSubToken(&(ptr->comment)); + if (token == NUMBER) + { + aptr->x = val.num; + token = xconfigGetSubToken(&(ptr->comment)); + if (token != NUMBER) + Error(INVALID_SCR_MSG, NULL); + aptr->y = val.num; + } else { + if (absKeyword) + Error(INVALID_SCR_MSG, NULL); + else + xconfigUnGetToken (token); + } + break; + case CONF_ADJ_RIGHTOF: + case CONF_ADJ_LEFTOF: + case CONF_ADJ_ABOVE: + case CONF_ADJ_BELOW: + case CONF_ADJ_RELATIVE: + token = xconfigGetSubToken(&(ptr->comment)); + if (token != STRING) + Error(INVALID_SCR_MSG, NULL); + aptr->refscreen = val.str; + if (aptr->where == CONF_ADJ_RELATIVE) + { + token = xconfigGetSubToken(&(ptr->comment)); + if (token != NUMBER) + Error(INVALID_SCR_MSG, NULL); + aptr->x = val.num; + token = xconfigGetSubToken(&(ptr->comment)); + if (token != NUMBER) + Error(INVALID_SCR_MSG, NULL); + aptr->y = val.num; + } + break; + case CONF_ADJ_OBSOLETE: + /* top */ + aptr->top_name = val.str; + + /* bottom */ + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (SCREEN_MSG, NULL); + aptr->bottom_name = val.str; + + /* left */ + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (SCREEN_MSG, NULL); + aptr->left_name = val.str; + + /* right */ + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (SCREEN_MSG, NULL); + aptr->right_name = val.str; + + } + ptr->adjacencies = (XConfigAdjacencyPtr) + xconfigAddListItem((GenericListPtr) ptr->adjacencies, + (GenericListPtr) aptr); + } + break; + case INPUTDEVICE: + { + XConfigInputrefPtr iptr; + + iptr = calloc (1, sizeof (XConfigInputrefRec)); + iptr->next = NULL; + iptr->options = NULL; + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (INPUTDEV_MSG, NULL); + iptr->input_name = val.str; + while ((token = xconfigGetSubToken (&(ptr->comment))) == STRING) + { + iptr->options = + xconfigAddNewOption (iptr->options, val.str, NULL); + } + xconfigUnGetToken (token); + ptr->inputs = (XConfigInputrefPtr) + xconfigAddListItem((GenericListPtr) ptr->inputs, + (GenericListPtr) iptr); + } + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintLayoutSection (FILE * cf, XConfigLayoutPtr ptr) +{ + XConfigAdjacencyPtr aptr; + XConfigInactivePtr iptr; + XConfigInputrefPtr inptr; + XConfigOptionPtr optr; + + while (ptr) + { + fprintf (cf, "Section \"ServerLayout\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + + for (aptr = ptr->adjacencies; aptr; aptr = aptr->next) + { + fprintf (cf, " Screen "); + if (aptr->scrnum >= 0) + fprintf (cf, "%2d", aptr->scrnum); + else + fprintf (cf, " "); + fprintf (cf, " \"%s\"", aptr->screen_name); + switch(aptr->where) + { + case CONF_ADJ_OBSOLETE: + fprintf (cf, " \"%s\"", aptr->top_name); + fprintf (cf, " \"%s\"", aptr->bottom_name); + fprintf (cf, " \"%s\"", aptr->right_name); + fprintf (cf, " \"%s\"\n", aptr->left_name); + break; + case CONF_ADJ_ABSOLUTE: + if (aptr->x != -1) + fprintf (cf, " %d %d\n", aptr->x, aptr->y); + else + fprintf (cf, "\n"); + break; + case CONF_ADJ_RIGHTOF: + fprintf (cf, " RightOf \"%s\"\n", aptr->refscreen); + break; + case CONF_ADJ_LEFTOF: + fprintf (cf, " LeftOf \"%s\"\n", aptr->refscreen); + break; + case CONF_ADJ_ABOVE: + fprintf (cf, " Above \"%s\"\n", aptr->refscreen); + break; + case CONF_ADJ_BELOW: + fprintf (cf, " Below \"%s\"\n", aptr->refscreen); + break; + case CONF_ADJ_RELATIVE: + fprintf (cf, " Relative \"%s\" %d %d\n", aptr->refscreen, + aptr->x, aptr->y); + break; + } + } + for (iptr = ptr->inactives; iptr; iptr = iptr->next) + fprintf (cf, " Inactive \"%s\"\n", iptr->device_name); + for (inptr = ptr->inputs; inptr; inptr = inptr->next) + { + fprintf (cf, " InputDevice \"%s\"", inptr->input_name); + for (optr = inptr->options; optr; optr = optr->next) + { + fprintf(cf, " \"%s\"", optr->name); + } + fprintf(cf, "\n"); + } + xconfigPrintOptionList(cf, ptr->options, 1); + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigFreeLayoutList (XConfigLayoutPtr ptr) +{ + XConfigLayoutPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->comment); + xconfigFreeAdjacencyList (ptr->adjacencies); + xconfigFreeInputrefList (ptr->inputs); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeAdjacencyList (XConfigAdjacencyPtr ptr) +{ + XConfigAdjacencyPtr prev; + + while (ptr) + { + TEST_FREE (ptr->screen_name); + TEST_FREE (ptr->top_name); + TEST_FREE (ptr->bottom_name); + TEST_FREE (ptr->left_name); + TEST_FREE (ptr->right_name); + + prev = ptr; + ptr = ptr->next; + free (prev); + } + +} + +void +xconfigFreeInputrefList (XConfigInputrefPtr ptr) +{ + XConfigInputrefPtr prev; + + while (ptr) + { + TEST_FREE (ptr->input_name); + xconfigOptionListFree (ptr->options); + prev = ptr; + ptr = ptr->next; + free (prev); + } + +} + +#define CheckScreen(str, ptr)\ +if (str[0] != '\0') \ +{ \ +screen = xconfigFindScreen (str, p->conf_screen_lst); \ +if (!screen) \ +{ \ + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_SCREEN_MSG, \ + str, layout->identifier); \ + return (FALSE); \ +} \ +else \ + ptr = screen; \ +} + +int +xconfigValidateLayout (XConfigPtr p) +{ + XConfigLayoutPtr layout = p->layouts; + XConfigAdjacencyPtr adj; + XConfigInactivePtr iptr; + XConfigInputrefPtr inputRef; + XConfigScreenPtr screen; + XConfigDevicePtr device; + XConfigInputPtr input; + + /* + * if we do not have a layout, just return TRUE; we'll add a + * layout later during the Sanitize step + */ + + if (!layout) return TRUE; + + while (layout) + { + adj = layout->adjacencies; + while (adj) + { + /* the first one can't be "" but all others can */ + screen = xconfigFindScreen (adj->screen_name, p->screens); + if (!screen) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_SCREEN_MSG, + adj->screen_name, layout->identifier); + return (FALSE); + } + else + adj->screen = screen; + +#if 0 + CheckScreen (adj->top_name, adj->top); + CheckScreen (adj->bottom_name, adj->bottom); + CheckScreen (adj->left_name, adj->left); + CheckScreen (adj->right_name, adj->right); +#endif + + adj = adj->next; + } + + /* I not believe the "inactives" list is used for anything */ + + iptr = layout->inactives; + while (iptr) + { + device = xconfigFindDevice (iptr->device_name, + p->devices); + if (!device) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_DEVICE_MSG, + iptr->device_name, layout->identifier); + return (FALSE); + } + else + iptr->device = device; + iptr = iptr->next; + } + + /* + * the layout->inputs list is also updated in + * getCoreInputDevice() when no core input device is found in + * the layout's input list + */ + + inputRef = layout->inputs; + while (inputRef) + { + input = xconfigFindInput (inputRef->input_name, + p->inputs); + if (!input) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_INPUT_MSG, + inputRef->input_name, layout->identifier); + return (FALSE); + } + else { + inputRef->input = input; + } + inputRef = inputRef->next; + } + layout = layout->next; + } + return (TRUE); +} + +int +xconfigSanitizeLayout(XConfigPtr p, + const char *screenName, + GenerateOptions *gop) +{ + XConfigLayoutPtr layout = p->layouts; + + /* add an implicit layout if none exist */ + + if (!p->layouts) { + if (!addImpliedLayout(p, screenName)) { + return FALSE; + } + } + + /* check that input devices are assigned for each layout */ + + for (layout = p->layouts; layout; layout = layout->next) { + if (!xconfigCheckCoreInputDevices(gop, p, layout)) { + return FALSE; + } + } + + return TRUE; +} + +XConfigLayoutPtr +xconfigFindLayout (const char *name, XConfigLayoutPtr list) +{ + while (list) + { + if (xconfigNameCompare (list->identifier, name) == 0) + return (list); + list = list->next; + } + return (NULL); +} + + +static int addImpliedLayout(XConfigPtr config, const char *screenName) +{ + XConfigScreenPtr screen; + XConfigLayoutPtr layout; + XConfigAdjacencyPtr adj; + + if (config->layouts) return TRUE; + + /* + * which screen section is the active one? + * + * If there is a -screen option, use that one, otherwise use the first + * screen in the config's list. + */ + + if (screenName) { + screen = xconfigFindScreen(screenName, config->screens); + if (!screen) { + xconfigErrorMsg(ErrorMsg, "No Screen section called \"%s\"\n", + screenName); + return FALSE; + } + } else { + screen = config->screens; + } + + xconfigErrorMsg(WarnMsg, "No Layout specified, constructing implicit " + "layout section using screen \"%s\".\n", + screen->identifier); + + /* allocate the new layout section */ + + layout = calloc(1, sizeof(XConfigLayoutRec)); + + layout->identifier = xconfigStrdup("Default Layout"); + + adj = calloc(1, sizeof(XConfigAdjacencyRec)); + adj->scrnum = -1; + adj->screen = screen; + adj->screen_name = xconfigStrdup(screen->identifier); + + layout->adjacencies = adj; + + config->layouts = layout; + + /* validate the Layout here to setup all the pointers */ + + if (!xconfigValidateLayout(config)) return FALSE; + + return TRUE; +} diff --git a/src/XF86Config-parser/Makefile b/src/XF86Config-parser/Makefile new file mode 100644 index 0000000..ef973a6 --- /dev/null +++ b/src/XF86Config-parser/Makefile @@ -0,0 +1,62 @@ +SRC = \ + DRI.c \ + Device.c \ + Files.c \ + Flags.c \ + Input.c \ + Keyboard.c \ + Layout.c \ + Module.c \ + Monitor.c \ + Pointer.c \ + Screen.c \ + Vendor.c \ + Video.c \ + Read.c \ + Scan.c \ + Write.c \ + Util.c \ + Extensions.c \ + Generate.c + +OBJS = $(SRC:%.c=%.o) +DEPS = $(SRC:%.c=%.d) + +ifndef CC + CC = gcc +endif + +CFLAGS = -Wall -g + +ifdef NV_CFLAGS + CFLAGS += $(NV_CFLAGS) +endif + +ifndef RANLIB + RANLIB = ranlib +endif + +LIB = libXF86Config-parser.a +LIB_O = $(LIB:%.a=%.o) + +default all: $(LIB) + +.PHONY: clean clobber + +$(LIB): $(OBJS) + $(LD) -r -o $(LIB_O) $(OBJS) + $(AR) ruv $(LIB) $(LIB_O) + $(RANLIB) $(LIB) + +%.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + +%.d: %.c + @set -e; $(CC) -MM $(CPPFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +clean clobber: + rm -rf *.o *~ *.d $(LIB) $(LIB_O) + +-include $(DEPS) diff --git a/src/XF86Config-parser/Makefile.inc b/src/XF86Config-parser/Makefile.inc new file mode 100644 index 0000000..d41889f --- /dev/null +++ b/src/XF86Config-parser/Makefile.inc @@ -0,0 +1,58 @@ +# +# nvidia-settings: A tool for configuring the NVIDIA X driver on Unix +# and Linux systems. +# +# Copyright (C) 2004 NVIDIA Corporation. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of Version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 +# of the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the: +# +# Free Software Foundation, Inc. +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# + +# +# src files and headers +# + +SRC += \ + Device.c \ + DRI.c \ + Extensions.c \ + Files.c \ + Flags.c \ + Generate.c \ + Input.c \ + Keyboard.c \ + Layout.c \ + Module.c \ + Monitor.c \ + Pointer.c \ + Read.c \ + Scan.c \ + Screen.c \ + Util.c \ + Vendor.c \ + Video.c \ + Write.c + +EXTRA_DIST += \ + Makefile.inc \ + Configint.h \ + configProcs.h \ + Makefile \ + xf86Parser.h \ + xf86tokens.h + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/XF86Config-parser/Module.c b/src/XF86Config-parser/Module.c new file mode 100644 index 0000000..0605367 --- /dev/null +++ b/src/XF86Config-parser/Module.c @@ -0,0 +1,282 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec SubModuleTab[] = +{ + {ENDSUBSECTION, "endsubsection"}, + {OPTION, "option"}, + {-1, ""}, +}; + +static XConfigSymTabRec ModuleTab[] = +{ + {ENDSECTION, "endsection"}, + {LOAD, "load"}, + {LOAD_DRIVER, "loaddriver"}, + {SUBSECTION, "subsection"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeModules + +XConfigLoadPtr +xconfigParseModuleSubSection (XConfigLoadPtr head, char *name) +{ + int token; + PARSE_PROLOGUE (XConfigLoadPtr, XConfigLoadRec) + + ptr->name = name; + ptr->type = XCONFIG_LOAD_MODULE; + ptr->opt = NULL; + ptr->next = NULL; + + while ((token = xconfigGetToken (SubModuleTab)) != ENDSUBSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case OPTION: + ptr->opt = xconfigParseOption(ptr->opt); + break; + case EOF_TOKEN: + xconfigErrorMsg(ParseErrorMsg, UNEXPECTED_EOF_MSG); + free(ptr); + return NULL; + default: + xconfigErrorMsg(ParseErrorMsg, INVALID_KEYWORD_MSG, + xconfigTokenString()); + free(ptr); + return NULL; + break; + } + + } + + return ((XConfigLoadPtr) xconfigAddListItem ((GenericListPtr) head, + (GenericListPtr) ptr)); +} + +XConfigModulePtr +xconfigParseModuleSection (void) +{ + int token; + PARSE_PROLOGUE (XConfigModulePtr, XConfigModuleRec) + + while ((token = xconfigGetToken (ModuleTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case LOAD: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Load"); + ptr->loads = + xconfigAddNewLoadDirective (ptr->loads, val.str, + XCONFIG_LOAD_MODULE, NULL, TRUE); + break; + case LOAD_DRIVER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "LoadDriver"); + ptr->loads = + xconfigAddNewLoadDirective (ptr->loads, val.str, + XCONFIG_LOAD_DRIVER, NULL, TRUE); + break; + case SUBSECTION: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "SubSection"); + ptr->loads = + xconfigParseModuleSubSection (ptr->loads, val.str); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintModuleSection (FILE * cf, XConfigModulePtr ptr) +{ + XConfigLoadPtr lptr; + + if (ptr == NULL) + return; + + if (ptr->comment) + fprintf(cf, "%s", ptr->comment); + for (lptr = ptr->loads; lptr; lptr = lptr->next) + { + switch (lptr->type) + { + case XCONFIG_LOAD_MODULE: + if( lptr->opt == NULL ) { + fprintf (cf, " Load \"%s\"", lptr->name); + if (lptr->comment) + fprintf(cf, "%s", lptr->comment); + else + fputc('\n', cf); + } + else + { + fprintf (cf, " SubSection \"%s\"\n", lptr->name); + if (lptr->comment) + fprintf(cf, "%s", lptr->comment); + xconfigPrintOptionList(cf, lptr->opt, 2); + fprintf (cf, " EndSubSection\n"); + } + break; + case XCONFIG_LOAD_DRIVER: + fprintf (cf, " LoadDriver \"%s\"", lptr->name); + if (lptr->comment) + fprintf(cf, "%s", lptr->comment); + else + fputc('\n', cf); + break; +#if 0 + default: + fprintf (cf, "# Unknown type \"%s\"\n", lptr->name); + break; +#endif + } + } +} + +XConfigLoadPtr +xconfigAddNewLoadDirective (XConfigLoadPtr head, char *name, int type, + XConfigOptionPtr opts, int do_token) +{ + XConfigLoadPtr new; + int token; + + new = calloc (1, sizeof (XConfigLoadRec)); + new->name = name; + new->type = type; + new->opt = opts; + new->next = NULL; + + if (do_token) { + if ((token = xconfigGetToken(NULL)) == COMMENT) + new->comment = xconfigAddComment(new->comment, val.str); + else + xconfigUnGetToken(token); + } + + return ((XConfigLoadPtr) xconfigAddListItem ((GenericListPtr) head, + (GenericListPtr) new)); +} + +XConfigLoadPtr +xconfigRemoveLoadDirective(XConfigLoadPtr head, XConfigLoadPtr load) +{ + XConfigLoadPtr prev = NULL; + XConfigLoadPtr l = head; + + while (l) { + if (l == load) { + if (prev) prev->next = load->next; + if (head == load) head = load->next; + TEST_FREE(load->name); + TEST_FREE(load->comment); + xconfigOptionListFree(load->opt); + free(load); + break; + } + + prev = l; + l = l->next; + } + + return head; +} + +void +xconfigFreeModules (XConfigModulePtr ptr) +{ + XConfigLoadPtr lptr; + XConfigLoadPtr prev; + + if (ptr == NULL) + return; + lptr = ptr->loads; + while (lptr) + { + TEST_FREE (lptr->name); + TEST_FREE (lptr->comment); + prev = lptr; + lptr = lptr->next; + free (prev); + } + TEST_FREE (ptr->comment); + free (ptr); +} diff --git a/src/XF86Config-parser/Monitor.c b/src/XF86Config-parser/Monitor.c new file mode 100644 index 0000000..8c273c4 --- /dev/null +++ b/src/XF86Config-parser/Monitor.c @@ -0,0 +1,889 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec MonitorTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {VENDOR, "vendorname"}, + {MODEL, "modelname"}, + {USEMODES, "usemodes"}, + {MODELINE, "modeline"}, + {DISPLAYSIZE, "displaysize"}, + {HORIZSYNC, "horizsync"}, + {VERTREFRESH, "vertrefresh"}, + {MODE, "mode"}, + {GAMMA, "gamma"}, + {OPTION, "option"}, + {-1, ""}, +}; + +static XConfigSymTabRec ModesTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {MODELINE, "modeline"}, + {MODE, "mode"}, + {-1, ""}, +}; + +static XConfigSymTabRec TimingTab[] = +{ + {TT_INTERLACE, "interlace"}, + {TT_PHSYNC, "+hsync"}, + {TT_NHSYNC, "-hsync"}, + {TT_PVSYNC, "+vsync"}, + {TT_NVSYNC, "-vsync"}, + {TT_CSYNC, "composite"}, + {TT_PCSYNC, "+csync"}, + {TT_NCSYNC, "-csync"}, + {TT_DBLSCAN, "doublescan"}, + {TT_HSKEW, "hskew"}, + {TT_BCAST, "bcast"}, + {TT_VSCAN, "vscan"}, + {TT_CUSTOM, "CUSTOM"}, + {-1, ""}, +}; + +static XConfigSymTabRec ModeTab[] = +{ + {DOTCLOCK, "dotclock"}, + {HTIMINGS, "htimings"}, + {VTIMINGS, "vtimings"}, + {FLAGS, "flags"}, + {HSKEW, "hskew"}, + {BCAST, "bcast"}, + {VSCAN, "vscan"}, + {ENDMODE, "endmode"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeModeLineList + +XConfigModeLinePtr +xconfigParseModeLine (void) +{ + int token; + PARSE_PROLOGUE (XConfigModeLinePtr, XConfigModeLineRec) + + /* Identifier */ + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error ("ModeLine identifier expected", NULL); + ptr->identifier = val.str; + + /* DotClock */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine dotclock expected", NULL); + ptr->clock = (int) (val.realnum * 1000.0 + 0.5); + + /* HDisplay */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine Hdisplay expected", NULL); + ptr->hdisplay = val.num; + + /* HSyncStart */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine HSyncStart expected", NULL); + ptr->hsyncstart = val.num; + + /* HSyncEnd */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine HSyncEnd expected", NULL); + ptr->hsyncend = val.num; + + /* HTotal */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine HTotal expected", NULL); + ptr->htotal = val.num; + + /* VDisplay */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine Vdisplay expected", NULL); + ptr->vdisplay = val.num; + + /* VSyncStart */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine VSyncStart expected", NULL); + ptr->vsyncstart = val.num; + + /* VSyncEnd */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine VSyncEnd expected", NULL); + ptr->vsyncend = val.num; + + /* VTotal */ + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("ModeLine VTotal expected", NULL); + ptr->vtotal = val.num; + + token = xconfigGetSubTokenWithTab (&(ptr->comment), TimingTab); + while ((token == TT_INTERLACE) || (token == TT_PHSYNC) || + (token == TT_NHSYNC) || (token == TT_PVSYNC) || + (token == TT_NVSYNC) || (token == TT_CSYNC) || + (token == TT_PCSYNC) || (token == TT_NCSYNC) || + (token == TT_DBLSCAN) || (token == TT_HSKEW) || + (token == TT_VSCAN) || (token == TT_BCAST)) + { + switch (token) + { + + case TT_INTERLACE: + ptr->flags |= XCONFIG_MODE_INTERLACE; + break; + case TT_PHSYNC: + ptr->flags |= XCONFIG_MODE_PHSYNC; + break; + case TT_NHSYNC: + ptr->flags |= XCONFIG_MODE_NHSYNC; + break; + case TT_PVSYNC: + ptr->flags |= XCONFIG_MODE_PVSYNC; + break; + case TT_NVSYNC: + ptr->flags |= XCONFIG_MODE_NVSYNC; + break; + case TT_CSYNC: + ptr->flags |= XCONFIG_MODE_CSYNC; + break; + case TT_PCSYNC: + ptr->flags |= XCONFIG_MODE_PCSYNC; + break; + case TT_NCSYNC: + ptr->flags |= XCONFIG_MODE_NCSYNC; + break; + case TT_DBLSCAN: + ptr->flags |= XCONFIG_MODE_DBLSCAN; + break; + case TT_HSKEW: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Hskew"); + ptr->hskew = val.num; + ptr->flags |= XCONFIG_MODE_HSKEW; + break; + case TT_BCAST: + ptr->flags |= XCONFIG_MODE_BCAST; + break; + case TT_VSCAN: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Vscan"); + ptr->vscan = val.num; + ptr->flags |= XCONFIG_MODE_VSCAN; + break; + case TT_CUSTOM: + ptr->flags |= XCONFIG_MODE_CUSTOM; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + token = xconfigGetSubTokenWithTab (&(ptr->comment), TimingTab); + } + xconfigUnGetToken (token); + + return (ptr); +} + +XConfigModeLinePtr +xconfigParseVerboseMode (void) +{ + int token, token2; + int had_dotclock = 0, had_htimings = 0, had_vtimings = 0; + PARSE_PROLOGUE (XConfigModeLinePtr, XConfigModeLineRec) + + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error ("Mode name expected", NULL); + ptr->identifier = val.str; + while ((token = xconfigGetToken (ModeTab)) != ENDMODE) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case DOTCLOCK: + if ((token = xconfigGetSubToken (&(ptr->comment))) != NUMBER) + Error (NUMBER_MSG, "DotClock"); + ptr->clock = (int) (val.realnum * 1000.0 + 0.5); + had_dotclock = 1; + break; + case HTIMINGS: + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->hdisplay = val.num; + else + Error ("Horizontal display expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->hsyncstart = val.num; + else + Error ("Horizontal sync start expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->hsyncend = val.num; + else + Error ("Horizontal sync end expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->htotal = val.num; + else + Error ("Horizontal total expected", NULL); + had_htimings = 1; + break; + case VTIMINGS: + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->vdisplay = val.num; + else + Error ("Vertical display expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->vsyncstart = val.num; + else + Error ("Vertical sync start expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->vsyncend = val.num; + else + Error ("Vertical sync end expected", NULL); + + if (xconfigGetSubToken (&(ptr->comment)) == NUMBER) + ptr->vtotal = val.num; + else + Error ("Vertical total expected", NULL); + had_vtimings = 1; + break; + case FLAGS: + token = xconfigGetSubToken (&(ptr->comment)); + if (token != STRING) + Error (QUOTE_MSG, "Flags"); + while (token == STRING) + { + token2 = xconfigGetStringToken (TimingTab); + switch (token2) + { + case TT_INTERLACE: + ptr->flags |= XCONFIG_MODE_INTERLACE; + break; + case TT_PHSYNC: + ptr->flags |= XCONFIG_MODE_PHSYNC; + break; + case TT_NHSYNC: + ptr->flags |= XCONFIG_MODE_NHSYNC; + break; + case TT_PVSYNC: + ptr->flags |= XCONFIG_MODE_PVSYNC; + break; + case TT_NVSYNC: + ptr->flags |= XCONFIG_MODE_NVSYNC; + break; + case TT_CSYNC: + ptr->flags |= XCONFIG_MODE_CSYNC; + break; + case TT_PCSYNC: + ptr->flags |= XCONFIG_MODE_PCSYNC; + break; + case TT_NCSYNC: + ptr->flags |= XCONFIG_MODE_NCSYNC; + break; + case TT_DBLSCAN: + ptr->flags |= XCONFIG_MODE_DBLSCAN; + break; + case TT_CUSTOM: + ptr->flags |= XCONFIG_MODE_CUSTOM; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error ("Unknown flag string", NULL); + break; + } + token = xconfigGetSubToken (&(ptr->comment)); + } + xconfigUnGetToken (token); + break; + case HSKEW: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("Horizontal skew expected", NULL); + ptr->flags |= XCONFIG_MODE_HSKEW; + ptr->hskew = val.num; + break; + case VSCAN: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error ("Vertical scan count expected", NULL); + ptr->flags |= XCONFIG_MODE_VSCAN; + ptr->vscan = val.num; + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error ("Unexepcted token in verbose \"Mode\" entry\n", NULL); + } + } + if (!had_dotclock) + Error ("the dotclock is missing", NULL); + if (!had_htimings) + Error ("the horizontal timings are missing", NULL); + if (!had_vtimings) + Error ("the vertical timings are missing", NULL); + + return (ptr); +} + +#undef CLEANUP + +#define CLEANUP xconfigFreeMonitorList + +XConfigMonitorPtr +xconfigParseMonitorSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigMonitorPtr, XConfigMonitorRec) + + while ((token = xconfigGetToken (MonitorTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case VENDOR: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Vendor"); + ptr->vendor = val.str; + break; + case MODEL: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "ModelName"); + ptr->modelname = val.str; + break; + case MODE: + HANDLE_LIST (modelines, xconfigParseVerboseMode, + XConfigModeLinePtr); + break; + case MODELINE: + HANDLE_LIST (modelines, xconfigParseModeLine, + XConfigModeLinePtr); + break; + case DISPLAYSIZE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (DISPLAYSIZE_MSG, NULL); + ptr->width = val.realnum; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (DISPLAYSIZE_MSG, NULL); + ptr->height = val.realnum; + break; + + case HORIZSYNC: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (HORIZSYNC_MSG, NULL); + do { + ptr->hsync[ptr->n_hsync].lo = val.realnum; + switch (token = xconfigGetSubToken (&(ptr->comment))) + { + case COMMA: + ptr->hsync[ptr->n_hsync].hi = + ptr->hsync[ptr->n_hsync].lo; + break; + case DASH: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || + (float)val.realnum < ptr->hsync[ptr->n_hsync].lo) + Error (HORIZSYNC_MSG, NULL); + ptr->hsync[ptr->n_hsync].hi = val.realnum; + if ((token = xconfigGetSubToken (&(ptr->comment))) == COMMA) + break; + ptr->n_hsync++; + goto HorizDone; + default: + /* We cannot currently know if a '\n' was found, + * or this is a real error + */ + ptr->hsync[ptr->n_hsync].hi = + ptr->hsync[ptr->n_hsync].lo; + ptr->n_hsync++; + goto HorizDone; + } + if (ptr->n_hsync >= CONF_MAX_HSYNC) + Error ("Sorry. Too many horizontal sync intervals.", NULL); + ptr->n_hsync++; + } while ((token = xconfigGetSubToken (&(ptr->comment))) == NUMBER); +HorizDone: + xconfigUnGetToken (token); + break; + + case VERTREFRESH: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (VERTREFRESH_MSG, NULL); + do { + ptr->vrefresh[ptr->n_vrefresh].lo = val.realnum; + switch (token = xconfigGetSubToken (&(ptr->comment))) + { + case COMMA: + ptr->vrefresh[ptr->n_vrefresh].hi = + ptr->vrefresh[ptr->n_vrefresh].lo; + break; + case DASH: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || + (float)val.realnum < ptr->vrefresh[ptr->n_vrefresh].lo) + Error (VERTREFRESH_MSG, NULL); + ptr->vrefresh[ptr->n_vrefresh].hi = val.realnum; + if ((token = xconfigGetSubToken (&(ptr->comment))) == COMMA) + break; + ptr->n_vrefresh++; + goto VertDone; + default: + /* We cannot currently know if a '\n' was found, + * or this is a real error + */ + ptr->vrefresh[ptr->n_vrefresh].hi = + ptr->vrefresh[ptr->n_vrefresh].lo; + ptr->n_vrefresh++; + goto VertDone; + } + if (ptr->n_vrefresh >= CONF_MAX_VREFRESH) + Error ("Sorry. Too many vertical refresh intervals.", NULL); + ptr->n_vrefresh++; + } while ((token = xconfigGetSubToken (&(ptr->comment))) == NUMBER); +VertDone: + xconfigUnGetToken (token); + break; + + case GAMMA: + if( xconfigGetSubToken (&(ptr->comment)) != NUMBER ) + { + Error (INVALID_GAMMA_MSG, NULL); + } + else + { + ptr->gamma_red = ptr->gamma_green = + ptr->gamma_blue = val.realnum; + if( xconfigGetSubToken (&(ptr->comment)) == NUMBER ) + { + ptr->gamma_green = val.realnum; + if( xconfigGetSubToken (&(ptr->comment)) == NUMBER ) + { + ptr->gamma_blue = val.realnum; + } + else + { + Error (INVALID_GAMMA_MSG, NULL); + } + } + else + xconfigUnGetToken (token); + } + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case USEMODES: + { + XConfigModesLinkPtr mptr; + + if ((token = xconfigGetSubToken (&(ptr->comment))) != STRING) + Error (QUOTE_MSG, "UseModes"); + + /* add to the end of the list of modes sections + referenced here */ + mptr = calloc (1, sizeof (XConfigModesLinkRec)); + mptr->next = NULL; + mptr->modes_name = val.str; + mptr->modes = NULL; + ptr->modes_sections = (XConfigModesLinkPtr) + xconfigAddListItem((GenericListPtr)ptr->modes_sections, + (GenericListPtr)mptr); + } + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + xconfigErrorMsg(ParseErrorMsg, INVALID_KEYWORD_MSG, + xconfigTokenString()); + CLEANUP (ptr); + return NULL; + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP +#define CLEANUP xconfigFreeModesList + +XConfigModesPtr +xconfigParseModesSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigModesPtr, XConfigModesRec) + + while ((token = xconfigGetToken (ModesTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case MODE: + HANDLE_LIST (modelines, xconfigParseVerboseMode, + XConfigModeLinePtr); + break; + case MODELINE: + HANDLE_LIST (modelines, xconfigParseModeLine, + XConfigModeLinePtr); + break; + default: + xconfigErrorMsg(ParseErrorMsg, INVALID_KEYWORD_MSG, + xconfigTokenString()); + CLEANUP (ptr); + return NULL; + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintMonitorSection (FILE * cf, XConfigMonitorPtr ptr) +{ + int i; + XConfigModeLinePtr mlptr; + XConfigModesLinkPtr mptr; + + while (ptr) + { + mptr = ptr->modes_sections; + fprintf (cf, "Section \"Monitor\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + if (ptr->vendor) + fprintf (cf, " VendorName \"%s\"\n", ptr->vendor); + if (ptr->modelname) + fprintf (cf, " ModelName \"%s\"\n", ptr->modelname); + while (mptr) { + fprintf (cf, " UseModes \"%s\"\n", mptr->modes_name); + mptr = mptr->next; + } + if (ptr->width) + fprintf (cf, " DisplaySize %d %d\n", + ptr->width, + ptr->height); + for (i = 0; i < ptr->n_hsync; i++) + { + fprintf (cf, " HorizSync %2.1f - %2.1f\n", + ptr->hsync[i].lo, + ptr->hsync[i].hi); + } + for (i = 0; i < ptr->n_vrefresh; i++) + { + fprintf (cf, " VertRefresh %2.1f - %2.1f\n", + ptr->vrefresh[i].lo, + ptr->vrefresh[i].hi); + } + if (ptr->gamma_red) { + if (ptr->gamma_red == ptr->gamma_green + && ptr->gamma_red == ptr->gamma_blue) + { + fprintf (cf, " Gamma %.4g\n", + ptr->gamma_red); + } else { + fprintf (cf, " Gamma %.4g %.4g %.4g\n", + ptr->gamma_red, + ptr->gamma_green, + ptr->gamma_blue); + } + } + for (mlptr = ptr->modelines; mlptr; mlptr = mlptr->next) + { + fprintf (cf, " ModeLine \"%s\" %2.1f ", + mlptr->identifier, mlptr->clock / 1000.0); + fprintf (cf, "%d %d %d %d %d %d %d %d", + mlptr->hdisplay, mlptr->hsyncstart, + mlptr->hsyncend, mlptr->htotal, + mlptr->vdisplay, mlptr->vsyncstart, + mlptr->vsyncend, mlptr->vtotal); + if (mlptr->flags & XCONFIG_MODE_PHSYNC) + fprintf (cf, " +hsync"); + if (mlptr->flags & XCONFIG_MODE_NHSYNC) + fprintf (cf, " -hsync"); + if (mlptr->flags & XCONFIG_MODE_PVSYNC) + fprintf (cf, " +vsync"); + if (mlptr->flags & XCONFIG_MODE_NVSYNC) + fprintf (cf, " -vsync"); + if (mlptr->flags & XCONFIG_MODE_INTERLACE) + fprintf (cf, " interlace"); + if (mlptr->flags & XCONFIG_MODE_CSYNC) + fprintf (cf, " composite"); + if (mlptr->flags & XCONFIG_MODE_PCSYNC) + fprintf (cf, " +csync"); + if (mlptr->flags & XCONFIG_MODE_NCSYNC) + fprintf (cf, " -csync"); + if (mlptr->flags & XCONFIG_MODE_DBLSCAN) + fprintf (cf, " doublescan"); + if (mlptr->flags & XCONFIG_MODE_HSKEW) + fprintf (cf, " hskew %d", mlptr->hskew); + if (mlptr->flags & XCONFIG_MODE_BCAST) + fprintf (cf, " bcast"); + fprintf (cf, "\n"); + } + xconfigPrintOptionList(cf, ptr->options, 1); + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigPrintModesSection (FILE * cf, XConfigModesPtr ptr) +{ + XConfigModeLinePtr mlptr; + + while (ptr) + { + fprintf (cf, "Section \"Modes\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + for (mlptr = ptr->modelines; mlptr; mlptr = mlptr->next) + { + fprintf (cf, " ModeLine \"%s\" %2.1f ", + mlptr->identifier, mlptr->clock / 1000.0); + fprintf (cf, "%d %d %d %d %d %d %d %d", + mlptr->hdisplay, mlptr->hsyncstart, + mlptr->hsyncend, mlptr->htotal, + mlptr->vdisplay, mlptr->vsyncstart, + mlptr->vsyncend, mlptr->vtotal); + if (mlptr->flags & XCONFIG_MODE_PHSYNC) + fprintf (cf, " +hsync"); + if (mlptr->flags & XCONFIG_MODE_NHSYNC) + fprintf (cf, " -hsync"); + if (mlptr->flags & XCONFIG_MODE_PVSYNC) + fprintf (cf, " +vsync"); + if (mlptr->flags & XCONFIG_MODE_NVSYNC) + fprintf (cf, " -vsync"); + if (mlptr->flags & XCONFIG_MODE_INTERLACE) + fprintf (cf, " interlace"); + if (mlptr->flags & XCONFIG_MODE_CSYNC) + fprintf (cf, " composite"); + if (mlptr->flags & XCONFIG_MODE_PCSYNC) + fprintf (cf, " +csync"); + if (mlptr->flags & XCONFIG_MODE_NCSYNC) + fprintf (cf, " -csync"); + if (mlptr->flags & XCONFIG_MODE_DBLSCAN) + fprintf (cf, " doublescan"); + if (mlptr->flags & XCONFIG_MODE_HSKEW) + fprintf (cf, " hskew %d", mlptr->hskew); + if (mlptr->flags & XCONFIG_MODE_VSCAN) + fprintf (cf, " vscan %d", mlptr->vscan); + if (mlptr->flags & XCONFIG_MODE_BCAST) + fprintf (cf, " bcast"); + if (mlptr->comment) + fprintf (cf, "%s", mlptr->comment); + else + fprintf (cf, "\n"); + } + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigFreeMonitorList (XConfigMonitorPtr ptr) +{ + XConfigMonitorPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->vendor); + TEST_FREE (ptr->modelname); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + xconfigFreeModeLineList (ptr->modelines); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeModesList (XConfigModesPtr ptr) +{ + XConfigModesPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->comment); + xconfigFreeModeLineList (ptr->modelines); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeModeLineList (XConfigModeLinePtr ptr) +{ + XConfigModeLinePtr prev; + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->comment); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +XConfigMonitorPtr +xconfigFindMonitor (const char *ident, XConfigMonitorPtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +XConfigModesPtr +xconfigFindModes (const char *ident, XConfigModesPtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +XConfigModeLinePtr +xconfigFindModeLine (const char *ident, XConfigModeLinePtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +int +xconfigValidateMonitor (XConfigPtr p, XConfigScreenPtr screen) +{ + XConfigMonitorPtr monitor = screen->monitor; + XConfigModesLinkPtr modeslnk = monitor->modes_sections; + XConfigModesPtr modes; + while(modeslnk) + { + modes = xconfigFindModes (modeslnk->modes_name, p->modes); + if (!modes) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_MODES_MSG, + modeslnk->modes_name, screen->identifier); + return (FALSE); + } + modeslnk->modes = modes; + modeslnk = modeslnk->next; + } + return (TRUE); +} diff --git a/src/XF86Config-parser/Pointer.c b/src/XF86Config-parser/Pointer.c new file mode 100644 index 0000000..d1e282a --- /dev/null +++ b/src/XF86Config-parser/Pointer.c @@ -0,0 +1,236 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec PointerTab[] = +{ + {PROTOCOL, "protocol"}, + {EMULATE3, "emulate3buttons"}, + {EM3TIMEOUT, "emulate3timeout"}, + {ENDSUBSECTION, "endsubsection"}, + {ENDSECTION, "endsection"}, + {PDEVICE, "device"}, + {PDEVICE, "port"}, + {BAUDRATE, "baudrate"}, + {SAMPLERATE, "samplerate"}, + {CLEARDTR, "cleardtr"}, + {CLEARRTS, "clearrts"}, + {CHORDMIDDLE, "chordmiddle"}, + {PRESOLUTION, "resolution"}, + {DEVICE_NAME, "devicename"}, + {ALWAYSCORE, "alwayscore"}, + {PBUTTONS, "buttons"}, + {ZAXISMAPPING, "zaxismapping"}, + {-1, ""}, +}; + +static XConfigSymTabRec ZMapTab[] = +{ + {XAXIS, "x"}, + {YAXIS, "y"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeInputList + +XConfigInputPtr +xconfigParsePointerSection (void) +{ + char *s, *s1, *s2; + int l; + int token; + PARSE_PROLOGUE (XConfigInputPtr, XConfigInputRec) + + while ((token = xconfigGetToken (PointerTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case PROTOCOL: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Protocol"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("Protocol"), + val.str); + break; + case PDEVICE: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Device"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("Device"), + val.str); + break; + case EMULATE3: + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("Emulate3Buttons"), + NULL); + break; + case EM3TIMEOUT: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || val.num < 0) + Error (POSITIVE_INT_MSG, "Emulate3Timeout"); + s = xconfigULongToString(val.num); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("Emulate3Timeout"), + s); + break; + case CHORDMIDDLE: + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("ChordMiddle"), + NULL); + break; + case PBUTTONS: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || val.num < 0) + Error (POSITIVE_INT_MSG, "Buttons"); + s = xconfigULongToString(val.num); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("Buttons"), s); + break; + case BAUDRATE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || val.num < 0) + Error (POSITIVE_INT_MSG, "BaudRate"); + s = xconfigULongToString(val.num); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("BaudRate"), s); + break; + case SAMPLERATE: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || val.num < 0) + Error (POSITIVE_INT_MSG, "SampleRate"); + s = xconfigULongToString(val.num); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("SampleRate"), s); + break; + case PRESOLUTION: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || val.num < 0) + Error (POSITIVE_INT_MSG, "Resolution"); + s = xconfigULongToString(val.num); + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("Resolution"), s); + break; + case CLEARDTR: + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("ClearDTR"), NULL); + break; + case CLEARRTS: + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("ClearRTS"), NULL); + break; + case ZAXISMAPPING: + switch (xconfigGetToken(ZMapTab)) { + case NUMBER: + if (val.num < 0) + Error (ZAXISMAPPING_MSG, NULL); + s1 = xconfigULongToString(val.num); + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER || + val.num < 0) + Error (ZAXISMAPPING_MSG, NULL); + s2 = xconfigULongToString(val.num); + l = strlen(s1) + 1 + strlen(s2) + 1; + s = malloc(l); + sprintf(s, "%s %s", s1, s2); + free(s1); + free(s2); + break; + case XAXIS: + s = xconfigStrdup("x"); + break; + case YAXIS: + s = xconfigStrdup("y"); + break; + default: + Error (ZAXISMAPPING_MSG, NULL); + break; + } + ptr->options = + xconfigAddNewOption(ptr->options, + xconfigStrdup("ZAxisMapping"), + s); + break; + case ALWAYSCORE: + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + ptr->identifier = xconfigStrdup(CONF_IMPLICIT_POINTER); + ptr->driver = xconfigStrdup("mouse"); + ptr->options = xconfigAddNewOption(ptr->options, + xconfigStrdup("CorePointer"), NULL); + + return ptr; +} + +#undef CLEANUP + diff --git a/src/XF86Config-parser/Read.c b/src/XF86Config-parser/Read.c new file mode 100644 index 0000000..7d21e44 --- /dev/null +++ b/src/XF86Config-parser/Read.c @@ -0,0 +1,401 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec TopLevelTab[] = +{ + {SECTION, "section"}, + {-1, ""}, +}; + + +#define CLEANUP xconfigFreeConfig + +#define READ_HANDLE_RETURN(f,func) \ + if ((ptr->f=func) == NULL) { \ + xconfigFreeConfig(ptr); \ + return XCONFIG_RETURN_PARSE_ERROR; \ + } + +#define READ_HANDLE_LIST(field,func,type) \ +{ \ + type p = func(); \ + if (p == NULL) { \ + xconfigFreeConfig(ptr); \ + return XCONFIG_RETURN_PARSE_ERROR; \ + } else { \ + ptr->field = (type) \ + xconfigAddListItem((GenericListPtr) ptr->field, \ + (GenericListPtr) p); \ + } \ +} + +#define READ_ERROR(a,b) \ + do { \ + xconfigErrorMsg(ParseErrorMsg, a, b); \ + xconfigFreeConfig(ptr); \ + return XCONFIG_RETURN_PARSE_ERROR; \ + } while (0) \ + + + +/* + * xconfigReadConfigFile() - read the open XConfig file, returning the + * parsed data as XConfigPtr. + */ + +XConfigError xconfigReadConfigFile(XConfigPtr *configPtr) +{ + int token; + XConfigPtr ptr = NULL; + + *configPtr = NULL; + + ptr = xconfigAlloc(sizeof(XConfigRec)); + + while ((token = xconfigGetToken(TopLevelTab)) != EOF_TOKEN) { + + switch (token) { + + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + + case SECTION: + if (xconfigGetSubToken(&(ptr->comment)) != STRING) { + xconfigErrorMsg(ParseErrorMsg, QUOTE_MSG, "Section"); + xconfigFreeConfig(ptr); + return XCONFIG_RETURN_PARSE_ERROR; + } + + xconfigSetSection(val.str); + + if (xconfigNameCompare(val.str, "files") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_RETURN(files, xconfigParseFilesSection()); + } + else if (xconfigNameCompare(val.str, "serverflags") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_RETURN(flags, xconfigParseFlagsSection()); + } + else if (xconfigNameCompare(val.str, "keyboard") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(inputs, xconfigParseKeyboardSection, + XConfigInputPtr); + } + else if (xconfigNameCompare(val.str, "pointer") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(inputs, xconfigParsePointerSection, + XConfigInputPtr); + } + else if (xconfigNameCompare(val.str, "videoadaptor") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(videoadaptors, + xconfigParseVideoAdaptorSection, + XConfigVideoAdaptorPtr); + } + else if (xconfigNameCompare(val.str, "device") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(devices, xconfigParseDeviceSection, + XConfigDevicePtr); + } + else if (xconfigNameCompare(val.str, "monitor") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(monitors, xconfigParseMonitorSection, + XConfigMonitorPtr); + } + else if (xconfigNameCompare(val.str, "modes") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(modes, xconfigParseModesSection, + XConfigModesPtr); + } + else if (xconfigNameCompare(val.str, "screen") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(screens, xconfigParseScreenSection, + XConfigScreenPtr); + } + else if (xconfigNameCompare(val.str, "inputdevice") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(inputs, xconfigParseInputSection, + XConfigInputPtr); + } + else if (xconfigNameCompare(val.str, "module") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_RETURN(modules, xconfigParseModuleSection()); + } + else if (xconfigNameCompare(val.str, "serverlayout") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(layouts, xconfigParseLayoutSection, + XConfigLayoutPtr); + } + else if (xconfigNameCompare(val.str, "vendor") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_LIST(vendors, xconfigParseVendorSection, + XConfigVendorPtr); + } + else if (xconfigNameCompare(val.str, "dri") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_RETURN(dri, xconfigParseDRISection()); + } + else if (xconfigNameCompare (val.str, "extensions") == 0) + { + free(val.str); + val.str = NULL; + READ_HANDLE_RETURN(extensions, xconfigParseExtensionsSection()); + } + else + { + READ_ERROR(INVALID_SECTION_MSG, xconfigTokenString()); + free(val.str); + val.str = NULL; + } + break; + + default: + READ_ERROR(INVALID_KEYWORD_MSG, xconfigTokenString()); + free(val.str); + val.str = NULL; + } + } + + if (xconfigValidateConfig(ptr)) { + ptr->filename = strdup(xconfigGetConfigFileName()); + *configPtr = ptr; + return XCONFIG_RETURN_SUCCESS; + } else { + xconfigFreeConfig(ptr); + return XCONFIG_RETURN_VALIDATION_ERROR; + } +} + +#undef CLEANUP + + +/* + * This function resolves name references and reports errors if the named + * objects cannot be found. + */ + +int xconfigValidateConfig(XConfigPtr p) +{ + if (!xconfigValidateDevice(p)) + return FALSE; + if (!xconfigValidateScreen(p)) + return FALSE; + if (!xconfigValidateInput(p)) + return FALSE; + if (!xconfigValidateLayout(p)) + return FALSE; + + return(TRUE); +} + + + +/* + * This function fixes up any problems that it finds in the config, + * when possible. + */ + +int xconfigSanitizeConfig(XConfigPtr p, + const char *screenName, + GenerateOptions *gop) +{ + if (!xconfigSanitizeScreen(p)) + return FALSE; + + if (!xconfigSanitizeLayout(p, screenName, gop)) + return FALSE; + + return TRUE; +} + + + +/* + * adds an item to the end of the linked list. Any record whose first field + * is a GenericListRec can be cast to this type and used with this function. + * A pointer to the head of the list is returned to handle the addition of + * the first item. + */ +GenericListPtr +xconfigAddListItem (GenericListPtr head, GenericListPtr new) +{ + GenericListPtr p = head; + GenericListPtr last = NULL; + + while (p) + { + last = p; + p = p->next; + } + + if (last) + { + last->next = new; + return (head); + } + else + return (new); +} + + +/* + * removes an item from the linked list. Any record whose first field + * is a GenericListRec can be cast to this type and used with this function. + * A pointer to the head of the list is returned to handle the removal of + * the first item. + */ +GenericListPtr +xconfigRemoveListItem (GenericListPtr head, GenericListPtr item) +{ + GenericListPtr cur = head; + GenericListPtr prev = NULL; + + while (cur) + { + if (cur == item) + { + if (prev) prev->next = item->next; + if (head == item) head = item->next; + break; + } + prev = cur; + cur = cur->next; + } + + return head; +} + + +/* + * Test if one chained list contains the other. + * In this case both list have the same endpoint (provided they don't loop) + */ +int +xconfigItemNotSublist(GenericListPtr list_1, GenericListPtr list_2) +{ + GenericListPtr p = list_1; + GenericListPtr last_1 = NULL, last_2 = NULL; + + while (p) { + last_1 = p; + p = p->next; + } + + p = list_2; + while (p) { + last_2 = p; + p = p->next; + } + + return (!(last_1 == last_2)); +} + +void +xconfigFreeConfig (XConfigPtr p) +{ + if (p == NULL) + return; + + xconfigFreeFiles (p->files); + xconfigFreeModules (p->modules); + xconfigFreeFlags (p->flags); + xconfigFreeMonitorList (p->monitors); + xconfigFreeModesList (p->modes); + xconfigFreeVideoAdaptorList (p->videoadaptors); + xconfigFreeDeviceList (p->devices); + xconfigFreeScreenList (p->screens); + xconfigFreeLayoutList (p->layouts); + xconfigFreeInputList (p->inputs); + xconfigFreeVendorList (p->vendors); + xconfigFreeDRI (p->dri); + TEST_FREE(p->comment); + + free (p); +} diff --git a/src/XF86Config-parser/Scan.c b/src/XF86Config-parser/Scan.c new file mode 100644 index 0000000..4e694ba --- /dev/null +++ b/src/XF86Config-parser/Scan.c @@ -0,0 +1,975 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> + +#if !defined(X_NOT_POSIX) +#if defined(_POSIX_SOURCE) +#include <limits.h> +#else +#define _POSIX_SOURCE +#include <limits.h> +#undef _POSIX_SOURCE +#endif /* _POSIX_SOURCE */ +#endif /* !X_NOT_POSIX */ +#if !defined(PATH_MAX) +#if defined(MAXPATHLEN) +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif /* MAXPATHLEN */ +#endif /* !PATH_MAX */ + +#if !defined(MAXHOSTNAMELEN) +#define MAXHOSTNAMELEN 32 +#endif /* !MAXHOSTNAMELEN */ + +#include "Configint.h" +#include "xf86tokens.h" + +#define CONFIG_BUF_LEN 1024 + +static int StringToToken (char *, XConfigSymTabRec *); + +static FILE *configFile = NULL; +static const char **builtinConfig = NULL; +static int builtinIndex = 0; +static int configPos = 0; /* current readers position */ +static char *configBuf, *configRBuf; /* buffer for lines */ +static int pushToken = LOCK_TOKEN; +static int eol_seen = 0; /* private state to handle comments */ +LexRec val; + +int configLineNo = 0; /* linenumber */ +char *configSection = NULL; /* name of current section being parsed */ +char *configPath; /* path to config file */ + + + + +static int xconfigIsAlpha(char c) +{ + return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))); +} + +static int xconfigIsDigit(char c) +{ + return ((c >= '0') && (c <= '9')); +} + +static int xconfigIsUpper(char c) +{ + return ((c >= 'A') && (c <= 'Z')); +} + +static char xconfigToLower(char c) +{ + if ((c >= 'A') && (c <= 'Z')) { + return c + ('a' - 'A'); + } else { + return c; + } +} + + +/* + * xconfigStrToUL -- + * + * A portable, but restricted, version of strtoul(). It only understands + * hex, octal, and decimal. But it's good enough for our needs. + */ + +static unsigned int xconfigStrToUL (char *str) +{ + int base = 10; + char *p = str; + unsigned int tot = 0; + + if (*p == '0') + { + p++; + if ((*p == 'x') || (*p == 'X')) + { + p++; + base = 16; + } + else + base = 8; + } + while (*p) + { + if ((*p >= '0') && (*p <= ((base == 8) ? '7' : '9'))) + { + tot = tot * base + (*p - '0'); + } + else if ((base == 16) && (*p >= 'a') && (*p <= 'f')) + { + tot = tot * base + 10 + (*p - 'a'); + } + else if ((base == 16) && (*p >= 'A') && (*p <= 'F')) + { + tot = tot * base + 10 + (*p - 'A'); + } + else + { + return (tot); + } + p++; + } + return (tot); +} + + + +/* + * xconfigGetToken -- + * Read next Token form the config file. Handle the global variable + * pushToken. + */ + +int xconfigGetToken (XConfigSymTabRec * tab) +{ + int c, i; + + /* + * First check whether pushToken has a different value than LOCK_TOKEN. + * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the + * oth * case the next token must be read from the input. + */ + if (pushToken == EOF_TOKEN) + return (EOF_TOKEN); + else if (pushToken == LOCK_TOKEN) + { + /* + * eol_seen is only set for the first token after a newline. + */ + eol_seen = 0; + + c = configBuf[configPos]; + + /* + * Get start of next Token. EOF is handled, + * whitespaces are skipped. + */ + +again: + if (!c) + { + char *ret; + if (configFile) + ret = fgets (configBuf, CONFIG_BUF_LEN - 1, configFile); + else { + if (builtinConfig[builtinIndex] == NULL) + ret = NULL; + else { + ret = strncpy(configBuf, builtinConfig[builtinIndex], + CONFIG_BUF_LEN); + builtinIndex++; + } + } + if (ret == NULL) + { + return (pushToken = EOF_TOKEN); + } + configLineNo++; + configPos = 0; + eol_seen = 1; + } + + i = 0; + for (;;) { + c = configBuf[configPos++]; + configRBuf[i++] = c; + switch (c) { + case ' ': + case '\t': + case '\r': + continue; + case '\n': + i = 0; + continue; + } + break; + } + if (c == '\0') + goto again; + + if (c == '#') + { + do + { + configRBuf[i++] = (c = configBuf[configPos++]); + } + while ((c != '\n') && (c != '\r') && (c != '\0')); + configRBuf[i] = '\0'; + /* XXX no private copy. + * Use xconfigAddComment when setting a comment. + */ + val.str = configRBuf; + return (COMMENT); + } + + /* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */ + else if ((c == ',') && !xconfigIsAlpha(configBuf[configPos])) + { + return COMMA; + } + else if ((c == '-') && !xconfigIsAlpha(configBuf[configPos])) + { + return DASH; + } + + /* + * Numbers are returned immediately ... + */ + if (xconfigIsDigit(c)) + { + int base; + + if (c == '0') + if ((configBuf[configPos] == 'x') || + (configBuf[configPos] == 'X')) + base = 16; + else + base = 8; + else + base = 10; + + configRBuf[0] = c; + i = 1; + while (xconfigIsDigit(c = configBuf[configPos++]) || + (c == '.') || (c == 'x') || (c == 'X') || + ((base == 16) && (((c >= 'a') && (c <= 'f')) || + ((c >= 'A') && (c <= 'F'))))) + configRBuf[i++] = c; + configPos--; /* GJA -- one too far */ + configRBuf[i] = '\0'; + val.num = xconfigStrToUL (configRBuf); + val.realnum = atof (configRBuf); + return (NUMBER); + } + + /* + * All Strings START with a \" ... + */ + else if (c == '\"') + { + i = -1; + do + { + configRBuf[++i] = (c = configBuf[configPos++]); + } + while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0')); + configRBuf[i] = '\0'; + val.str = malloc (strlen (configRBuf) + 1); + strcpy (val.str, configRBuf); /* private copy ! */ + return (STRING); + } + + /* + * ... and now we MUST have a valid token. The search is + * handled later along with the pushed tokens. + */ + else + { + configRBuf[0] = c; + i = 0; + do + { + configRBuf[++i] = (c = configBuf[configPos++]);; + } + while ((c != ' ') && + (c != '\t') && + (c != '\n') && + (c != '\r') && + (c != '\0') && + (c != '#')); + + --configPos; + configRBuf[i] = '\0'; + i = 0; + } + + } + else + { + + /* + * Here we deal with pushed tokens. Reinitialize pushToken again. If + * the pushed token was NUMBER || STRING return them again ... + */ + int temp = pushToken; + pushToken = LOCK_TOKEN; + + if (temp == COMMA || temp == DASH) + return (temp); + if (temp == NUMBER || temp == STRING) + return (temp); + } + + /* + * Joop, at last we have to lookup the token ... + */ + if (tab) + { + i = 0; + while (tab[i].token != -1) + if (xconfigNameCompare (configRBuf, tab[i].name) == 0) + return (tab[i].token); + else + i++; + } + + return (ERROR_TOKEN); /* Error catcher */ +} + +int xconfigGetSubToken (char **comment) +{ + int token; + + for (;;) { + token = xconfigGetToken(NULL); + if (token == COMMENT) { + if (comment) + *comment = xconfigAddComment(*comment, val.str); + } + else + return (token); + } + /*NOTREACHED*/ +} + +int xconfigGetSubTokenWithTab (char **comment, XConfigSymTabRec *tab) +{ + int token; + + for (;;) { + token = xconfigGetToken(tab); + if (token == COMMENT) { + if (comment) + *comment = xconfigAddComment(*comment, val.str); + } + else + return (token); + } + /*NOTREACHED*/ +} + +void xconfigUnGetToken (int token) +{ + pushToken = token; +} + +char *xconfigTokenString (void) +{ + return configRBuf; +} + +static int pathIsAbsolute(const char *path) +{ + if (path && path[0] == '/') + return 1; + return 0; +} + +/* A path is "safe" if it is relative and if it contains no ".." elements. */ +static int pathIsSafe(const char *path) +{ + if (pathIsAbsolute(path)) + return 0; + + /* Compare with ".." */ + if (!strcmp(path, "..")) + return 0; + + /* Look for leading "../" */ + if (!strncmp(path, "../", 3)) + return 0; + + /* Look for trailing "/.." */ + if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/..")) + return 0; + + /* Look for "/../" */ + if (strstr(path, "/../")) + return 0; + + return 1; +} + +/* + * This function substitutes the following escape sequences: + * + * %A cmdline argument as an absolute path (must be absolute to match) + * %R cmdline argument as a relative path + * %S cmdline argument as a "safe" path (relative, and no ".." elements) + * %X default config file name ("XF86Config") + * %H hostname + * %E config file environment ($XF86CONFIG) as an absolute path + * %F config file environment ($XF86CONFIG) as a relative path + * %G config file environment ($XF86CONFIG) as a safe path + * %D $HOME + * %P projroot + * %M major version number + * %% % + * %& UNIXOS2 only: prepend X11ROOT env var + */ + +#ifndef XCONFIGFILE +#define XCONFIGFILE "xorg.conf" +#endif +#ifndef PROJECTROOT +#define PROJECTROOT "/usr/X11R6" +#endif +#ifndef XCONFENV +#define XCONFENV "XF86CONFIG" +#endif +#define XFREE86CFGFILE "XF86Config" +#ifndef X_VERSION_MAJOR +#ifdef XVERSION +#if XVERSION > 40000000 +#define X_VERSION_MAJOR (XVERSION / 10000000) +#else +#define X_VERSION_MAJOR (XVERSION / 1000) +#endif +#else +#define X_VERSION_MAJOR 4 +#endif +#endif + +#define BAIL_OUT do { \ + free(result); \ + return NULL; \ + } while (0) + +#define CHECK_LENGTH do { \ + if (l > PATH_MAX) { \ + BAIL_OUT; \ + } \ + } while (0) + +#define APPEND_STR(s) do { \ + if (strlen(s) + l > PATH_MAX) { \ + BAIL_OUT; \ + } else { \ + strcpy(result + l, s); \ + l += strlen(s); \ + } \ + } while (0) + +static char *DoSubstitution(const char *template, + const char *cmdline, + const char *projroot, + int *cmdlineUsed, int *envUsed, char *XConfigFile) +{ + char *result; + int i, l; + static const char *env = NULL, *home = NULL; + static char *hostname = NULL; + static char majorvers[3] = ""; + + if (!template) + return NULL; + + if (cmdlineUsed) + *cmdlineUsed = 0; + if (envUsed) + *envUsed = 0; + + result = malloc(PATH_MAX + 1); + l = 0; + for (i = 0; template[i]; i++) { + if (template[i] != '%') { + result[l++] = template[i]; + CHECK_LENGTH; + } else { + switch (template[++i]) { + case 'A': + if (cmdline && pathIsAbsolute(cmdline)) { + APPEND_STR(cmdline); + if (cmdlineUsed) + *cmdlineUsed = 1; + } else + BAIL_OUT; + break; + case 'R': + if (cmdline && !pathIsAbsolute(cmdline)) { + APPEND_STR(cmdline); + if (cmdlineUsed) + *cmdlineUsed = 1; + } else + BAIL_OUT; + break; + case 'S': + if (cmdline && pathIsSafe(cmdline)) { + APPEND_STR(cmdline); + if (cmdlineUsed) + *cmdlineUsed = 1; + } else + BAIL_OUT; + break; + case 'X': + APPEND_STR(XConfigFile); + break; + case 'H': + if (!hostname) { + if ((hostname = malloc(MAXHOSTNAMELEN + 1))) { + if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { + hostname[MAXHOSTNAMELEN] = '\0'; + } else { + free(hostname); + hostname = NULL; + } + } + } + if (hostname) + APPEND_STR(hostname); + break; + case 'E': + if (!env) + env = getenv(XCONFENV); + if (env && pathIsAbsolute(env)) { + APPEND_STR(env); + if (envUsed) + *envUsed = 1; + } else + BAIL_OUT; + break; + case 'F': + if (!env) + env = getenv(XCONFENV); + if (env && !pathIsAbsolute(env)) { + APPEND_STR(env); + if (envUsed) + *envUsed = 1; + } else + BAIL_OUT; + break; + case 'G': + if (!env) + env = getenv(XCONFENV); + if (env && pathIsSafe(env)) { + APPEND_STR(env); + if (envUsed) + *envUsed = 1; + } else + BAIL_OUT; + break; + case 'D': + if (!home) + home = getenv("HOME"); + if (home && pathIsAbsolute(home)) + APPEND_STR(home); + else + BAIL_OUT; + break; + case 'P': + if (projroot && pathIsAbsolute(projroot)) + APPEND_STR(projroot); + else + BAIL_OUT; + break; + case 'M': + if (!majorvers[0]) { + sprintf(majorvers, "%d", X_VERSION_MAJOR); + } + APPEND_STR(majorvers); + break; + case '%': + result[l++] = '%'; + CHECK_LENGTH; + break; + default: + xconfigErrorMsg(InternalErrorMsg, + "invalid escape %%%c found in path template\n", + template[i]); + BAIL_OUT; + break; + } + } + } + return result; +} + +/* + * xconfigOpenConfigFile -- + * + * This function takes a config file search path (optional), a + * command-line specified file name (optional) and the ProjectRoot + * path (optional) and locates and opens a config file based on that + * information. If a command-line file name is specified, then this + * function fails if none of the located files. + * + * The return value is a pointer to the actual name of the file that + * was opened. When no file is found, the return value is NULL. + * + * The escape sequences allowed in the search path are defined above. + * + */ + + +/* + * __root_configpath[] - this is the XconfigConfig search path used by + * XFree86 when the server runs as root. + */ + +static const char __root_configpath[] = +"%A," /* <cmdline> */ +"%R," /* <cmdline> (as relative path) */ +"/etc/X11/%R," /* /etc/X11/<cmdline> */ +"%P/etc/X11/%R," /* /usr/X11R6/etc/X11/<cmdline> */ +"%E," /* $XF86CONFIG */ +"%F," /* $XF86CONFIG (as relative path) */ +"/etc/X11/%F," /* /etc/X11/$XF86CONFIG */ +"%P/etc/X11/%F," /* /usr/X11R6/etc/X11/$XF86CONFIG */ +"%D/%X," /* $HOME/XF86Config */ +"/etc/X11/%X-%M," /* /etc/X11/XF86Config-4 */ +"/etc/X11/%X," /* /etc/X11/XF86Config */ +"/etc/%X," /* /etc/XF86Config */ +"%P/etc/X11/%X.%H," /* /usr/X11R6/etc/X11/XF86Config.<hostname> */ +"%P/etc/X11/%X-%M," /* /usr/X11R6/etc/X11/XF86Config-4 */ +"%P/etc/X11/%X," /* /usr/X11R6/etc/X11/XF86Config */ +"%P/lib/X11/%X.%H," /* /usr/X11R6/lib/X11/XF86Config.<hostname> */ +"%P/lib/X11/%X-%M," /* /usr/X11R6/lib/X11/XF86Config-4 */ +"%P/lib/X11/%X"; /* /usr/X11R6/lib/X11/XF86Config */ + + + +/* + * __user_configpath[] - this is the XF86Config search path used by + * XFree86 when the server runs as a normal user + */ + +static const char __user_configpath[] = +"%A," /* <cmdline> XXX */ +"%R," /* <cmdline> (as relative path) XXX */ +"/etc/X11/%S," /* /etc/X11/<cmdline> */ +"%P/etc/X11/%S," /* /usr/X11R6/etc/X11/<cmdline> */ +"/etc/X11/%G," /* /etc/X11/$XF86CONFIG */ +"%P/etc/X11/%G," /* /usr/X11R6/etc/X11/$XF86CONFIG */ +"/etc/X11/%X-%M," /* /etc/X11/XF86Config-4 */ +"/etc/X11/%X," /* /etc/X11/XF86Config */ +"/etc/%X," /* /etc/XF86Config */ +"%P/etc/X11/%X.%H," /* /usr/X11R6/etc/X11/XF86Config.<hostname> */ +"%P/etc/X11/%X-%M," /* /usr/X11R6/etc/X11/XF86Config-4 */ +"%P/etc/X11/%X," /* /usr/X11R6/etc/X11/XF86Config */ +"%P/lib/X11/%X.%H," /* /usr/X11R6/lib/X11/XF86Config.<hostname> */ +"%P/lib/X11/%X-%M," /* /usr/X11R6/lib/X11/XF86Config-4 */ +"%P/lib/X11/%X"; /* /usr/X11R6/lib/X11/XF86Config */ + + + +const char *xconfigOpenConfigFile(const char *cmdline, const char *projroot) +{ + const char *searchpath; + char *pathcopy; + const char *template; + int cmdlineUsed = 0; + + configFile = NULL; + configPos = 0; /* current readers position */ + configLineNo = 0; /* linenumber */ + pushToken = LOCK_TOKEN; + + /* + * select the search path: XFree86 uses a slightly different path + * depending on whether the user is root + */ + + if (getuid() == 0) { + searchpath = __root_configpath; + } else { + searchpath = __user_configpath; + } + + if (!projroot) projroot = PROJECTROOT; + + pathcopy = strdup(searchpath); + + template = strtok(pathcopy, ","); + + /* First, search for a config file. */ + while (template && !configFile) { + if ((configPath = DoSubstitution(template, cmdline, projroot, + &cmdlineUsed, NULL, XCONFIGFILE))) { + if ((configFile = fopen(configPath, "r")) != 0) { + if (cmdline && !cmdlineUsed) { + fclose(configFile); + configFile = NULL; + } + } + } + if (configPath && !configFile) { + free(configPath); + configPath = NULL; + } + template = strtok(NULL, ","); + } + + /* Then search for fallback */ + if (!configFile) { + strcpy(pathcopy, searchpath); + template = strtok(pathcopy, ","); + + while (template && !configFile) { + if ((configPath = DoSubstitution(template, cmdline, projroot, + &cmdlineUsed, NULL, + XFREE86CFGFILE))) { + if ((configFile = fopen(configPath, "r")) != 0) { + if (cmdline && !cmdlineUsed) { + fclose(configFile); + configFile = NULL; + } + } + } + if (configPath && !configFile) { + free(configPath); + configPath = NULL; + } + template = strtok(NULL, ","); + } + } + + free(pathcopy); + + if (!configFile) { + return NULL; + } + + configBuf = malloc(CONFIG_BUF_LEN); + configRBuf = malloc(CONFIG_BUF_LEN); + configBuf[0] = '\0'; + + return configPath; +} + +void xconfigCloseConfigFile (void) +{ + free (configPath); + configPath = NULL; + free (configRBuf); + configRBuf = NULL; + free (configBuf); + configBuf = NULL; + + if (configFile) { + fclose (configFile); + configFile = NULL; + } else { + builtinConfig = NULL; + builtinIndex = 0; + } +} + + +char *xconfigGetConfigFileName(void) +{ + return configPath; +} + + +void +xconfigSetSection (char *section) +{ + if (configSection) + free(configSection); + configSection = malloc(strlen (section) + 1); + strcpy (configSection, section); +} + +/* + * xconfigGetToken -- + * Lookup a string if it is actually a token in disguise. + */ + + +char * +xconfigAddComment(char *cur, char *add) +{ + char *str; + int len, curlen, iscomment, hasnewline = 0, endnewline; + + if (add == NULL || add[0] == '\0') + return (cur); + + if (cur) { + curlen = strlen(cur); + if (curlen) + hasnewline = cur[curlen - 1] == '\n'; + eol_seen = 0; + } + else + curlen = 0; + + str = add; + iscomment = 0; + while (*str) { + if (*str != ' ' && *str != '\t') + break; + ++str; + } + iscomment = (*str == '#'); + + len = strlen(add); + endnewline = add[len - 1] == '\n'; + len += 1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen; + + if ((str = realloc(cur, len + curlen)) == NULL) + return (cur); + + cur = str; + + if (eol_seen || (curlen && !hasnewline)) + cur[curlen++] = '\n'; + if (!iscomment) + cur[curlen++] = '#'; + strcpy(cur + curlen, add); + if (!endnewline) + strcat(cur, "\n"); + + return (cur); +} + +int +xconfigGetStringToken (XConfigSymTabRec * tab) +{ + return StringToToken (val.str, tab); +} + +static int +StringToToken (char *str, XConfigSymTabRec * tab) +{ + int i; + + for (i = 0; tab[i].token != -1; i++) + { + if (!xconfigNameCompare (tab[i].name, str)) + return tab[i].token; + } + return (ERROR_TOKEN); +} + + +/* + * Compare two names. The characters '_', ' ', and '\t' are ignored + * in the comparison. + */ +int +xconfigNameCompare (const char *s1, const char *s2) +{ + char c1, c2; + + if (!s1 || *s1 == 0) { + if (!s2 || *s2 == 0) + return (0); + else + return (1); + } + + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') + s1++; + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') + s2++; + c1 = (xconfigIsUpper(*s1) ? xconfigToLower(*s1) : *s1); + c2 = (xconfigIsUpper(*s2) ? xconfigToLower(*s2) : *s2); + while (c1 == c2) + { + if (c1 == '\0') + return (0); + s1++; + s2++; + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') + s1++; + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') + s2++; + c1 = (xconfigIsUpper(*s1) ? xconfigToLower(*s1) : *s1); + c2 = (xconfigIsUpper(*s2) ? xconfigToLower(*s2) : *s2); + } + return (c1 - c2); +} + +/* + * Compare two modelines. The modeline identifiers and comments are + * ignored in the comparison. + */ +int +xconfigModelineCompare(XConfigModeLinePtr m1, XConfigModeLinePtr m2) +{ + if (!m1 && !m2) + return (0); + + if (!m1 || !m2) + return (1); + + if (m1->clock != m2->clock && + m1->hdisplay != m2->hdisplay && + m1->hsyncstart != m2->hsyncstart && + m1->hsyncend != m2->hsyncend && + m1->htotal != m2->htotal && + m1->vdisplay != m2->vdisplay && + m1->vsyncstart != m2->vsyncstart && + m1->vsyncend != m2->vsyncend && + m1->vtotal != m2->vtotal && + m1->vscan != m2->vscan && + m1->flags != m2->flags && + m1->hskew != m2->hskew) + return (1); + return (0); +} diff --git a/src/XF86Config-parser/Screen.c b/src/XF86Config-parser/Screen.c new file mode 100644 index 0000000..f58d76b --- /dev/null +++ b/src/XF86Config-parser/Screen.c @@ -0,0 +1,679 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec DisplayTab[] = +{ + {ENDSUBSECTION, "endsubsection"}, + {MODES, "modes"}, + {VIEWPORT, "viewport"}, + {VIRTUAL, "virtual"}, + {VISUAL, "visual"}, + {BLACK_TOK, "black"}, + {WHITE_TOK, "white"}, + {DEPTH, "depth"}, + {BPP, "fbbpp"}, + {WEIGHT, "weight"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeDisplayList + +XConfigDisplayPtr +xconfigParseDisplaySubSection (void) +{ + int token; + PARSE_PROLOGUE (XConfigDisplayPtr, XConfigDisplayRec) + + ptr->black.red = ptr->black.green = ptr->black.blue = -1; + ptr->white.red = ptr->white.green = ptr->white.blue = -1; + ptr->frameX0 = ptr->frameY0 = -1; + while ((token = xconfigGetToken (DisplayTab)) != ENDSUBSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case VIEWPORT: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (VIEWPORT_MSG, NULL); + ptr->frameX0 = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (VIEWPORT_MSG, NULL); + ptr->frameY0 = val.num; + break; + case VIRTUAL: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (VIRTUAL_MSG, NULL); + ptr->virtualX = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (VIRTUAL_MSG, NULL); + ptr->virtualY = val.num; + break; + case DEPTH: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Display"); + ptr->depth = val.num; + break; + case BPP: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "Display"); + ptr->bpp = val.num; + break; + case VISUAL: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Display"); + ptr->visual = val.str; + break; + case WEIGHT: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WEIGHT_MSG, NULL); + ptr->weight.red = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WEIGHT_MSG, NULL); + ptr->weight.green = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WEIGHT_MSG, NULL); + ptr->weight.blue = val.num; + break; + case BLACK_TOK: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (BLACK_MSG, NULL); + ptr->black.red = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (BLACK_MSG, NULL); + ptr->black.green = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (BLACK_MSG, NULL); + ptr->black.blue = val.num; + break; + case WHITE_TOK: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WHITE_MSG, NULL); + ptr->white.red = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WHITE_MSG, NULL); + ptr->white.green = val.num; + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (WHITE_MSG, NULL); + ptr->white.blue = val.num; + break; + case MODES: + { + XConfigModePtr mptr; + + while ((token = + xconfigGetSubTokenWithTab(&(ptr->comment), + DisplayTab)) == STRING) + { + mptr = calloc (1, sizeof (XConfigModeRec)); + mptr->mode_name = val.str; + mptr->next = NULL; + ptr->modes = (XConfigModePtr) + xconfigAddListItem ((GenericListPtr) ptr->modes, + (GenericListPtr) mptr); + } + xconfigUnGetToken (token); + } + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +static XConfigSymTabRec ScreenTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {OBSDRIVER, "driver"}, + {MDEVICE, "device"}, + {MONITOR, "monitor"}, + {VIDEOADAPTOR, "videoadaptor"}, + {SCREENNO, "screenno"}, + {SUBSECTION, "subsection"}, + {DEFAULTDEPTH, "defaultcolordepth"}, + {DEFAULTDEPTH, "defaultdepth"}, + {DEFAULTBPP, "defaultbpp"}, + {DEFAULTFBBPP, "defaultfbbpp"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeScreenList +XConfigScreenPtr +xconfigParseScreenSection (void) +{ + int has_ident = FALSE; + int has_driver= FALSE; + int token; + + PARSE_PROLOGUE (XConfigScreenPtr, XConfigScreenRec) + + while ((token = xconfigGetToken (ScreenTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + ptr->identifier = val.str; + if (has_ident || has_driver) + Error (ONLY_ONE_MSG,"Identifier or Driver"); + has_ident = TRUE; + break; + case OBSDRIVER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Driver"); + ptr->obsolete_driver = val.str; + if (has_ident || has_driver) + Error (ONLY_ONE_MSG,"Identifier or Driver"); + has_driver = TRUE; + break; + case DEFAULTDEPTH: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "DefaultDepth"); + ptr->defaultdepth = val.num; + break; + case DEFAULTBPP: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "DefaultBPP"); + ptr->defaultbpp = val.num; + break; + case DEFAULTFBBPP: + if (xconfigGetSubToken (&(ptr->comment)) != NUMBER) + Error (NUMBER_MSG, "DefaultFbBPP"); + ptr->defaultfbbpp = val.num; + break; + case MDEVICE: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Device"); + ptr->device_name = val.str; + break; + case MONITOR: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Monitor"); + ptr->monitor_name = val.str; + break; + case VIDEOADAPTOR: + { + XConfigAdaptorLinkPtr aptr; + + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "VideoAdaptor"); + + /* Don't allow duplicates */ + for (aptr = ptr->adaptors; aptr; + aptr = (XConfigAdaptorLinkPtr) aptr->next) + if (xconfigNameCompare (val.str, aptr->adaptor_name) == 0) + break; + + if (aptr == NULL) + { + aptr = calloc (1, sizeof (XConfigAdaptorLinkRec)); + aptr->next = NULL; + aptr->adaptor_name = val.str; + ptr->adaptors = (XConfigAdaptorLinkPtr) + xconfigAddListItem ((GenericListPtr) ptr->adaptors, + (GenericListPtr) aptr); + } + } + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case SUBSECTION: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "SubSection"); + { + free(val.str); + HANDLE_LIST (displays, xconfigParseDisplaySubSection, + XConfigDisplayPtr); + } + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + if (!has_ident && !has_driver) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +void +xconfigPrintScreenSection (FILE * cf, XConfigScreenPtr ptr) +{ + XConfigAdaptorLinkPtr aptr; + XConfigDisplayPtr dptr; + XConfigModePtr mptr; + + while (ptr) + { + fprintf (cf, "Section \"Screen\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + if (ptr->obsolete_driver) + fprintf (cf, " Driver \"%s\"\n", ptr->obsolete_driver); + if (ptr->device_name) + fprintf (cf, " Device \"%s\"\n", ptr->device_name); + if (ptr->monitor_name) + fprintf (cf, " Monitor \"%s\"\n", ptr->monitor_name); + if (ptr->defaultdepth) + fprintf (cf, " DefaultDepth %d\n", + ptr->defaultdepth); + if (ptr->defaultbpp) + fprintf (cf, " DefaultBPP %d\n", + ptr->defaultbpp); + if (ptr->defaultfbbpp) + fprintf (cf, " DefaultFbBPP %d\n", + ptr->defaultfbbpp); + xconfigPrintOptionList(cf, ptr->options, 1); + for (aptr = ptr->adaptors; aptr; aptr = aptr->next) + { + fprintf (cf, " VideoAdaptor \"%s\"\n", aptr->adaptor_name); + } + for (dptr = ptr->displays; dptr; dptr = dptr->next) + { + fprintf (cf, " SubSection \"Display\"\n"); + if (dptr->comment) + fprintf (cf, "%s", dptr->comment); + if (dptr->frameX0 >= 0 || dptr->frameY0 >= 0) + { + fprintf (cf, " Viewport %d %d\n", + dptr->frameX0, dptr->frameY0); + } + if (dptr->virtualX != 0 || dptr->virtualY != 0) + { + fprintf (cf, " Virtual %d %d\n", + dptr->virtualX, dptr->virtualY); + } + if (dptr->depth) + { + fprintf (cf, " Depth %d\n", dptr->depth); + } + if (dptr->bpp) + { + fprintf (cf, " FbBPP %d\n", dptr->bpp); + } + if (dptr->visual) + { + fprintf (cf, " Visual \"%s\"\n", dptr->visual); + } + if (dptr->weight.red != 0) + { + fprintf (cf, " Weight %d %d %d\n", + dptr->weight.red, dptr->weight.green, dptr->weight.blue); + } + if (dptr->black.red != -1) + { + fprintf (cf, " Black 0x%04x 0x%04x 0x%04x\n", + dptr->black.red, dptr->black.green, dptr->black.blue); + } + if (dptr->white.red != -1) + { + fprintf (cf, " White 0x%04x 0x%04x 0x%04x\n", + dptr->white.red, dptr->white.green, dptr->white.blue); + } + if (dptr->modes) + { + fprintf (cf, " Modes "); + } + for (mptr = dptr->modes; mptr; mptr = mptr->next) + { + fprintf (cf, " \"%s\"", mptr->mode_name); + } + if (dptr->modes) + { + fprintf (cf, "\n"); + } + xconfigPrintOptionList(cf, dptr->options, 2); + fprintf (cf, " EndSubSection\n"); + } + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } + +} + +void +xconfigFreeScreenList (XConfigScreenPtr ptr) +{ + XConfigScreenPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->monitor_name); + TEST_FREE (ptr->device_name); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + xconfigFreeAdaptorLinkList (ptr->adaptors); + xconfigFreeDisplayList (ptr->displays); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeAdaptorLinkList (XConfigAdaptorLinkPtr ptr) +{ + XConfigAdaptorLinkPtr prev; + + while (ptr) + { + TEST_FREE (ptr->adaptor_name); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeDisplayList (XConfigDisplayPtr ptr) +{ + XConfigDisplayPtr prev; + + while (ptr) + { + xconfigFreeModeList (ptr->modes); + xconfigOptionListFree (ptr->options); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeModeList (XConfigModePtr ptr) +{ + XConfigModePtr prev; + + while (ptr) + { + TEST_FREE (ptr->mode_name); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +int +xconfigValidateScreen (XConfigPtr p) +{ + XConfigScreenPtr screen = p->screens; + XConfigMonitorPtr monitor; + XConfigDevicePtr device; + XConfigAdaptorLinkPtr adaptor; + + if (!screen) + { + xconfigErrorMsg(ValidationErrorMsg, "At least one Screen section " + "is required."); + return (FALSE); + } + + while (screen) + { + if (screen->obsolete_driver && !screen->identifier) + screen->identifier = screen->obsolete_driver; + + monitor = xconfigFindMonitor (screen->monitor_name, p->monitors); + if (screen->monitor_name) + { + if (!monitor) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_MONITOR_MSG, + screen->monitor_name, screen->identifier); + return (FALSE); + } + else + { + screen->monitor = monitor; + if (!xconfigValidateMonitor(p, screen)) + return (FALSE); + } + } + + device = xconfigFindDevice (screen->device_name, p->devices); + if (!device) + { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_DEVICE_MSG, + screen->device_name, screen->identifier); + return (FALSE); + } + else + screen->device = device; + + adaptor = screen->adaptors; + while (adaptor) { + adaptor->adaptor = xconfigFindVideoAdaptor(adaptor->adaptor_name, + p->videoadaptors); + if (!adaptor->adaptor) { + xconfigErrorMsg(ValidationErrorMsg, UNDEFINED_ADAPTOR_MSG, + adaptor->adaptor_name, + screen->identifier); + return (FALSE); + } else if (adaptor->adaptor->fwdref) { + xconfigErrorMsg(ValidationErrorMsg, ADAPTOR_REF_TWICE_MSG, + adaptor->adaptor_name, + adaptor->adaptor->fwdref); + return (FALSE); + } + + adaptor->adaptor->fwdref = xconfigStrdup(screen->identifier); + adaptor = adaptor->next; + } + + screen = screen->next; + } + + return (TRUE); +} + +int xconfigSanitizeScreen(XConfigPtr p) +{ + XConfigScreenPtr screen = p->screens; + XConfigMonitorPtr monitor; + + while (screen) { + + /* + * if no monitor for this screen (either the monitor name, or + * the actual monitor pointer), find a monitor: resolve + * discrepancies between screen->monitor_name and + * screen->monitor; otherwise use the first monitor in the + * config; if we still don't have a monitor, add a new one + */ + + if (!screen->monitor_name || !screen->monitor) { + + monitor = NULL; + + if (!monitor && screen->monitor) { + monitor = screen->monitor; + } + + if (!monitor && screen->monitor_name) { + monitor = xconfigFindMonitor(screen->monitor_name, + p->monitors); + } + + if (!monitor && p->monitors) { + monitor = p->monitors; + } + + if (!monitor) { + monitor = xconfigAddMonitor(p, 0); + } + + if (monitor) { + screen->monitor = monitor; + + if (screen->monitor_name) { + free(screen->monitor_name); + } + + screen->monitor_name = xconfigStrdup(monitor->identifier); + + if (!xconfigValidateMonitor(p, screen)) + return (FALSE); + } + } + + screen = screen->next; + } + + return TRUE; +} + + + +XConfigScreenPtr +xconfigFindScreen (const char *ident, XConfigScreenPtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +XConfigModePtr +xconfigFindMode (const char *name, XConfigModePtr p) +{ + while (p) + { + if (xconfigNameCompare (name, p->mode_name) == 0) + return (p); + + p = p->next; + } + return (NULL); +} + +XConfigModePtr +xconfigAddMode(XConfigModePtr head, const char *name) +{ + XConfigModePtr mode; + + mode = xconfigAlloc(sizeof(XConfigModeRec)); + mode->mode_name = xconfigStrdup(name); + + mode->next = head; + + return mode; + +} + + +XConfigModePtr +xconfigRemoveMode(XConfigModePtr head, const char *name) +{ + XConfigModePtr prev = NULL; + XConfigModePtr m = head; + + while (m) { + if (xconfigNameCompare(m->mode_name, name) == 0) { + if (prev) prev->next = m->next; + if (head == m) head = m->next; + free(m->mode_name); + free(m); + break; + } + prev = m; + m = m->next; + } + + return head; +} + + + diff --git a/src/XF86Config-parser/Util.c b/src/XF86Config-parser/Util.c new file mode 100644 index 0000000..f149afa --- /dev/null +++ b/src/XF86Config-parser/Util.c @@ -0,0 +1,185 @@ +/* + * nvidia-xconfig: A tool for manipulating X config files, + * specifically for use by the NVIDIA Linux graphics driver. + * + * Copyright (C) 2005 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + * + * Util.c + */ + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> + +#include "xf86Parser.h" +#include "Configint.h" + +void *xconfigAlloc(size_t size) +{ + void *m = malloc(size); + + if (!m) { + fprintf(stderr, "memory allocation failure (%s)! \n", strerror(errno)); + exit(1); + } + memset((char *) m, 0, size); + return m; + +} /* xconfigAlloc() */ + + +/* + * xconfigStrdup() - wrapper for strdup() that checks the return + * value; if an error occurs, an error is printed to stderr and exit + * is called -- this function will only return on success. + */ + +char *xconfigStrdup(const char *s) +{ + char *m; + + if (!s) return NULL; + + m = strdup(s); + + if (!m) { + fprintf(stderr, "memory allocation failure during strdup (%s)! \n", + strerror(errno)); + exit(1); + } + return m; + +} /* xconfigStrdup() */ + + +/* + * xconfigStrcat() - allocate a new string, copying all given strings + * into it. taken from glib + */ + +char *xconfigStrcat(const char *str, ...) +{ + unsigned int l; + va_list args; + char *s; + char *concat; + + l = 1 + strlen(str); + va_start(args, str); + s = va_arg(args, char *); + + while (s) { + l += strlen(s); + s = va_arg(args, char *); + } + va_end(args); + + concat = xconfigAlloc(l); + concat[0] = 0; + + strcat(concat, str); + va_start(args, str); + s = va_arg(args, char *); + while (s) { + strcat(concat, s); + s = va_arg(args, char *); + } + va_end(args); + + return concat; + +} /* xconfigStrcat() */ + + + + + + +#define NV_FMT_BUF_LEN 64 + +extern int configLineNo; +extern char *configSection; +extern char *configPath; + +void xconfigErrorMsg(MsgType t, char *fmt, ...) +{ + va_list ap; + int len, current_len = NV_FMT_BUF_LEN; + char *b, *pre = NULL, *msg; + char scratch[64]; + + b = xconfigAlloc(current_len); + + while (1) { + va_start(ap, fmt); + len = vsnprintf(b, current_len, fmt, ap); + va_end(ap); + + if ((len > -1) && (len < current_len)) { + break; + } else if (len > -1) { + current_len = len + 1; + } else { + current_len += NV_FMT_BUF_LEN; + } + + free(b); + b = xconfigAlloc(current_len); + } + + switch (t) { + case ParseErrorMsg: + sprintf(scratch, "%d", configLineNo); + pre = xconfigStrcat("Parse error on line ", scratch, " of section ", + configSection, " in file ", configPath, ".\n", NULL); + break; + case ParseWarningMsg: + sprintf(scratch, "%d", configLineNo); + pre = xconfigStrcat("Parse warning on line ", scratch, " of section ", + configSection, " in file ", configPath, ".\n", NULL); + break; + case ValidationErrorMsg: + pre = xconfigStrcat("Data incomplete in file ", configPath, ".\n", NULL); + break; + case InternalErrorMsg: break; + case WriteErrorMsg: break; + case WarnMsg: break; + case ErrorMsg: break; + case DebugMsg: break; + case UnknownMsg: break; + } + + if (pre) { + msg = xconfigStrcat(pre, b, NULL); + } else { + msg = strdup(b); + } + + /* call back into the host to print the message */ + + xconfigPrint(t, msg); + + + free(b); + free(msg); + if (pre) free(pre); +} diff --git a/src/XF86Config-parser/Vendor.c b/src/XF86Config-parser/Vendor.c new file mode 100644 index 0000000..7f6beba --- /dev/null +++ b/src/XF86Config-parser/Vendor.c @@ -0,0 +1,245 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec VendorSubTab[] = +{ + {ENDSUBSECTION, "endsubsection"}, + {IDENTIFIER, "identifier"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeVendorSubList + +XConfigVendSubPtr +xconfigParseVendorSubSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigVendSubPtr, XConfigVendSubRec) + + while ((token = xconfigGetToken (VendorSubTab)) != ENDSUBSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment))) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +static XConfigSymTabRec VendorTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {OPTION, "option"}, + {SUBSECTION, "subsection"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeVendorList + +XConfigVendorPtr +xconfigParseVendorSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigVendorPtr, XConfigVendorRec) + + while ((token = xconfigGetToken (VendorTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case SUBSECTION: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "SubSection"); + { + HANDLE_LIST (subs, xconfigParseVendorSubSection, + XConfigVendSubPtr); + } + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +#undef CLEANUP + +void +xconfigPrintVendorSection (FILE * cf, XConfigVendorPtr ptr) +{ + XConfigVendSubPtr pptr; + + while (ptr) + { + fprintf (cf, "Section \"Vendor\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + + xconfigPrintOptionList(cf, ptr->options, 1); + for (pptr = ptr->subs; pptr; pptr = pptr->next) + { + fprintf (cf, " SubSection \"Vendor\"\n"); + if (pptr->comment) + fprintf (cf, "%s", pptr->comment); + if (pptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", pptr->identifier); + xconfigPrintOptionList(cf, pptr->options, 2); + fprintf (cf, " EndSubSection\n"); + } + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } +} + +void +xconfigFreeVendorList (XConfigVendorPtr p) +{ + if (p == NULL) + return; + xconfigFreeVendorSubList (p->subs); + TEST_FREE (p->identifier); + TEST_FREE (p->comment); + xconfigOptionListFree (p->options); + free (p); +} + +void +xconfigFreeVendorSubList (XConfigVendSubPtr ptr) +{ + XConfigVendSubPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->name); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +XConfigVendorPtr +xconfigFindVendor (const char *name, XConfigVendorPtr list) +{ + while (list) + { + if (xconfigNameCompare (list->identifier, name) == 0) + return (list); + list = list->next; + } + return (NULL); +} + diff --git a/src/XF86Config-parser/Video.c b/src/XF86Config-parser/Video.c new file mode 100644 index 0000000..a09d7f7 --- /dev/null +++ b/src/XF86Config-parser/Video.c @@ -0,0 +1,284 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static XConfigSymTabRec VideoPortTab[] = +{ + {ENDSUBSECTION, "endsubsection"}, + {IDENTIFIER, "identifier"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeVideoPortList + +XConfigVideoPortPtr +xconfigParseVideoPortSubSection (void) +{ + int has_ident = FALSE; + int token; + PARSE_PROLOGUE (XConfigVideoPortPtr, XConfigVideoPortRec) + + while ((token = xconfigGetToken (VideoPortTab)) != ENDSUBSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + ptr->identifier = val.str; + has_ident = TRUE; + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + return ptr; +} + +#undef CLEANUP + +static XConfigSymTabRec VideoAdaptorTab[] = +{ + {ENDSECTION, "endsection"}, + {IDENTIFIER, "identifier"}, + {VENDOR, "vendorname"}, + {BOARD, "boardname"}, + {BUSID, "busid"}, + {DRIVER, "driver"}, + {OPTION, "option"}, + {SUBSECTION, "subsection"}, + {-1, ""}, +}; + +#define CLEANUP xconfigFreeVideoAdaptorList + +XConfigVideoAdaptorPtr +xconfigParseVideoAdaptorSection (void) +{ + int has_ident = FALSE; + int token; + + PARSE_PROLOGUE (XConfigVideoAdaptorPtr, XConfigVideoAdaptorRec) + + while ((token = xconfigGetToken (VideoAdaptorTab)) != ENDSECTION) + { + switch (token) + { + case COMMENT: + ptr->comment = xconfigAddComment(ptr->comment, val.str); + break; + case IDENTIFIER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Identifier"); + ptr->identifier = val.str; + if (has_ident == TRUE) + Error (MULTIPLE_MSG, "Identifier"); + has_ident = TRUE; + break; + case VENDOR: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Vendor"); + ptr->vendor = val.str; + break; + case BOARD: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Board"); + ptr->board = val.str; + break; + case BUSID: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "BusID"); + ptr->busid = val.str; + break; + case DRIVER: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "Driver"); + ptr->driver = val.str; + break; + case OPTION: + ptr->options = xconfigParseOption(ptr->options); + break; + case SUBSECTION: + if (xconfigGetSubToken (&(ptr->comment)) != STRING) + Error (QUOTE_MSG, "SubSection"); + { + HANDLE_LIST (ports, xconfigParseVideoPortSubSection, + XConfigVideoPortPtr); + } + break; + + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + default: + Error (INVALID_KEYWORD_MSG, xconfigTokenString ()); + break; + } + } + + if (!has_ident) + Error (NO_IDENT_MSG, NULL); + + return ptr; +} + +void +xconfigPrintVideoAdaptorSection (FILE * cf, XConfigVideoAdaptorPtr ptr) +{ + XConfigVideoPortPtr pptr; + + while (ptr) + { + fprintf (cf, "Section \"VideoAdaptor\"\n"); + if (ptr->comment) + fprintf (cf, "%s", ptr->comment); + if (ptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", ptr->identifier); + if (ptr->vendor) + fprintf (cf, " VendorName \"%s\"\n", ptr->vendor); + if (ptr->board) + fprintf (cf, " BoardName \"%s\"\n", ptr->board); + if (ptr->busid) + fprintf (cf, " BusID \"%s\"\n", ptr->busid); + if (ptr->driver) + fprintf (cf, " Driver \"%s\"\n", ptr->driver); + xconfigPrintOptionList(cf, ptr->options, 1); + for (pptr = ptr->ports; pptr; pptr = pptr->next) + { + fprintf (cf, " SubSection \"VideoPort\"\n"); + if (pptr->comment) + fprintf (cf, "%s", pptr->comment); + if (pptr->identifier) + fprintf (cf, " Identifier \"%s\"\n", pptr->identifier); + xconfigPrintOptionList(cf, pptr->options, 2); + fprintf (cf, " EndSubSection\n"); + } + fprintf (cf, "EndSection\n\n"); + ptr = ptr->next; + } + +} + +void +xconfigFreeVideoAdaptorList (XConfigVideoAdaptorPtr ptr) +{ + XConfigVideoAdaptorPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->vendor); + TEST_FREE (ptr->board); + TEST_FREE (ptr->busid); + TEST_FREE (ptr->driver); + TEST_FREE (ptr->fwdref); + TEST_FREE (ptr->comment); + xconfigFreeVideoPortList (ptr->ports); + xconfigOptionListFree (ptr->options); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +void +xconfigFreeVideoPortList (XConfigVideoPortPtr ptr) +{ + XConfigVideoPortPtr prev; + + while (ptr) + { + TEST_FREE (ptr->identifier); + TEST_FREE (ptr->comment); + xconfigOptionListFree (ptr->options); + prev = ptr; + ptr = ptr->next; + free (prev); + } +} + +XConfigVideoAdaptorPtr +xconfigFindVideoAdaptor (const char *ident, XConfigVideoAdaptorPtr p) +{ + while (p) + { + if (xconfigNameCompare (ident, p->identifier) == 0) + return (p); + + p = p->next; + } + return (NULL); +} diff --git a/src/XF86Config-parser/Write.c b/src/XF86Config-parser/Write.c new file mode 100644 index 0000000..a1658e2 --- /dev/null +++ b/src/XF86Config-parser/Write.c @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* View/edit this file with tab stops set to 4 */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> + +int xconfigWriteConfigFile (const char *filename, XConfigPtr cptr) +{ + FILE *cf; + + if ((cf = fopen(filename, "w")) == NULL) + { + xconfigErrorMsg(WriteErrorMsg, "Unable to open the file \"%s\" for " + "writing (%s).\n", filename, strerror(errno)); + return FALSE; + } + + if (cptr->comment) + fprintf (cf, "%s\n", cptr->comment); + + xconfigPrintLayoutSection (cf, cptr->layouts); + + fprintf (cf, "Section \"Files\"\n"); + xconfigPrintFileSection (cf, cptr->files); + fprintf (cf, "EndSection\n\n"); + + fprintf (cf, "Section \"Module\"\n"); + xconfigPrintModuleSection (cf, cptr->modules); + fprintf (cf, "EndSection\n\n"); + + xconfigPrintVendorSection (cf, cptr->vendors); + + xconfigPrintServerFlagsSection (cf, cptr->flags); + + xconfigPrintInputSection (cf, cptr->inputs); + + xconfigPrintVideoAdaptorSection (cf, cptr->videoadaptors); + + xconfigPrintModesSection (cf, cptr->modes); + + xconfigPrintMonitorSection (cf, cptr->monitors); + + xconfigPrintDeviceSection (cf, cptr->devices); + + xconfigPrintScreenSection (cf, cptr->screens); + + xconfigPrintDRISection (cf, cptr->dri); + + xconfigPrintExtensionsSection (cf, cptr->extensions); + + fclose(cf); + return TRUE; +} diff --git a/src/XF86Config-parser/configProcs.h b/src/XF86Config-parser/configProcs.h new file mode 100644 index 0000000..59bac71 --- /dev/null +++ b/src/XF86Config-parser/configProcs.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1997-2001 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* Private procs. Public procs are in xf86Parser.h and xf86Optrec.h */ + +#include "xf86Parser.h" + + +/* Device.c */ +XConfigDevicePtr xconfigParseDeviceSection(void); +void xconfigPrintDeviceSection(FILE *cf, XConfigDevicePtr ptr); +int xconfigValidateDevice(XConfigPtr p); + +/* Files.c */ +XConfigFilesPtr xconfigParseFilesSection(void); +void xconfigPrintFileSection(FILE *cf, XConfigFilesPtr ptr); + +/* Flags.c */ +XConfigFlagsPtr xconfigParseFlagsSection(void); +void xconfigPrintServerFlagsSection(FILE *f, XConfigFlagsPtr flags); + +/* Input.c */ +XConfigInputPtr xconfigParseInputSection(void); +void xconfigPrintInputSection(FILE *f, XConfigInputPtr ptr); +int xconfigValidateInput (XConfigPtr p); + +/* Keyboard.c */ +XConfigInputPtr xconfigParseKeyboardSection(void); + +/* Layout.c */ +XConfigLayoutPtr xconfigParseLayoutSection(void); +void xconfigPrintLayoutSection(FILE *cf, XConfigLayoutPtr ptr); +int xconfigValidateLayout(XConfigPtr p); +int xconfigSanitizeLayout(XConfigPtr p, const char *screenName, + GenerateOptions *gop); + +/* Module.c */ +XConfigLoadPtr xconfigParseModuleSubSection(XConfigLoadPtr head, char *name); +XConfigModulePtr xconfigParseModuleSection(void); +void xconfigPrintModuleSection(FILE *cf, XConfigModulePtr ptr); + +/* Monitor.c */ +XConfigModeLinePtr xconfigParseModeLine(void); +XConfigModeLinePtr xconfigParseVerboseMode(void); +XConfigMonitorPtr xconfigParseMonitorSection(void); +XConfigModesPtr xconfigParseModesSection(void); +void xconfigPrintMonitorSection(FILE *cf, XConfigMonitorPtr ptr); +void xconfigPrintModesSection(FILE *cf, XConfigModesPtr ptr); +int xconfigValidateMonitor(XConfigPtr p, XConfigScreenPtr screen); + +/* Pointer.c */ +XConfigInputPtr xconfigParsePointerSection(void); + +/* Screen.c */ +XConfigDisplayPtr xconfigParseDisplaySubSection(void); +XConfigScreenPtr xconfigParseScreenSection(void); +void xconfigPrintScreenSection(FILE *cf, XConfigScreenPtr ptr); +int xconfigValidateScreen(XConfigPtr p); +int xconfigSanitizeScreen(XConfigPtr p); + +/* Vendor.c */ +XConfigVendorPtr xconfigParseVendorSection(void); +XConfigVendSubPtr xconfigParseVendorSubSection (void); +void xconfigPrintVendorSection(FILE * cf, XConfigVendorPtr ptr); + +/* Video.c */ +XConfigVideoPortPtr xconfigParseVideoPortSubSection(void); +XConfigVideoAdaptorPtr xconfigParseVideoAdaptorSection(void); +void xconfigPrintVideoAdaptorSection(FILE *cf, XConfigVideoAdaptorPtr ptr); + +/* Read.c */ +int xconfigValidateConfig(XConfigPtr p); + +/* Scan.c */ +int xconfigGetToken(XConfigSymTabRec *tab); +int xconfigGetSubToken(char **comment); +int xconfigGetSubTokenWithTab(char **comment, XConfigSymTabRec *tab); +void xconfigUnGetToken(int token); +char *xconfigTokenString(void); +void xconfigSetSection(char *section); +int xconfigGetStringToken(XConfigSymTabRec *tab); +char *xconfigGetConfigFileName(void); + +/* Write.c */ + +/* DRI.c */ +XConfigBuffersPtr xconfigParseBuffers (void); +XConfigDRIPtr xconfigParseDRISection (void); +void xconfigPrintDRISection (FILE * cf, XConfigDRIPtr ptr); + +/* Util.c */ +void *xconfigAlloc(size_t size); +void xconfigErrorMsg(MsgType, char *fmt, ...); + +/* Extensions.c */ +XConfigExtensionsPtr xconfigParseExtensionsSection (void); +void xconfigPrintExtensionsSection (FILE * cf, XConfigExtensionsPtr ptr); + +/* Generate.c */ +XConfigMonitorPtr xconfigAddMonitor(XConfigPtr config, int count); +int xconfigAddMouse(GenerateOptions *gop, XConfigPtr config); +int xconfigAddKeyboard(GenerateOptions *gop, XConfigPtr config); diff --git a/src/XF86Config-parser/xf86Parser.h b/src/XF86Config-parser/xf86Parser.h new file mode 100644 index 0000000..40b8162 --- /dev/null +++ b/src/XF86Config-parser/xf86Parser.h @@ -0,0 +1,737 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * This file specifies the external interface for the X configuration + * file parser; based loosely on the XFree86 and Xorg X server + * configuration code. + */ + + +#ifndef _xf86Parser_h_ +#define _xf86Parser_h_ + +#include <stdio.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +// Unix variations: Linux +#if !defined(NV_LINUX) && defined(__linux__) +# define NV_LINUX +#endif // defined(__linux__) + +// Unix variations: SunOS +#if !defined(NV_SUNOS) && defined(__sun__) || defined(__sun) +# define NV_SUNOS +#endif // defined(__sun__) + +// Unix variations: FreeBSD +#if !defined(NV_BSD) && defined(__FreeBSD__) +# define NV_BSD +#endif // defined(__FreeBSD__) + + +/* + * return codes + */ + +typedef enum { + XCONFIG_RETURN_SUCCESS = 0, + XCONFIG_RETURN_NO_XCONFIG_FOUND, + XCONFIG_RETURN_PARSE_ERROR, + XCONFIG_RETURN_ALLOCATION_ERROR, + XCONFIG_RETURN_VALIDATION_ERROR, + XCONFIG_RETURN_INVALID_COMMAND_LINE, + XCONFIG_RETURN_SANITY_ERROR, + XCONFIG_RETURN_WRITE_ERROR +} XConfigError; + + +/* + * Message types + */ + +typedef enum { + ParseErrorMsg, + ParseWarningMsg, + ValidationErrorMsg, + InternalErrorMsg, + WriteErrorMsg, + WarnMsg, + ErrorMsg, + DebugMsg, + UnknownMsg +} MsgType; + + +/* + * The user of libXF86Config-parser should provide an implementation + * of xconfigPrint() + */ + +void xconfigPrint(MsgType t, const char *msg); + + +/* + * all records that need to be linked lists should contain a next + * pointer as their first field, so that they can be cast as a + * GenericListRec + */ + +typedef struct { void *next; } GenericListRec, *GenericListPtr; + + + +/* + * Options are stored in the XConfigOptionRec structure + */ + +typedef struct __xconfigoptionrec { + struct __xconfigoptionrec *next; + char *name; + char *val; + int used; + char *comment; +} XConfigOptionRec, *XConfigOptionPtr; + + + +/* + * Files Section + */ + +typedef struct { + char *logfile; + char *rgbpath; + char *modulepath; + char *inputdevs; + char *fontpath; + char *comment; +} XConfigFilesRec, *XConfigFilesPtr; + +/* Values for load_type */ +#define XCONFIG_LOAD_MODULE 0 +#define XCONFIG_LOAD_DRIVER 1 + + + +/* + * Modules Section + */ + +typedef struct __xconfigloadrec { + struct __xconfigloadrec *next; + int type; + char *name; + XConfigOptionPtr opt; + char *comment; +} XConfigLoadRec, *XConfigLoadPtr; + +typedef struct { + XConfigLoadPtr loads; + char *comment; +} XConfigModuleRec, *XConfigModulePtr; + +#define CONF_IMPLICIT_KEYBOARD "Implicit Core Keyboard" + +#define CONF_IMPLICIT_POINTER "Implicit Core Pointer" + + + +/* + * Modeline structure + */ + +#define XCONFIG_MODE_PHSYNC 0x0001 +#define XCONFIG_MODE_NHSYNC 0x0002 +#define XCONFIG_MODE_PVSYNC 0x0004 +#define XCONFIG_MODE_NVSYNC 0x0008 +#define XCONFIG_MODE_INTERLACE 0x0010 +#define XCONFIG_MODE_DBLSCAN 0x0020 +#define XCONFIG_MODE_CSYNC 0x0040 +#define XCONFIG_MODE_PCSYNC 0x0080 +#define XCONFIG_MODE_NCSYNC 0x0100 +#define XCONFIG_MODE_HSKEW 0x0200 /* hskew provided */ +#define XCONFIG_MODE_BCAST 0x0400 +#define XCONFIG_MODE_CUSTOM 0x0800 /* timing numbers customized by editor */ +#define XCONFIG_MODE_VSCAN 0x1000 + +typedef struct __xconfigconfmodelinerec { + struct __xconfigconfmodelinerec *next; + char *identifier; + int clock; + int hdisplay; + int hsyncstart; + int hsyncend; + int htotal; + int vdisplay; + int vsyncstart; + int vsyncend; + int vtotal; + int vscan; + int flags; + int hskew; + char *comment; +} XConfigModeLineRec, *XConfigModeLinePtr; + + + +/* + * VideoPort and VideoAdapter XXX what are these? + */ + +typedef struct __xconfigconfvideoportrec { + struct __xconfigconfvideoportrec *next; + char *identifier; + XConfigOptionPtr options; + char *comment; +} XConfigVideoPortRec, *XConfigVideoPortPtr; + +typedef struct __xconfigconfvideoadaptorrec { + struct __xconfigconfvideoadaptorrec *next; + char *identifier; + char *vendor; + char *board; + char *busid; + char *driver; + XConfigOptionPtr options; + XConfigVideoPortPtr ports; + char *fwdref; + char *comment; +} XConfigVideoAdaptorRec, *XConfigVideoAdaptorPtr; + + + +/* + * Monitor Section + */ + +#define CONF_MAX_HSYNC 8 +#define CONF_MAX_VREFRESH 8 + +typedef struct { float hi, lo; } parser_range; + +typedef struct { int red, green, blue; } parser_rgb; + +typedef struct __xconfigconfmodesrec { + struct __xconfigconfmodesrec *next; + char *identifier; + XConfigModeLinePtr modelines; + char *comment; +} XConfigModesRec, *XConfigModesPtr; + +typedef struct __xconfigconfmodeslinkrec { + struct __xconfigconfmodeslinkrec *next; + char *modes_name; + XConfigModesPtr modes; +} XConfigModesLinkRec, *XConfigModesLinkPtr; + +typedef struct __xconfigconfmonitorrec { + struct __xconfigconfmonitorrec *next; + char *identifier; + char *vendor; + char *modelname; + int width; /* in mm */ + int height; /* in mm */ + XConfigModeLinePtr modelines; + int n_hsync; + parser_range hsync[CONF_MAX_HSYNC]; + int n_vrefresh; + parser_range vrefresh[CONF_MAX_VREFRESH]; + float gamma_red; + float gamma_green; + float gamma_blue; + XConfigOptionPtr options; + XConfigModesLinkPtr modes_sections; + char *comment; +} XConfigMonitorRec, *XConfigMonitorPtr; + + + +/* + * Device Section + */ + +#define CONF_MAXDACSPEEDS 4 +#define CONF_MAXCLOCKS 128 + +typedef struct __xconfigconfdevicerec { + struct __xconfigconfdevicerec *next; + char *identifier; + char *vendor; + char *board; + char *chipset; + char *busid; + char *card; + char *driver; + char *ramdac; + int dacSpeeds[CONF_MAXDACSPEEDS]; + int videoram; + int textclockfreq; + unsigned long bios_base; + unsigned long mem_base; + unsigned long io_base; + char *clockchip; + int clocks; + int clock[CONF_MAXCLOCKS]; + int chipid; + int chiprev; + int irq; + int screen; + XConfigOptionPtr options; + char *comment; +} XConfigDeviceRec, *XConfigDevicePtr; + + + +/* + * Screen Section + */ + +typedef struct __xconfigmoderec { + struct __xconfigmoderec *next; + char *mode_name; +} XConfigModeRec, *XConfigModePtr; + +typedef struct __xconfigconfdisplayrec { + struct __xconfigconfdisplayrec *next; + int frameX0; + int frameY0; + int virtualX; + int virtualY; + int depth; + int bpp; + char *visual; + parser_rgb weight; + parser_rgb black; + parser_rgb white; + XConfigModePtr modes; + XConfigOptionPtr options; + char *comment; +} XConfigDisplayRec, *XConfigDisplayPtr; + +typedef struct __xconfigconfadaptorlinkrec { + struct __xconfigconfadaptorlinkrec *next; + char *adaptor_name; + XConfigVideoAdaptorPtr adaptor; +} XConfigAdaptorLinkRec, *XConfigAdaptorLinkPtr; + +typedef struct __xconfigconfscreenrec { + struct __xconfigconfscreenrec *next; + char *identifier; + char *obsolete_driver; + int defaultdepth; + int defaultbpp; + int defaultfbbpp; + char *monitor_name; + XConfigMonitorPtr monitor; + char *device_name; + XConfigDevicePtr device; + XConfigAdaptorLinkPtr adaptors; + XConfigDisplayPtr displays; + XConfigOptionPtr options; + char *comment; +} XConfigScreenRec, *XConfigScreenPtr; + + + +/* + * Input Section + */ + +typedef struct __xconfigconfinputrec { + struct __xconfigconfinputrec *next; + char *identifier; + char *driver; + XConfigOptionPtr options; + char *comment; +} XConfigInputRec, *XConfigInputPtr; + + + +/* + * Input Reference; used by layout to store list of XConfigInputPtrs + */ + +typedef struct __xconfigconfinputrefrec { + struct __xconfigconfinputrefrec *next; + XConfigInputPtr input; + char *input_name; + XConfigOptionPtr options; +} XConfigInputrefRec, *XConfigInputrefPtr; + + + +/* + * Adjacency structure; used by layout to store list of + * XConfigScreenPtrs + */ + +/* Values for adj_where */ +#define CONF_ADJ_OBSOLETE -1 +#define CONF_ADJ_ABSOLUTE 0 +#define CONF_ADJ_RIGHTOF 1 +#define CONF_ADJ_LEFTOF 2 +#define CONF_ADJ_ABOVE 3 +#define CONF_ADJ_BELOW 4 +#define CONF_ADJ_RELATIVE 5 + +typedef struct __xconfigconfadjacencyrec { + struct __xconfigconfadjacencyrec *next; + int scrnum; + XConfigScreenPtr screen; + char *screen_name; + XConfigScreenPtr top; + char *top_name; + XConfigScreenPtr bottom; + char *bottom_name; + XConfigScreenPtr left; + char *left_name; + XConfigScreenPtr right; + char *right_name; + int where; + int x; + int y; + char *refscreen; +} XConfigAdjacencyRec, *XConfigAdjacencyPtr; + + + +/* + * XConfigInactiveRec XXX what is this? + */ + +typedef struct __xconfigconfinactiverec { + struct __xconfigconfinactiverec *next; + char *device_name; + XConfigDevicePtr device; +} XConfigInactiveRec, *XConfigInactivePtr; + + + +/* + * Layout Section + */ + +typedef struct __xconfigconflayoutrec { + struct __xconfigconflayoutrec *next; + char *identifier; + XConfigAdjacencyPtr adjacencies; + XConfigInactivePtr inactives; + XConfigInputrefPtr inputs; + XConfigOptionPtr options; + char *comment; +} XConfigLayoutRec, *XConfigLayoutPtr; + + + +/* + * Vendor Section XXX what is this? + */ + +typedef struct __xconfigconfvendsubrec { + struct __xconfigconfvendsubrec *next; + char *name; + char *identifier; + XConfigOptionPtr options; + char *comment; +} XConfigVendSubRec, *XConfigVendSubPtr; + +typedef struct __xconfigconfvendorrec { + struct __xconfigconfvendorrec *next; + char *identifier; + XConfigOptionPtr options; + XConfigVendSubPtr subs; + char *comment; +} XConfigVendorRec, *XConfigVendorPtr; + + + +/* + * DRI section + */ + +typedef struct __xconfigconfbuffersrec { + struct __xconfigconfbuffersrec *next; + int count; + int size; + char *flags; + char *comment; +} XConfigBuffersRec, *XConfigBuffersPtr; + +typedef struct { + char *group_name; + int group; + int mode; + XConfigBuffersPtr buffers; + char * comment; +} XConfigDRIRec, *XConfigDRIPtr; + + + +/* + * ServerFlags Section + */ + +typedef struct { + XConfigOptionPtr options; + char *comment; +} XConfigFlagsRec, *XConfigFlagsPtr; + + + +/* + * Extensions Section + */ + +typedef struct +{ + XConfigOptionPtr options; + char *comment; +} +XConfigExtensionsRec, *XConfigExtensionsPtr; + + +/* + * Configuration file structure + */ + +typedef struct { + XConfigFilesPtr files; + XConfigModulePtr modules; + XConfigFlagsPtr flags; + XConfigVideoAdaptorPtr videoadaptors; + XConfigModesPtr modes; + XConfigMonitorPtr monitors; + XConfigDevicePtr devices; + XConfigScreenPtr screens; + XConfigInputPtr inputs; + XConfigLayoutPtr layouts; + XConfigVendorPtr vendors; + XConfigDRIPtr dri; + XConfigExtensionsPtr extensions; + char *comment; + char *filename; +} XConfigRec, *XConfigPtr; + +typedef struct { + int token; /* id of the token */ + char *name; /* pointer to the LOWERCASED name */ +} XConfigSymTabRec, *XConfigSymTabPtr; + + +/* + * data structure containing options; used during generation of X + * config, and when sanitizing an existing config + */ + +#define X_IS_XF86 0 +#define X_IS_XORG 1 + +typedef struct { + int xserver; + char *x_project_root; + char *keyboard; + char *mouse; + char *keyboard_driver; +} GenerateOptions; + + +/* + * Functions for open, reading, and writing XConfig files. + */ +const char *xconfigOpenConfigFile(const char *, const char *); +XConfigError xconfigReadConfigFile(XConfigPtr *); +int xconfigSanitizeConfig(XConfigPtr p, const char *screenName, + GenerateOptions *gop); +void xconfigCloseConfigFile(void); +int xconfigWriteConfigFile(const char *, XConfigPtr); + +void xconfigFreeConfig(XConfigPtr p); + +/* + * Functions for searching for entries in lists + */ + +XConfigDevicePtr xconfigFindDevice(const char *ident, XConfigDevicePtr p); +XConfigLayoutPtr xconfigFindLayout(const char *name, XConfigLayoutPtr list); +XConfigMonitorPtr xconfigFindMonitor(const char *ident, XConfigMonitorPtr p); +XConfigModesPtr xconfigFindModes(const char *ident, XConfigModesPtr p); +XConfigModeLinePtr xconfigFindModeLine(const char *ident, + XConfigModeLinePtr p); +XConfigScreenPtr xconfigFindScreen(const char *ident, XConfigScreenPtr p); +XConfigModePtr xconfigFindMode(const char *name, XConfigModePtr p); +XConfigInputPtr xconfigFindInput(const char *ident, XConfigInputPtr p); +XConfigInputPtr xconfigFindInputByDriver(const char *driver, + XConfigInputPtr p); +XConfigVendorPtr xconfigFindVendor(const char *name, XConfigVendorPtr list); +XConfigVideoAdaptorPtr xconfigFindVideoAdaptor(const char *ident, + XConfigVideoAdaptorPtr p); + +/* + * Functions for freeing lists + */ + +void xconfigFreeDeviceList(XConfigDevicePtr ptr); +void xconfigFreeFiles(XConfigFilesPtr p); +void xconfigFreeFlags(XConfigFlagsPtr flags); +void xconfigFreeInputList(XConfigInputPtr ptr); +void xconfigFreeLayoutList(XConfigLayoutPtr ptr); +void xconfigFreeAdjacencyList(XConfigAdjacencyPtr ptr); +void xconfigFreeInputrefList(XConfigInputrefPtr ptr); +void xconfigFreeModules(XConfigModulePtr ptr); +void xconfigFreeMonitorList(XConfigMonitorPtr ptr); +void xconfigFreeModesList(XConfigModesPtr ptr); +void xconfigFreeModeLineList(XConfigModeLinePtr ptr); +void xconfigFreeScreenList(XConfigScreenPtr ptr); +void xconfigFreeAdaptorLinkList(XConfigAdaptorLinkPtr ptr); +void xconfigFreeDisplayList(XConfigDisplayPtr ptr); +void xconfigFreeModeList(XConfigModePtr ptr); +void xconfigFreeVendorList(XConfigVendorPtr p); +void xconfigFreeVendorSubList(XConfigVendSubPtr ptr); +void xconfigFreeVideoAdaptorList(XConfigVideoAdaptorPtr ptr); +void xconfigFreeVideoPortList(XConfigVideoPortPtr ptr); +void xconfigFreeBuffersList (XConfigBuffersPtr ptr); +void xconfigFreeDRI(XConfigDRIPtr ptr); +void xconfigFreeExtensions(XConfigExtensionsPtr ptr); + + +/* + * item/list manipulation + */ + +GenericListPtr xconfigAddListItem(GenericListPtr head, GenericListPtr c_new); +GenericListPtr xconfigRemoveListItem(GenericListPtr list, GenericListPtr item); +int xconfigItemNotSublist(GenericListPtr list_1, GenericListPtr list_2); +char *xconfigAddComment(char *cur, char *add); +XConfigLoadPtr xconfigAddNewLoadDirective(XConfigLoadPtr head, + char *name, int type, + XConfigOptionPtr opts, int do_token); +XConfigLoadPtr xconfigRemoveLoadDirective(XConfigLoadPtr head, + XConfigLoadPtr load); + +/* + * Functions for manipulating Options + */ + +XConfigOptionPtr xconfigAddNewOption(XConfigOptionPtr head, + char *name, char *val); +XConfigOptionPtr xconfigRemoveOption(XConfigOptionPtr list, + XConfigOptionPtr opt); +XConfigOptionPtr xconfigOptionListDup(XConfigOptionPtr opt); +void xconfigOptionListFree(XConfigOptionPtr opt); +char *xconfigOptionName(XConfigOptionPtr opt); +char *xconfigOptionValue(XConfigOptionPtr opt); +XConfigOptionPtr xconfigNewOption(char *name, char *value); +XConfigOptionPtr xconfigNextOption(XConfigOptionPtr list); +XConfigOptionPtr xconfigFindOption(XConfigOptionPtr list, const char *name); +char *xconfigFindOptionValue(XConfigOptionPtr list, + const char *name); +int xconfigFindOptionBoolean (XConfigOptionPtr, + const char *name); +XConfigOptionPtr xconfigOptionListCreate(const char **options, + int count, int used); +XConfigOptionPtr xconfigOptionListMerge(XConfigOptionPtr head, + XConfigOptionPtr tail); + +/* + * Miscellaneous utility routines + */ + +char *xconfigStrdup(const char *s); +char *xconfigStrcat(const char *str, ...); +int xconfigNameCompare(const char *s1, const char *s2); +int xconfigModelineCompare(XConfigModeLinePtr m1, XConfigModeLinePtr m2); +char *xconfigULongToString(unsigned long i); +XConfigOptionPtr xconfigParseOption(XConfigOptionPtr head); +void xconfigPrintOptionList(FILE *fp, XConfigOptionPtr list, int tabs); +int xconfigParsePciBusString(const char *busID, + int *bus, int *device, int *func); + +XConfigDisplayPtr +xconfigAddDisplay(XConfigDisplayPtr head, const int depth); + +XConfigModePtr +xconfigAddMode(XConfigModePtr head, const char *name); + +XConfigModePtr +xconfigRemoveMode(XConfigModePtr head, const char *name); + + +XConfigPtr xconfigGenerate(GenerateOptions *gop); + +XConfigScreenPtr xconfigGenerateAddScreen(XConfigPtr config, int bus, int slot, + char *boardname, int count); + +void xconfigGenerateAssignScreenAdjacencies(XConfigLayoutPtr layout); + +void xconfigGeneratePrintPossibleMice(void); +void xconfigGeneratePrintPossibleKeyboards(void); + +/* + * check (and update, if necessary) the inputs in the specified layout + * section + */ + +int xconfigCheckCoreInputDevices(GenerateOptions *gop, + XConfigPtr config, XConfigLayoutPtr layout); + +#endif /* _xf86Parser_h_ */ diff --git a/src/XF86Config-parser/xf86tokens.h b/src/XF86Config-parser/xf86tokens.h new file mode 100644 index 0000000..1189bc0 --- /dev/null +++ b/src/XF86Config-parser/xf86tokens.h @@ -0,0 +1,276 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/parser/xf86tokens.h,v 1.20 2003/08/24 17:37:09 dawes Exp $ */ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 + * THE X CONSORTIUM 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 the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +#ifndef _xf86_tokens_h +#define _xf86_tokens_h + +/* Undefine symbols that some OSs might define */ +#undef IOBASE + +/* + * Each token should have a unique value regardless of the section + * it is used in. + */ + +typedef enum { + /* errno-style tokens */ + EOF_TOKEN = -4, + LOCK_TOKEN = -3, + ERROR_TOKEN = -2, + + /* value type tokens */ + NUMBER = 1, + STRING, + + /* Tokens that can appear in many sections */ + SECTION, + SUBSECTION, + ENDSECTION, + ENDSUBSECTION, + IDENTIFIER, + VENDOR, + DASH, + COMMA, + OPTION, + COMMENT, + + /* Frequency units */ + HRZ, + KHZ, + MHZ, + + /* File tokens */ + FONTPATH, + RGBPATH, + MODULEPATH, + INPUTDEVICES, + LOGFILEPATH, + + /* Server Flag tokens. These are deprecated in favour of generic Options */ + NOTRAPSIGNALS, + DONTZAP, + DONTZOOM, + DISABLEVIDMODE, + ALLOWNONLOCAL, + DISABLEMODINDEV, + MODINDEVALLOWNONLOCAL, + ALLOWMOUSEOPENFAIL, + BLANKTIME, + STANDBYTIME, + SUSPENDTIME, + OFFTIME, + DEFAULTLAYOUT, + + /* Monitor tokens */ + MODEL, + MODELINE, + DISPLAYSIZE, + HORIZSYNC, + VERTREFRESH, + MODE, + GAMMA, + USEMODES, + + /* Modes tokens */ + /* no new ones */ + + /* Mode tokens */ + DOTCLOCK, + HTIMINGS, + VTIMINGS, + FLAGS, + HSKEW, + BCAST, + VSCAN, + ENDMODE, + + /* Screen tokens */ + OBSDRIVER, + MDEVICE, + MONITOR, + SCREENNO, + DEFAULTDEPTH, + DEFAULTBPP, + DEFAULTFBBPP, + + /* VideoAdaptor tokens */ + VIDEOADAPTOR, + + /* Mode timing tokens */ + TT_INTERLACE, + TT_PHSYNC, + TT_NHSYNC, + TT_PVSYNC, + TT_NVSYNC, + TT_CSYNC, + TT_PCSYNC, + TT_NCSYNC, + TT_DBLSCAN, + TT_HSKEW, + TT_BCAST, + TT_VSCAN, + TT_CUSTOM, + + /* Module tokens */ + LOAD, + LOAD_DRIVER, + + /* Device tokens */ + DRIVER, + CHIPSET, + CLOCKS, + VIDEORAM, + BOARD, + IOBASE, + RAMDAC, + DACSPEED, + BIOSBASE, + MEMBASE, + CLOCKCHIP, + CHIPID, + CHIPREV, + CARD, + BUSID, + TEXTCLOCKFRQ, + IRQ, + + /* Keyboard tokens */ + AUTOREPEAT, + XLEDS, + KPROTOCOL, + XKBKEYMAP, + XKBCOMPAT, + XKBTYPES, + XKBKEYCODES, + XKBGEOMETRY, + XKBSYMBOLS, + XKBDISABLE, + PANIX106, + XKBRULES, + XKBMODEL, + XKBLAYOUT, + XKBVARIANT, + XKBOPTIONS, + /* The next two have become ServerFlags options */ + VTINIT, + VTSYSREQ, + /* Obsolete keyboard tokens */ + SERVERNUM, + LEFTALT, + RIGHTALT, + SCROLLLOCK_TOK, + RIGHTCTL, + /* arguments for the above obsolete tokens */ + CONF_KM_META, + CONF_KM_COMPOSE, + CONF_KM_MODESHIFT, + CONF_KM_MODELOCK, + CONF_KM_SCROLLLOCK, + CONF_KM_CONTROL, + + /* Pointer tokens */ + EMULATE3, + BAUDRATE, + SAMPLERATE, + PRESOLUTION, + CLEARDTR, + CLEARRTS, + CHORDMIDDLE, + PROTOCOL, + PDEVICE, + EM3TIMEOUT, + DEVICE_NAME, + ALWAYSCORE, + PBUTTONS, + ZAXISMAPPING, + + /* Pointer Z axis mapping tokens */ + XAXIS, + YAXIS, + + /* Display tokens */ + MODES, + VIEWPORT, + VIRTUAL, + VISUAL, + BLACK_TOK, + WHITE_TOK, + DEPTH, + BPP, + WEIGHT, + + /* Layout Tokens */ + SCREEN, + INACTIVE, + INPUTDEVICE, + + /* Adjaceny Tokens */ + RIGHTOF, + LEFTOF, + ABOVE, + BELOW, + RELATIVE, + ABSOLUTE, + + /* Vendor Tokens */ + VENDORNAME, + + /* DRI Tokens */ + GROUP, + BUFFERS +} ParserTokens; + +#endif /* _xf86_tokens_h */ diff --git a/src/command-line.c b/src/command-line.c index 199db69..0a918e6 100644 --- a/src/command-line.c +++ b/src/command-line.c @@ -51,6 +51,14 @@ static char *tilde_expansion(char *str); static char *nvstrcat(const char *str, ...); /* + * verbosity, controls output of errors, warnings and other + * information (used by msg.c). + */ + +int __verbosity = VERBOSITY_DEFAULT; + + +/* * print_version() - print version information */ @@ -110,6 +118,17 @@ static const NVGetoptOption __options[] = { "the X server, and exit. This mode of operation is useful to place " "in your .xinitrc file, for example." }, + { "no-config", 'n', 0, NULL, + "Do not load the configuration file. This mode of operation is useful " + "if nvidia-settings has difficulties starting due to problems with " + "applying settings in the configuration file." }, + + { "verbose", 'V', NVGETOPT_HAS_ARGUMENT, NULL, + "Controls how much information is printed. Valid values are 'errors' " + "(print error messages), 'warnings' (print error and warning messages), " + "and 'all' (print error, warning and other informational messages). By " + "default, only errors are printed." }, + { "assign", 'a', NVGETOPT_HAS_ARGUMENT, print_assign_help, NULL }, { "query", 'q', NVGETOPT_HAS_ARGUMENT, print_query_help, NULL }, @@ -292,8 +311,24 @@ Options *parse_command_line(int argc, char *argv[], char *dpy) switch (c) { case 'v': print_version(); exit(0); break; case 'h': print_help(); exit(0); break; - case 'l': op->load = 1; break; + case 'l': op->only_load = 1; break; + case 'n': op->no_load = 1; break; case 'c': op->ctrl_display = strval; break; + case 'V': + __verbosity = VERBOSITY_DEFAULT; + if (nv_strcasecmp(strval, "errors") == NV_TRUE) { + __verbosity = VERBOSITY_ERROR; + } else if (nv_strcasecmp(strval, "warnings") == NV_TRUE) { + __verbosity = VERBOSITY_WARNING; + } else if (nv_strcasecmp(strval, "all") == NV_TRUE) { + __verbosity = VERBOSITY_ALL; + } else { + nv_error_msg("Invalid verbosity level '%s'. Please run " + "`%s --help` for usage information.\n", + strval, argv[0]); + exit(0); + } + break; case 'a': n = op->num_assignments; op->assignments = realloc(op->assignments, sizeof(char *) * (n+1)); diff --git a/src/command-line.h b/src/command-line.h index 0591751..fd1ed7f 100644 --- a/src/command-line.h +++ b/src/command-line.h @@ -29,6 +29,12 @@ #define DEFAULT_RC_FILE "~/.nvidia-settings-rc" +#define VERBOSITY_ERROR 0 /* errors only */ +#define VERBOSITY_WARNING 1 /* errors and warnings */ +#define VERBOSITY_ALL 2 /* errors, warnings and other info */ + +#define VERBOSITY_DEFAULT VERBOSITY_ERROR + /* * Options structure -- stores the parameters specified on the * commandline. @@ -69,11 +75,17 @@ typedef struct { * array. */ - int load; /* + int only_load; /* * If true, just read the configuration file, * send the attributes to the X server, and * exit. */ + + int no_load; /* + * If true, do not load the configuration file. + * The attributes are not sent to the X Server. + */ + } Options; diff --git a/src/config-file.c b/src/config-file.c index c620795..0ebd8d1 100644 --- a/src/config-file.c +++ b/src/config-file.c @@ -46,6 +46,7 @@ #include <ctype.h> #include <stdlib.h> #include <time.h> +#include <locale.h> #include "NvCtrlAttributes.h" @@ -79,9 +80,8 @@ static void save_gui_parsed_attributes(ParsedAttributeWrapper *w, static float get_color_value(int attr, float c[3], float b[3], float g[3]); -static int parse_config_properties(const char *line, ConfigProperties *conf); - -static void init_config_properties(ConfigProperties *conf); +static int parse_config_property(const char *file, const char *line, + ConfigProperties *conf); static void write_config_properties(FILE *stream, ConfigProperties *conf); @@ -97,6 +97,9 @@ static void write_config_properties(FILE *stream, ConfigProperties *conf); * message is printed to stderr, NV_FALSE is returned, and nothing is * sent to the X server. * + * NOTE: The conf->locale should have already been setup by calling + * init_config_properties() prior to calling this function. + * * XXX should we do any sort of versioning to handle compatibility * problems in the future? */ @@ -106,13 +109,9 @@ int nv_read_config_file(const char *file, const char *display_name, { int fd, ret, length; struct stat stat_buf; - char *buf; + char *buf, *locale; ParsedAttributeWrapper *w = NULL; - /* initialize the ConfigProperties */ - - init_config_properties(conf); - /* open the file */ fd = open(file, O_RDONLY); @@ -149,19 +148,28 @@ int nv_read_config_file(const char *file, const char *display_name, file, strerror(errno)); return NV_FALSE; } - - /* parse the actual text in the file */ + + + /* + * save the current locale, parse the actual text in the file + * and restore the saved locale (could be changed). + */ + + locale = strdup(conf->locale); w = parse_config_file(buf, file, length, conf); + setlocale(LC_ALL, locale); + free(locale); + + /* unmap and close the file */ + if (munmap (buf, stat_buf.st_size) == -1) { nv_error_msg("Unable to unmap file '%s' after reading (%s).", file, strerror(errno)); return NV_FALSE; } - /* close the file */ - close(fd); if (!w) return NV_FALSE; @@ -479,7 +487,7 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, /* first, see if this line is a config property */ - if (!parse_config_properties(tmp, conf)) { + if (!parse_config_property(file, tmp, conf)) { w = realloc(w, sizeof(ParsedAttributeWrapper) * (n+1)); @@ -674,9 +682,10 @@ ConfigPropertiesTableEntry configPropertyTable[] = { * property, return NV_FALSE. */ -static int parse_config_properties(const char *line, ConfigProperties *conf) +static int parse_config_property(const char *file, const char *line, ConfigProperties *conf) { char *no_spaces, *s; + char *locale; ConfigPropertiesTableEntry *t; int ret = NV_FALSE; unsigned int flag; @@ -691,23 +700,34 @@ static int parse_config_properties(const char *line, ConfigProperties *conf) *s = '\0'; - for (t = configPropertyTable, flag = 0; t->name; t++) { - if (nv_strcasecmp(no_spaces, t->name)) { - flag = t->flag; - break; + if (nv_strcasecmp(no_spaces, "RcFileLocale")) { + locale = ++s; + if (setlocale(LC_ALL, locale) == NULL) { + nv_warning_msg("Error parsing configuration file '%s': could " + "not set the specified locale '%s'.", + file, locale); + ret = NV_TRUE; + goto done; + } + } else { + for (t = configPropertyTable, flag = 0; t->name; t++) { + if (nv_strcasecmp(no_spaces, t->name)) { + flag = t->flag; + break; + } } - } - if (!flag) goto done; + if (!flag) goto done; - s++; + s++; - if (nv_strcasecmp(s, "yes")) { - conf->booleans |= flag; - } else if (nv_strcasecmp(s, "no")) { - conf->booleans &= ~flag; - } else { - goto done; + if (nv_strcasecmp(s, "yes")) { + conf->booleans |= flag; + } else if (nv_strcasecmp(s, "no")) { + conf->booleans &= ~flag; + } else { + goto done; + } } ret = NV_TRUE; @@ -735,6 +755,8 @@ static void write_config_properties(FILE *stream, ConfigProperties *conf) fprintf(stream, "# ConfigProperties:\n"); fprintf(stream, "\n"); + fprintf(stream, "RcFileLocale = %s\n", conf->locale); + for (t = configPropertyTable; t->name; t++) { fprintf(stream, "%s = %s\n", t->name, (t->flag & conf->booleans) ? "Yes" : "No"); @@ -748,7 +770,7 @@ static void write_config_properties(FILE *stream, ConfigProperties *conf) * structure. */ -static void init_config_properties(ConfigProperties *conf) +void init_config_properties(ConfigProperties *conf) { memset(conf, 0, sizeof(ConfigProperties)); @@ -758,4 +780,6 @@ static void init_config_properties(ConfigProperties *conf) CONFIG_PROPERTIES_SLIDER_TEXT_ENTRIES | CONFIG_PROPERTIES_SHOW_QUIT_DIALOG); + conf->locale = strdup(setlocale(LC_ALL, NULL)); + } /* init_config_properties() */ diff --git a/src/config-file.h b/src/config-file.h index c0516d4..ae787ce 100644 --- a/src/config-file.h +++ b/src/config-file.h @@ -43,9 +43,12 @@ typedef struct { unsigned int booleans; + char *locale; } ConfigProperties; +void init_config_properties(ConfigProperties *conf); + int nv_read_config_file(const char *, const char *, ParsedAttribute *, ConfigProperties *); diff --git a/src/gtk+-2.x/Makefile.inc b/src/gtk+-2.x/Makefile.inc index 9794f16..90ca4a9 100644 --- a/src/gtk+-2.x/Makefile.inc +++ b/src/gtk+-2.x/Makefile.inc @@ -40,10 +40,8 @@ SRC += \ ctkwindow.c \ ctkopengl.c \ ctkglx.c \ - ctkdevice.c \ ctkhelp.c \ ctkimagesliders.c \ - ctkdisplaydevice.c \ ctkdisplaydevice-crt.c \ ctkdisplaydevice-tv.c \ ctkdisplaydevice-dfp.c \ @@ -55,10 +53,18 @@ SRC += \ ctkclocks.c \ ctkutils.c \ ctkedid.c \ - ctkimage.c + ctkimage.c \ + ctkserver.c \ + ctkdisplaylayout.c \ + ctkdisplayconfig.c \ + ctkscreen.c \ + ctkgpu.c \ + ctkbanner.c \ + ctkvcsc.c EXTRA_DIST += \ + Makefile.inc \ ctkxvideo.h \ ctkcursorshadow.h \ ctkui.h \ @@ -73,10 +79,8 @@ EXTRA_DIST += \ ctkwindow.h \ ctkopengl.h \ ctkglx.h \ - ctkdevice.h \ ctkhelp.h \ ctkimagesliders.h \ - ctkdisplaydevice.h \ ctkdisplaydevice-crt.h \ ctkdisplaydevice-tv.h \ ctkdisplaydevice-dfp.h \ @@ -89,4 +93,14 @@ EXTRA_DIST += \ ctkclocks.h \ ctkutils.h \ ctkedid.h \ - ctkimage.h + ctkimage.h \ + ctkserver.h \ + ctkdisplaylayout.h \ + ctkdisplayconfig.h \ + ctkscreen.h \ + ctkgpu.h \ + ctkbanner.h \ + ctkvcsc.h + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/gtk+-2.x/ctkbanner.c b/src/gtk+-2.x/ctkbanner.c new file mode 100644 index 0000000..5921535 --- /dev/null +++ b/src/gtk+-2.x/ctkbanner.c @@ -0,0 +1,228 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2006 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <gtk/gtk.h> + +#include "image.h" +#include "ctkbanner.h" + +static void +ctk_banner_class_init (CtkBannerClass *); + +static void +ctk_banner_finalize (GObject *); + +static gboolean +ctk_banner_expose_event (GtkWidget *, GdkEventExpose *); + +static void +ctk_banner_size_request (GtkWidget *, GtkRequisition *); + +static gboolean +ctk_banner_configure_event (GtkWidget *, GdkEventConfigure *); + +static GObjectClass *parent_class; + + +GType ctk_banner_get_type( + void +) +{ + static GType ctk_banner_type = 0; + + if (!ctk_banner_type) { + static const GTypeInfo ctk_banner_info = { + sizeof (CtkBannerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ctk_banner_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CtkBanner), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_banner_type = g_type_register_static(GTK_TYPE_DRAWING_AREA, + "CtkBanner", &ctk_banner_info, 0); + } + + return ctk_banner_type; +} + +static void ctk_banner_class_init( + CtkBannerClass *ctk_banner_class +) +{ + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass *) ctk_banner_class; + gobject_class = (GObjectClass *) ctk_banner_class; + + parent_class = g_type_class_peek_parent(ctk_banner_class); + + gobject_class->finalize = ctk_banner_finalize; + + widget_class->expose_event = ctk_banner_expose_event; + widget_class->size_request = ctk_banner_size_request; + widget_class->configure_event = ctk_banner_configure_event; +} + +static void ctk_banner_finalize( + GObject *object +) +{ + CtkBanner *ctk_banner = CTK_BANNER(object); + + g_object_unref(ctk_banner->gdk_img_pixbuf); + g_object_unref(ctk_banner->gdk_img_fill_pixbuf); + + if (ctk_banner->gdk_pixbuf) + g_object_unref(ctk_banner->gdk_pixbuf); + + free_decompressed_image(ctk_banner->image_data, NULL); +} + +static gboolean ctk_banner_expose_event( + GtkWidget *widget, + GdkEventExpose *event +) +{ + CtkBanner *ctk_banner = CTK_BANNER(widget); + + gdk_draw_pixbuf(widget->window, + widget->style->fg_gc[GTK_STATE_NORMAL], + ctk_banner->gdk_pixbuf, + 0, 0, 0, 0, -1, -1, + GDK_RGB_DITHER_NORMAL, 0, 0); + + return FALSE; +} + +static gboolean ctk_banner_configure_event( + GtkWidget *widget, + GdkEventConfigure *event +) +{ + CtkBanner *ctk_banner = CTK_BANNER(widget); + gboolean has_alpha = FALSE; + + if ((event->width < ctk_banner->img->width) || + (event->height < ctk_banner->img->height)) + return FALSE; + + if (ctk_banner->gdk_pixbuf) + g_object_unref(ctk_banner->gdk_pixbuf); + + /* RGBA */ + if (ctk_banner->img->bytes_per_pixel == 4) + has_alpha = TRUE; + + ctk_banner->gdk_pixbuf = + gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, + MAX(event->width, ctk_banner->img->width), + MAX(event->height, ctk_banner->img->height)); + + gdk_pixbuf_copy_area(ctk_banner->gdk_img_pixbuf, + 0, 0, ctk_banner->img->fill_column_index, + ctk_banner->img->height, + ctk_banner->gdk_pixbuf, + 0, 0); + + gdk_pixbuf_scale(ctk_banner->gdk_img_fill_pixbuf, + ctk_banner->gdk_pixbuf, + ctk_banner->img->fill_column_index, 0, + MAX((event->width - ctk_banner->img->width), 1), + ctk_banner->img->height, 0.0f, 0.0f, + (ctk_banner->img->fill_column_index + + MAX((event->width - ctk_banner->img->width), 1)), + 1.0f, GDK_INTERP_NEAREST); + + gdk_pixbuf_copy_area(ctk_banner->gdk_img_pixbuf, + ctk_banner->img->fill_column_index, 0, + ctk_banner->img->fill_column_index, + ctk_banner->img->height, + ctk_banner->gdk_pixbuf, + (gdk_pixbuf_get_width(ctk_banner->gdk_pixbuf) - + ctk_banner->img->fill_column_index), + 0); + + return FALSE; +} + +static void ctk_banner_size_request( + GtkWidget *widget, + GtkRequisition *requisition +) +{ + CtkBanner *ctk_banner = CTK_BANNER(widget); + + requisition->width = ctk_banner->img->width; + requisition->height = ctk_banner->img->height; +} + +GtkWidget* ctk_banner_new(const nv_image_t *img) +{ + GObject *object; + CtkBanner *ctk_banner; + guint8 *image_data; + gboolean has_alpha = FALSE; + + if (!img->fill_column_index) return NULL; + + image_data = decompress_image_data(img); + if (!image_data) return NULL; + + object = g_object_new(CTK_TYPE_BANNER, NULL); + + ctk_banner = CTK_BANNER(object); + + ctk_banner->image_data = image_data; + + ctk_banner->img = img; + ctk_banner->gdk_pixbuf = NULL; + + /* RGBA */ + if (ctk_banner->img->bytes_per_pixel == 4) + has_alpha = TRUE; + + ctk_banner->gdk_img_pixbuf = + gdk_pixbuf_new_from_data(image_data, GDK_COLORSPACE_RGB, + has_alpha, 8, img->width, img->height, + img->width * img->bytes_per_pixel, + NULL, NULL); + + ctk_banner->gdk_img_fill_pixbuf = + gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, + 1, ctk_banner->img->height); + + gdk_pixbuf_copy_area(ctk_banner->gdk_img_pixbuf, + ctk_banner->img->fill_column_index, 0, 1, + ctk_banner->img->height, + ctk_banner->gdk_img_fill_pixbuf, + 0, 0); + + return GTK_WIDGET(object); +} diff --git a/src/gtk+-2.x/ctkbanner.h b/src/gtk+-2.x/ctkbanner.h new file mode 100644 index 0000000..7f9df73 --- /dev/null +++ b/src/gtk+-2.x/ctkbanner.h @@ -0,0 +1,77 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2006 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_BANNER_H__ +#define __CTK_BANNER_H__ + +#include "image.h" + +G_BEGIN_DECLS + +#define CTK_TYPE_BANNER (ctk_banner_get_type()) + +#define CTK_BANNER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_BANNER, CtkBanner)) + +#define CTK_BANNER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_BANNER, CtkBannerClass)) + +#define CTK_IS_BANNER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_BANNER)) + +#define CTK_IS_BANNER_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_BANNER)) + +#define CTK_BANNER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_BANNER, CtkBannerClass)) + + +typedef struct _CtkBanner CtkBanner; +typedef struct _CtkBannerClass CtkBannerClass; + +struct _CtkBanner +{ + GtkDrawingArea parent; + + const nv_image_t *img; + + guint8 *image_data; + + GdkPixbuf *gdk_img_pixbuf; + GdkPixbuf *gdk_img_fill_pixbuf; + GdkPixbuf *gdk_pixbuf; +}; + +struct _CtkBannerClass +{ + GtkDrawingAreaClass parent_class; +}; + +GType ctk_banner_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_banner_new (const nv_image_t *); + +G_END_DECLS + +#endif /* __CTK_BANNER_H__ */ + diff --git a/src/gtk+-2.x/ctkclocks.c b/src/gtk+-2.x/ctkclocks.c index 9835ec4..023b593 100644 --- a/src/gtk+-2.x/ctkclocks.c +++ b/src/gtk+-2.x/ctkclocks.c @@ -692,11 +692,6 @@ GtkWidget* ctk_clocks_new(NvCtrlAttributeHandle *handle, CTK_EVENT_NAME(NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS), G_CALLBACK(clocks_received), (gpointer) ctk_object); - - g_signal_connect(G_OBJECT(ctk_event), - CTK_EVENT_NAME(NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS), - G_CALLBACK(clocks_received), - (gpointer) ctk_object); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE), @@ -1150,6 +1145,10 @@ static void sync_gui_to_modify_clocks(CtkClocks *ctk_object, int which_clocks) GET_GPU_CLOCK(clk_ranges.u.range.min), GET_GPU_CLOCK(clk_ranges.u.range.max)); + g_signal_handlers_unblock_by_func(G_OBJECT(gtk_adjustment_gpu), + G_CALLBACK(adjustment_value_changed), + (gpointer) ctk_object); + gtk_range = GTK_RANGE(CTK_SCALE(ctk_object->mem_clk_scale)->gtk_scale); gtk_adjustment_mem = GTK_ADJUSTMENT(gtk_range->adjustment); @@ -1166,11 +1165,6 @@ static void sync_gui_to_modify_clocks(CtkClocks *ctk_object, int which_clocks) G_CALLBACK(adjustment_value_changed), (gpointer) ctk_object); - g_signal_handlers_unblock_by_func(G_OBJECT(gtk_adjustment_gpu), - G_CALLBACK(adjustment_value_changed), - (gpointer) ctk_object); - - /* Update the gui sensitivity */ sync_gui_sensitivity(ctk_object); diff --git a/src/gtk+-2.x/ctkconfig.c b/src/gtk+-2.x/ctkconfig.c index cf3abe6..8ce1421 100644 --- a/src/gtk+-2.x/ctkconfig.c +++ b/src/gtk+-2.x/ctkconfig.c @@ -714,6 +714,7 @@ void ctk_config_add_timer(CtkConfig *ctk_config, gpointer data) { GtkTreeIter iter; + gchar *s = g_strdup(descr); /* Timer defaults to user enabled/owner disabled */ @@ -722,7 +723,7 @@ void ctk_config_add_timer(CtkConfig *ctk_config, USER_ENABLE_COLUMN, TRUE, OWNER_ENABLE_COLUMN, FALSE, TIME_INTERVAL_COLUMN, interval, - DESCRIPTION_COLUMN, descr, + DESCRIPTION_COLUMN, s, FUNCTION_COLUMN, function, DATA_COLUMN, data, -1); @@ -746,6 +747,7 @@ void ctk_config_remove_timer(CtkConfig *ctk_config, GSourceFunc function) guint handle; gboolean user_enabled; gboolean owner_enabled; + gchar *descr; model = GTK_TREE_MODEL(ctk_config->list_store); @@ -756,6 +758,7 @@ void ctk_config_remove_timer(CtkConfig *ctk_config, GSourceFunc function) FUNCTION_COLUMN, &func, USER_ENABLE_COLUMN, &user_enabled, OWNER_ENABLE_COLUMN, &owner_enabled, + DESCRIPTION_COLUMN, &descr, HANDLE_COLUMN, &handle, -1); if (func == function) { @@ -764,6 +767,7 @@ void ctk_config_remove_timer(CtkConfig *ctk_config, GSourceFunc function) if (user_enabled && owner_enabled) { g_source_remove(handle); } + g_free(descr); gtk_list_store_remove(ctk_config->list_store, &iter); break; } @@ -780,7 +784,7 @@ void ctk_config_remove_timer(CtkConfig *ctk_config, GSourceFunc function) } } -void ctk_config_start_timer(CtkConfig *ctk_config, GSourceFunc function) +void ctk_config_start_timer(CtkConfig *ctk_config, GSourceFunc function, gpointer data) { GtkTreeModel *model; GtkTreeIter iter; @@ -790,7 +794,7 @@ void ctk_config_start_timer(CtkConfig *ctk_config, GSourceFunc function) guint interval; gboolean user_enabled; gboolean owner_enabled; - gpointer data; + gpointer model_data; model = GTK_TREE_MODEL(ctk_config->list_store); @@ -801,10 +805,10 @@ void ctk_config_start_timer(CtkConfig *ctk_config, GSourceFunc function) OWNER_ENABLE_COLUMN, &owner_enabled, HANDLE_COLUMN, &handle, FUNCTION_COLUMN, &func, - DATA_COLUMN, &data, + DATA_COLUMN, &model_data, TIME_INTERVAL_COLUMN, &interval, -1); - if (func == function) { + if ((func == function) && (model_data == data)) { /* Start the timer if is enabled by the user and it is not already running. */ @@ -822,7 +826,7 @@ void ctk_config_start_timer(CtkConfig *ctk_config, GSourceFunc function) } } -void ctk_config_stop_timer(CtkConfig *ctk_config, GSourceFunc function) +void ctk_config_stop_timer(CtkConfig *ctk_config, GSourceFunc function, gpointer data) { GtkTreeModel *model; GtkTreeIter iter; @@ -832,7 +836,7 @@ void ctk_config_stop_timer(CtkConfig *ctk_config, GSourceFunc function) guint interval; gboolean user_enabled; gboolean owner_enabled; - gpointer data; + gpointer model_data; model = GTK_TREE_MODEL(ctk_config->list_store); @@ -843,10 +847,10 @@ void ctk_config_stop_timer(CtkConfig *ctk_config, GSourceFunc function) OWNER_ENABLE_COLUMN, &owner_enabled, HANDLE_COLUMN, &handle, FUNCTION_COLUMN, &func, - DATA_COLUMN, &data, + DATA_COLUMN, &model_data, TIME_INTERVAL_COLUMN, &interval, -1); - if (func == function) { + if ((func == function) && (model_data == data)) { /* Remove the timer if was running. */ diff --git a/src/gtk+-2.x/ctkconfig.h b/src/gtk+-2.x/ctkconfig.h index 8599701..c978600 100644 --- a/src/gtk+-2.x/ctkconfig.h +++ b/src/gtk+-2.x/ctkconfig.h @@ -101,8 +101,8 @@ GtkTextBuffer *ctk_config_create_help (GtkTextTagTable *); void ctk_config_add_timer(CtkConfig *, guint, gchar *, GSourceFunc, gpointer); void ctk_config_remove_timer(CtkConfig *, GSourceFunc); -void ctk_config_start_timer(CtkConfig *, GSourceFunc); -void ctk_config_stop_timer(CtkConfig *, GSourceFunc); +void ctk_config_start_timer(CtkConfig *, GSourceFunc, gpointer); +void ctk_config_stop_timer(CtkConfig *, GSourceFunc, gpointer); gboolean ctk_config_slider_text_entry_shown(CtkConfig *); diff --git a/src/gtk+-2.x/ctkcursorshadow.c b/src/gtk+-2.x/ctkcursorshadow.c index 2da653e..9d91bd4 100644 --- a/src/gtk+-2.x/ctkcursorshadow.c +++ b/src/gtk+-2.x/ctkcursorshadow.c @@ -849,13 +849,10 @@ static void init_color_selector(CtkCursorShadow *ctk_cursor_shadow) GtkWidget *window; GtkWidget *vbox; GtkWidget *hbox; - GtkWidget *frame; - GtkWidget *image; + GtkWidget *banner; GtkWidget *hseparator; GtkWidget *button; GtkWidget *alignment; - const nv_image_t *img; - guint8 *image_buffer = NULL; guint ret; /* create the color selector window */ @@ -866,7 +863,7 @@ static void init_color_selector(CtkCursorShadow *ctk_cursor_shadow) /* create a vbox to pack all the window contents in */ - vbox = gtk_vbox_new(FALSE, 5); + vbox = gtk_vbox_new(FALSE, 10); gtk_container_add(GTK_CONTAINER(window), vbox); /* add a banner */ @@ -874,22 +871,8 @@ static void init_color_selector(CtkCursorShadow *ctk_cursor_shadow) hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - - img = &cursor_banner_image; - - image_buffer = decompress_image_data(img); - - image = gtk_image_new_from_pixbuf - (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, img->width, img->height, - img->width * img->bytes_per_pixel, - free_decompressed_image, NULL)); - - gtk_container_add(GTK_CONTAINER(frame), image); + banner = ctk_banner_image_new(&cursor_banner_image); + gtk_box_pack_start(GTK_BOX(hbox), banner, TRUE, TRUE, 0); /* create the color selector */ diff --git a/src/gtk+-2.x/ctkdevice.c b/src/gtk+-2.x/ctkdevice.c deleted file mode 100644 index d64e888..0000000 --- a/src/gtk+-2.x/ctkdevice.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix - * and Linux systems. - * - * Copyright (C) 2004 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of Version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 - * of the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307, USA - * - */ - -#include <gtk/gtk.h> -#include "NvCtrlAttributes.h" - -#include <stdio.h> - -#include "big_banner_penguin.h" -#include "big_banner_bsd.h" -#include "big_banner_sun.h" - -#include "image.h" - -#include "ctkdevice.h" -#include "ctkhelp.h" -#include "ctkutils.h" -#define N_GDK_PIXBUFS 45 - - -GType ctk_device_get_type( - void -) -{ - static GType ctk_device_type = 0; - - if (!ctk_device_type) { - static const GTypeInfo info_ctk_device = { - sizeof (CtkDeviceClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (CtkDevice), - 0, /* n_preallocs */ - NULL, /* instance_init */ - }; - - ctk_device_type = - g_type_register_static(GTK_TYPE_VBOX, - "CtkDevice", &info_ctk_device, 0); - } - - return ctk_device_type; -} - - - -GtkWidget* ctk_device_new( - NvCtrlAttributeHandle *handle -) -{ - GObject *object; - CtkDevice *ctk_device; - GtkWidget *label; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *frame; - GtkWidget *image; - GtkWidget *hseparator; - GtkWidget *table; - GtkWidget *alignment; - - guint8 *image_buffer = NULL; - const nv_image_t *img; - - char *product_name, *bus_type, *vbios_version, *video_ram, *irq; - char *os, *arch, *version, *bus_rate, *bus; - ReturnStatus ret; - gint tmp, os_val; - - gchar *__unknown = "Unknown"; - - /* - * get the data that we will display below - * - * XXX should be able to update any of this if an attribute - * changes. - */ - - /* NV_CTRL_STRING_PRODUCT_NAME */ - - ret = NvCtrlGetStringAttribute(handle, NV_CTRL_STRING_PRODUCT_NAME, - &product_name); - if (ret != NvCtrlSuccess) product_name = "Unknown GPU"; - - /* NV_CTRL_BUS_TYPE */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_BUS_TYPE, &tmp); - bus_type = NULL; - if (ret == NvCtrlSuccess) { - if (tmp == NV_CTRL_BUS_TYPE_AGP) bus_type = "AGP"; - if (tmp == NV_CTRL_BUS_TYPE_PCI) bus_type = "PCI"; - if (tmp == NV_CTRL_BUS_TYPE_PCI_EXPRESS) bus_type = "PCI Express"; - if (tmp == NV_CTRL_BUS_TYPE_INTEGRATED) bus_type = "Integrated"; - } - if (!bus_type) bus_type = __unknown; - - /* NV_CTRL_BUS_RATE */ - - bus_rate = NULL; - if (tmp == NV_CTRL_BUS_TYPE_AGP || - tmp == NV_CTRL_BUS_TYPE_PCI_EXPRESS) { - ret = NvCtrlGetAttribute(handle, NV_CTRL_BUS_RATE, &tmp); - if (ret == NvCtrlSuccess) { - bus_rate = g_strdup_printf("%dX", tmp); - } - } - - if (bus_rate != NULL) { - bus = g_strdup_printf("%s %s", bus_type, bus_rate); - g_free(bus_rate); - } else { - bus = g_strdup(bus_type); - } - - /* NV_CTRL_STRING_VBIOS_VERSION */ - - ret = NvCtrlGetStringAttribute(handle, NV_CTRL_STRING_VBIOS_VERSION, - &vbios_version); - if (ret != NvCtrlSuccess) vbios_version = __unknown; - - /* NV_CTRL_VIDEO_RAM */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_VIDEO_RAM, &tmp); - if (ret != NvCtrlSuccess) tmp = 0; - video_ram = g_strdup_printf("%d MB", tmp >> 10); - - /* NV_CTRL_IRQ */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_IRQ, &tmp); - if (ret != NvCtrlSuccess) tmp = 0; - irq = g_strdup_printf("%d", tmp); - - /* NV_CTRL_OPERATING_SYSTEM */ - - os_val = NV_CTRL_OPERATING_SYSTEM_LINUX; - ret = NvCtrlGetAttribute(handle, NV_CTRL_OPERATING_SYSTEM, &os_val); - os = NULL; - if (ret == NvCtrlSuccess) { - if (os_val == NV_CTRL_OPERATING_SYSTEM_LINUX) os = "Linux"; - else if (os_val == NV_CTRL_OPERATING_SYSTEM_FREEBSD) os = "FreeBSD"; - else if (os_val == NV_CTRL_OPERATING_SYSTEM_SUNOS) os = "SunOS"; - } - if (!os) os = __unknown; - - /* NV_CTRL_ARCHITECTURE */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_ARCHITECTURE, &tmp); - arch = NULL; - if (ret == NvCtrlSuccess) { - if (tmp == NV_CTRL_ARCHITECTURE_X86) arch = "x86"; - if (tmp == NV_CTRL_ARCHITECTURE_X86_64) arch = "x86_64"; - if (tmp == NV_CTRL_ARCHITECTURE_IA64) arch = "ia64"; - } - if (!arch) arch = __unknown; - os = g_strdup_printf("%s-%s", os, arch); - - /* NV_CTRL_STRING_NVIDIA_DRIVER_VERSION */ - - ret = NvCtrlGetStringAttribute(handle, - NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, - &version); - if (ret != NvCtrlSuccess) version = __unknown; - - - - /* now, create the object */ - - object = g_object_new(CTK_TYPE_DEVICE, NULL); - ctk_device = CTK_DEVICE(object); - - /* cache the attribute handle */ - - ctk_device->handle = handle; - - /* set container properties of the object */ - - gtk_box_set_spacing(GTK_BOX(ctk_device), 10); - - /* banner */ - - alignment = gtk_alignment_new(0, 0, 0, 0); - gtk_box_pack_start(GTK_BOX(ctk_device), alignment, FALSE, FALSE, 0); - - frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(alignment), frame); - - if (os_val == NV_CTRL_OPERATING_SYSTEM_LINUX) { - img = &big_banner_penguin_image; - } else if (os_val == NV_CTRL_OPERATING_SYSTEM_FREEBSD) { - img = &big_banner_bsd_image; - } else if (os_val == NV_CTRL_OPERATING_SYSTEM_SUNOS) { - img = &big_banner_sun_image; - } else { - img = &big_banner_penguin_image; /* Should never get here */ - } - - image_buffer = decompress_image_data(img); - - image = gtk_image_new_from_pixbuf - (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, img->width, img->height, - img->width * img->bytes_per_pixel, - free_decompressed_image, NULL)); - - gtk_container_add(GTK_CONTAINER(frame), image); - - /* - * Device information: TOP->MIDDLE - LEFT->RIGHT - * - * This displays basic display adatper information, including - * product name, bios version, bus type, video ram and interrupt - * line. - */ - - vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(ctk_device), vbox, TRUE, TRUE, 0); - - hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new("Graphics Card Information"); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - hseparator = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); - - table = gtk_table_new(7, 2, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); - - gtk_table_set_row_spacings(GTK_TABLE(table), 3); - gtk_table_set_col_spacings(GTK_TABLE(table), 15); - - gtk_container_set_border_width(GTK_CONTAINER(table), 5); - - - add_table_row(table, 0, 0, "Graphics Processor:", product_name); - add_table_row(table, 1, 0, "Bus Type:", bus); - add_table_row(table, 2, 0, "VBIOS Version:", vbios_version); - add_table_row(table, 3, 0, "Video Memory:", video_ram); - add_table_row(table, 4, 0, "IRQ:", irq); - add_table_row(table, 5, 0, "Operating System:", os); - add_table_row(table, 6, 0, "NVIDIA Driver Version:", version); - - g_free(bus); - g_free(video_ram); - g_free(irq); - g_free(os); - - gtk_widget_show_all(GTK_WIDGET(object)); - - return GTK_WIDGET(object); -} - - -GtkTextBuffer *ctk_device_create_help(GtkTextTagTable *table, - const gchar *screen_name) -{ - GtkTextIter i; - GtkTextBuffer *b; - - b = gtk_text_buffer_new(table); - - gtk_text_buffer_get_iter_at_offset(b, &i, 0); - - ctk_help_title(b, &i, "Graphics Card Information Help"); - - ctk_help_para(b, &i, "This page in the NVIDIA " - "X Server Control Panel describes basic " - "information about the Graphics Processing Unit " - "(GPU) on which the X screen '%s' is running.", - screen_name); - - ctk_help_heading(b, &i, "Graphics Processor"); - ctk_help_para(b, &i, "This is the product name of the GPU."); - - ctk_help_heading(b, &i, "Bus Type"); - ctk_help_para(b, &i, "This is the bus type which is " - "used to connect the NVIDIA GPU to the rest of " - "your computer; possible values are AGP, PCI, " - "PCI Express and Integrated."); - - ctk_help_heading(b, &i, "VBIOS Version"); - ctk_help_para(b, &i, "This is the Video BIOS version."); - - - ctk_help_heading(b, &i, "Video Memory"); - ctk_help_para(b, &i, "This is the amount of video memory on your " - "graphics card."); - - ctk_help_heading(b, &i, "IRQ"); - ctk_help_para(b, &i, "This is the interrupt request line assigned to " - "this GPU."); - - ctk_help_heading(b, &i, "Operating System"); - ctk_help_para(b, &i, "This is the operating system on which the NVIDIA " - "X driver is running; possible values are " - "'Linux' and 'FreeBSD'. This also specifies the platform " - "on which the operating system is running, such as x86, " - "x86_64, or ia64"); - - ctk_help_heading(b, &i, "NVIDIA Driver Version"); - ctk_help_para(b, &i, "This is the version of the NVIDIA Accelerated " - "Graphics Driver currently in use."); - - ctk_help_finish(b); - - return b; -} diff --git a/src/gtk+-2.x/ctkdisplayconfig.c b/src/gtk+-2.x/ctkdisplayconfig.c new file mode 100644 index 0000000..cc53c86 --- /dev/null +++ b/src/gtk+-2.x/ctkdisplayconfig.c @@ -0,0 +1,9131 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <stdlib.h> /* malloc */ +#include <unistd.h> /* lseek, close */ +#include <string.h> /* strlen, strdup */ +#include <errno.h> + +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <NvCtrlAttributes.h> + +#include <X11/Xlib.h> +#include <X11/Xproto.h> + +#include "msg.h" + +#include "blank_banner.h" + +#include "ctkimage.h" +#include "ctkevent.h" +#include "ctkhelp.h" +#include "ctkdisplayconfig.h" +#include "ctkdisplaylayout.h" + + +void layout_selected_callback(nvLayoutPtr layout, void *data); +void layout_modified_callback(nvLayoutPtr layout, void *data); + +static void setup_layout_frame(CtkDisplayConfig *ctk_object); + +static void setup_display_frame(CtkDisplayConfig *ctk_object); + +static void display_config_clicked(GtkWidget *widget, gpointer user_data); + +static void display_resolution_changed(GtkWidget *widget, gpointer user_data); +static void display_refresh_changed(GtkWidget *widget, gpointer user_data); + +static void display_position_type_changed(GtkWidget *widget, gpointer user_data); +static void display_position_offset_activate(GtkWidget *widget, gpointer user_data); +static void display_position_relative_changed(GtkWidget *widget, gpointer user_data); + +static void display_panning_activate(GtkWidget *widget, gpointer user_data); + +static void setup_screen_frame(CtkDisplayConfig *ctk_object); + +static void screen_depth_changed(GtkWidget *widget, gpointer user_data); + +static void screen_position_type_changed(GtkWidget *widget, gpointer user_data); +static void screen_position_offset_activate(GtkWidget *widget, gpointer user_data); +static void screen_position_relative_changed(GtkWidget *widget, gpointer user_data); + +static void screen_metamode_clicked(GtkWidget *widget, gpointer user_data); +static void screen_metamode_activate(GtkWidget *widget, gpointer user_data); +static void screen_metamode_add_clicked(GtkWidget *widget, gpointer user_data); +static void screen_metamode_delete_clicked(GtkWidget *widget, gpointer user_data); + +static void xconfig_preview_clicked(GtkWidget *widget, gpointer user_data); +static void xconfig_file_clicked(GtkWidget *widget, gpointer user_data); + +static void xinerama_state_toggled(GtkWidget *widget, gpointer user_data); +static void apply_clicked(GtkWidget *widget, gpointer user_data); +static void save_clicked(GtkWidget *widget, gpointer user_data); +static void probe_clicked(GtkWidget *widget, gpointer user_data); +static void advanced_clicked(GtkWidget *widget, gpointer user_data); +static void reset_clicked(GtkWidget *widget, gpointer user_data); +static void validation_details_clicked(GtkWidget *widget, gpointer user_data); + + + + +/*** D E F I N I T I O N S ***************************************************/ + + +#define DEFAULT_SWITCH_MODE_TIMEOUT 15 /* When switching modes, this is the + * number of seconds the user has to + * accept the new mode before we switch + * back to the original mode. + */ + +#define TAB " " +#define BIGTAB " " + +#define GTK_RESPONSE_USER_DISPLAY_ENABLE_TWINVIEW 1 +#define GTK_RESPONSE_USER_DISPLAY_ENABLE_XSCREEN 2 + +typedef void (* apply_token_func)(char *token, char *value, + void *data); + +typedef struct SwitchModeCallbackInfoRec { + CtkDisplayConfig *ctk_object; + int screen; +} SwitchModeCallbackInfo; + + + + +/*** G L O B A L S ***********************************************************/ + +static int __position_table[] = { CONF_ADJ_ABSOLUTE, + CONF_ADJ_RIGHTOF, + CONF_ADJ_LEFTOF, + CONF_ADJ_ABOVE, + CONF_ADJ_BELOW, + CONF_ADJ_RELATIVE }; + + +/* Layout tooltips */ + +static const char * __layout_xinerama_button_help = +"The Enable Xinerama checkbox enables the Xinerama X extension; Changing " +"this option will require restarting your X server."; + + +/* Display tooltips */ + +static const char * __dpy_resolution_mnu_help = +"The Resolution drop-down allows you to select a desired resolution " +"for the currently selected display device."; + +static const char * __dpy_refresh_mnu_help = +"The Refresh drop-down allows you to select a desired refresh rate " +"for the currently selected display device. Note that the selected " +"resolution may restrict the available refresh rates."; + +static const char * __dpy_position_type_help = +"The Position Type drop-down allows you to set how the selected display " +"device is placed within the X Screen."; + +static const char * __dpy_position_relative_help = +"The Position Relative drop-down allows you to set which other display " +"device (within the X Screen) the selected display device should be " +"relative to."; + +static const char * __dpy_position_offset_help = +"The Position Offset identifies the top left of the display device " +"as an offset from the top left of the X Screen position."; + +static const char * __dpy_panning_help = +"The Panning Domain sets the total width/height that the display " +"device may pan within."; + + +/* Screen tooltips */ + +static const char * __screen_depth_help = +"The Depth drop-down allows setting of the color quality for the selected " +"screen; Changing this option will require restarting your X server."; + +static const char * __screen_position_type_help = +"The Position Type drop-down allows you to set how the selected screen " +"is placed within the X Server layout; Changing this option will require " +"restarting your X server."; + +static const char * __screen_position_relative_help = +"The Position Relative drop-down allows you to set which other Screen " +"the selected screen should be relative to; Changing this option will " +"require restarting your X server."; + +static const char * __screen_position_offset_help = +"The Position Offset identifies the top left of the selected Screen as " +"an offset from the top left of the X Server layout in absolute coordinates; " +"Changing this option will require restarting your X server."; + +static const char * __screen_metamode_help = +"The MetaMode selection menu allows you to set the currently displayed " +"MetaMode for the selected screen; This option can be applied to " +"your currently running X server."; + +static const char * __screen_metamode_add_button_help = +"The Add MetaMode button allows you to create a new MetaMode for the " +"selected screen; This option can be applied to your currently " +"running X server."; + +static const char * __screen_metamode_delete_button_help = +"The Delete MetaMode button allows you to delete the currently selected " +"MetaMode for the screen; This option can be applied to your currently " +"running X server."; + + +/* General button tooltips */ + +static const char * __apply_button_help = +"The Apply button allows you to apply changes made to the server layout."; + +static const char * __probe_button_help = +"The probe button allows you to probe for new display devices that may " +"have been hotplugged."; + +static const char * __advanced_button_help = +"The Advanced/Basic button toggles between a basic view, and an advanced view " +"with extra configuration options."; + +static const char * __reset_button_help = +"The Reset button will re-probe the X Server for current configuration. Any " +"alterations you may have made (and not applied) will be lost."; + +static const char * __save_button_help = +"The Save to X Configuration File button allows you to save the current " +"X Server configuration settings to an X Configuration file."; + + + + +/*** F U N C T I O N S *******************************************************/ + + +/** get_display_type_str() ******************************************* + * + * Returns the type name of a display (CRT, CRT-1, DFP ..) + * + * If 'generic' is set to 1, then a generic version of the name is + * returned. + * + **/ + +static gchar *get_display_type_str(unsigned int device_mask, int be_generic) +{ + unsigned int bit = 0; + int num; + gchar *name = NULL; + gchar *type_name; + + + /* Get the generic type name of the display */ + if (device_mask & 0x000000FF) { + name = g_strdup("CRT"); + bit = (device_mask & 0x000000FF); + + } else if (device_mask & 0x0000FF00) { + name = g_strdup("TV"); + bit = (device_mask & 0x0000FF00) >> 8; + + } else if (device_mask & 0x00FF0000) { + name = g_strdup("DFP"); + bit = (device_mask & 0x00FF0000) >> 16; + } + + if (be_generic || !name) { + return name; + } + + + /* Add the specific display number to the name */ + num = 0; + while (bit) { + num++; + bit >>= 1; + } + if (num) { + num--; + } + + type_name = g_strdup_printf("%s-%d", name, num); + g_free(name); + + return type_name; + +} /* get_display_type_str() */ + + + +/** get_mode_str() *************************************************** + * + * Returns the mode string of a mode: + * + * "mode_name @WxH +X+Y" + * + **/ + +static gchar * get_mode_str(nvModePtr mode, int be_generic) +{ + gchar *mode_str; + gchar *tmp; + + + /* Make sure the mode has everything it needs to be displayed */ + if (!mode || !mode->display || !mode->display->gpu || !mode->metamode) { + return NULL; + } + + + /* Don't display dummy modes */ + if (be_generic && mode->dummy && !mode->modeline) { + return NULL; + } + + + /* Only one display, be very generic (no 'CRT:' in metamode) */ + if (be_generic && mode->display->gpu->num_displays == 1) { + mode_str = g_strdup(""); + + /* If there's more than one CRT/DFP/TV, we can't be generic. */ + } else { + int generic = be_generic; + + if ((mode->display->device_mask & 0x000000FF) && + (mode->display->device_mask != + (mode->display->gpu->connected_displays & 0x000000FF))) { + generic = 0; + } + if ((mode->display->device_mask & 0x0000FF00) && + (mode->display->device_mask != + (mode->display->gpu->connected_displays & 0x0000FF00))) { + generic = 0; + } + if ((mode->display->device_mask & 0x00FF0000) && + (mode->display->device_mask != + (mode->display->gpu->connected_displays & 0x00FF0000))) { + generic = 0; + } + + /* Get the display type */ + tmp = get_display_type_str(mode->display->device_mask, generic); + mode_str = g_strconcat(tmp, ": ", NULL); + g_free(tmp); + } + + + /* NULL mode */ + if (!mode->modeline) { + tmp = g_strconcat(mode_str, "NULL", NULL); + g_free(mode_str); + return tmp; + } + + + /* Mode name */ + tmp = g_strconcat(mode_str, mode->modeline->data.identifier, NULL); + g_free(mode_str); + mode_str = tmp; + + + /* Panning domain */ + if (!be_generic || (mode->pan[W] != mode->dim[W] || + mode->pan[H] != mode->dim[H])) { + tmp = g_strdup_printf("%s @%dx%d", + mode_str, mode->pan[W], mode->pan[H]); + g_free(mode_str); + mode_str = tmp; + } + + + /* Offset */ + + /* + * XXX Later, we'll want to allow the user to select how + * the metamodes are generated: + * + * Programability: + * make mode->dim relative to screen->dim + * + * Coherency: + * make mode->dim relative to mode->metamode->edim + * + * + * XXX Also, we may want to take in consideration the + * TwinViewOrientation when writing out position + * information. + */ + + tmp = g_strdup_printf("%s +%d+%d", + mode_str, + /* Make mode position relative */ + mode->dim[X] - mode->metamode->edim[X], + mode->dim[Y] - mode->metamode->edim[Y]); + g_free(mode_str); + mode_str = tmp; + + + return mode_str; + +} /* get_mode_str() */ + + + +/** get_display_from_gpu() ******************************************* + * + * Returns the display with the matching device_mask + * + **/ + +static nvDisplayPtr get_display_from_gpu(nvGpuPtr gpu, + unsigned int device_mask) +{ + nvDisplayPtr display; + + for (display = gpu->displays; display; display = display->next) { + if (display->device_mask == device_mask) return display; + } + + return NULL; + +} /* get_display_from_gpu() */ + + + +/** get_cur_screen_pos() ********************************************* + * + * Grabs a copy of the currently selected screen position. + * + **/ + +static void get_cur_screen_pos(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!display || !display->screen) return; + + ctk_object->cur_screen_pos[X] = display->screen->dim[X]; + ctk_object->cur_screen_pos[Y] = display->screen->dim[Y]; + +} /* get_cur_screen_pos() */ + + + +/** check_screen_pos_changed() *************************************** + * + * Checks to see if the screen's position changed. If so this + * function sets the apply_possible flag to FALSE. + * + **/ + +static void check_screen_pos_changed(CtkDisplayConfig *ctk_object) +{ + int old_dim[2]; + + /* Cache the old position */ + old_dim[X] = ctk_object->cur_screen_pos[X]; + old_dim[Y] = ctk_object->cur_screen_pos[Y]; + + /* Get the new position */ + get_cur_screen_pos(ctk_object); + + if (old_dim[X] != ctk_object->cur_screen_pos[X] || + old_dim[Y] != ctk_object->cur_screen_pos[Y]) { + ctk_object->apply_possible = FALSE; + } + +} /* check_screen_pos_changed() */ + + +/** find_closest_mode_with_modeline() ******************************** + * + * Helper function that returns the mode index of the display's mode + * that best matches the given modeline. + * + * A best match is: + * + * - The modelines are the same. + * - The modelines match in width & height. + * + **/ + +static int find_closest_mode_with_modeline(nvDisplayPtr display, + nvModeLinePtr modeline) +{ + nvModePtr mode; + int mode_idx; + int match_idx = -1; + + mode_idx = 0; + for (mode = display->modes; mode; mode = mode->next) { + if (mode->modeline->data.vdisplay == modeline->data.vdisplay && + mode->modeline->data.hdisplay == modeline->data.hdisplay) { + match_idx = mode_idx; + } + if (mode->modeline == modeline) break; + mode_idx++; + } + + return match_idx; + +} /* find_closest_mode_with_modeline() */ + + + +/** Parsing Tools **************************************************** + * + * Some tools for parsing strings + * + */ + +static const char *skip_whitespace(const char *str) +{ + while (*str && + (*str == ' ' || *str == '\t' || + *str == '\n' || *str == '\r')) { + str++; + } + return str; +} + +static void chop_whitespace(char *str) +{ + char *tmp = str + strlen(str) -1; + + while (tmp >= str && + (*tmp == ' ' || *tmp == '\t' || + *tmp == '\n' || *tmp == '\r')) { + *tmp = '\0'; + tmp++; + } +} + +static const char *skip_integer(const char *str) +{ + if (*str == '-' || *str == '+') { + str++; + } + while (*str && *str >= '0' && *str <= '9') { + str++; + } + return str; +} + +static const char *read_integer(const char *str, int *num) +{ + str = skip_whitespace(str); + *num = atoi(str); + str = skip_integer(str); + return skip_whitespace(str); +} + +static const char *read_pair(const char *str, char separator, int *a, int *b) +{ + str = read_integer(str, a); + if (!str) return NULL; + if (separator) { + if (*str != separator) return NULL; + str++; + } + return read_integer(str, b); +} + +static const char *read_name(const char *str, char **name, char term) +{ + const char *tmp; + + str = skip_whitespace(str); + tmp = str; + while (*str && *str != term) { + str++; + } + *name = (char *)calloc(1, str -tmp +1); + if (!(*name)) { + return NULL; + } + strncpy(*name, tmp, str -tmp); + if (*str == term) { + str++; + } + return skip_whitespace(str); +} + +/* Convert 'CRT-1' display device type names into a device_mask + * '0x00000002' bitmask + */ +static const char *read_display_name(const char *str, unsigned int *bit) +{ + if (!str || !bit) { + return NULL; + } + + str = skip_whitespace(str); + if (!strncmp(str, "CRT-", 4)) { + *bit = 1 << (atoi(str+4)); + + } else if (!strncmp(str, "TV-", 3)) { + *bit = (1 << (atoi(str+3))) << 8; + + } else if (!strncmp(str, "DFP-", 4)) { + *bit = (1 << (atoi(str+4))) << 16; + + } else { + return NULL; + } + + while (*str && *str != ':') { + str++; + } + if (*str == ':') { + str++; + } + + return skip_whitespace(str); +} + +static int read_float_range(char *str, float *min, float *max) +{ + if (!str) return 0; + + str = (char *)skip_whitespace(str); + *min = atof(str); + str = strstr(str, "-"); + if (!str) return 0; + str++; + *max = atof(str); + + return 1; +} + + + +/** apply_modeline_token() ******************************************* + * + * Modifies the modeline structure given with the token/value pair + * given. + * + **/ + +static void apply_modeline_token(char *token, char *value, void *data) +{ + nvModeLinePtr modeline = (nvModeLinePtr) data; + + if (!modeline || !token || !strlen(token)) { + return; + } + + /* Modeline Source */ + if (!strcasecmp("source", token)) { + if (!value || !strlen(value)) { + nv_warning_msg("Modeline 'source' token requires a value!"); + } else if (!strcasecmp("xserver", value)) { + modeline->source |= MODELINE_SOURCE_XSERVER; + } else if (!strcasecmp("xconfig", value)) { + modeline->source |= MODELINE_SOURCE_XCONFIG; + } else if (!strcasecmp("builtin", value)) { + modeline->source |= MODELINE_SOURCE_BUILTIN; + } else if (!strcasecmp("vesa", value)) { + modeline->source |= MODELINE_SOURCE_VESA; + } else if (!strcasecmp("edid", value)) { + modeline->source |= MODELINE_SOURCE_EDID; + } else if (!strcasecmp("nv-control", value)) { + modeline->source |= MODELINE_SOURCE_NVCONTROL; + } else { + nv_warning_msg("Unknown modeline source '%s'", value); + } + + /* X Config name */ + } else if (!strcasecmp("xconfig-name", token)) { + if (!value || !strlen(value)) { + nv_warning_msg("Modeline 'xconfig-name' token requires a value!"); + } else { + if (modeline->xconfig_name) { + free(modeline->xconfig_name); + } + modeline->xconfig_name = g_strdup(value); + } + + /* Unknown token */ + } else { + nv_warning_msg("Unknown modeline token value pair: %s=%s", + token, value); + } + +} /* apply_modeline_token() */ + + + +/** apply_metamode_token() ******************************************* + * + * Modifies the metamode structure given with the token/value pair + * given. + * + **/ + +static void apply_metamode_token(char *token, char *value, void *data) +{ + nvMetaModePtr metamode = (nvMetaModePtr) data; + + if (!metamode || !token || !strlen(token)) { + return; + } + + /* Metamode ID */ + if (!strcasecmp("id", token)) { + if (!value || !strlen(value)) { + nv_warning_msg("MetaMode 'id' token requires a value!"); + } else { + metamode->id = atoi(value); + } + + /* Modeline Source */ + } else if (!strcasecmp("source", token)) { + if (!value || !strlen(value)) { + nv_warning_msg("MetaMode 'source' token requires a value!"); + } else if (!strcasecmp("xconfig", value)) { + metamode->source |= METAMODE_SOURCE_XCONFIG; + } else if (!strcasecmp("implicit", value)) { + metamode->source |= METAMODE_SOURCE_IMPLICIT; + } else if (!strcasecmp("nv-control", value)) { + metamode->source |= METAMODE_SOURCE_NVCONTROL; + } else { + nv_warning_msg("Unknown MetaMode source '%s'", value); + } + + /* Switchable */ + } else if (!strcasecmp("switchable", token)) { + if (!value || !strlen(value)) { + nv_warning_msg("MetaMode 'switchable' token requires a value!"); + } else { + if (!strcasecmp(value, "yes")) { + metamode->switchable = TRUE; + } else { + metamode->switchable = FALSE; + } + } + + /* Unknown token */ + } else { + nv_warning_msg("Unknown MetaMode token value pair: %s=%s", + token, value); + } + +} /* apply_metamode_token */ + + + +/** apply_monitor_token() ******************************************** + * + * Returns the source string of a refresh/sync range. + * + **/ + +static void apply_monitor_token(char *token, char *value, void *data) +{ + char **source = (char **)data; + + if (!source || !token || !strlen(token)) { + return; + } + + /* Metamode ID */ + if (!strcasecmp("source", token)) { + if (*source) free(*source); + *source = strdup(value); + + /* Unknown token */ + } else { + nv_warning_msg("Unknown monitor range token value pair: %s=%s", + token, value); + } + +} /* apply_monitor_token() */ + + + +/** apply_screen_info_token() **************************************** + * + * Modifies the ScreenInfo structure (pointed to by data) with + * information from the token-value pair given. Currently accepts + * position and width/height data. + * + **/ + +typedef struct _ScreenInfo { + int x; + int y; + int width; + int height; +} ScreenInfo; + +static void apply_screen_info_token(char *token, char *value, void *data) +{ + ScreenInfo *screen_info = (ScreenInfo *)data; + + if (!screen_info || !token || !strlen(token)) { + return; + } + + /* X */ + if (!strcasecmp("x", token)) { + screen_info->x = atoi(value); + + /* Y */ + } else if (!strcasecmp("y", token)) { + screen_info->y = atoi(value); + + /* Width */ + } else if (!strcasecmp("width", token)) { + screen_info->width = atoi(value); + + /* Height */ + } else if (!strcasecmp("height", token)) { + screen_info->height = atoi(value); + + /* Unknown token */ + } else { + nv_warning_msg("Unknown screen info token value pair: %s=%s", + token, value); + } + +} /* apply_screen_info_token() */ + + + +/** parse_tokens() *************************************************** + * + * Parses the given tring for "token=value, token=value, ..." pairs + * and dispatches the handeling of tokens to the given function with + * the given data as an extra argument. + * + **/ + +static Bool parse_tokens(const char *str, apply_token_func func, void *data) +{ + char *token; + char *value; + + + if (str) { + + /* Parse each token */ + while (*str) { + + /* Read the token */ + str = read_name(str, &token, '='); + if (!str) return FALSE; + + /* Read the value */ + str = read_name(str, &value, ','); + if (!str) return FALSE; + + /* Remove trailing whitespace */ + chop_whitespace(token); + chop_whitespace(value); + + func(token, value, data); + + free(token); + free(value); + } + } + + return TRUE; + +} /* parse_tokens() */ + + + +/** parse_modeline() ************************************************* + * + * Converts a modeline string to an X config modeline structure that + * the XF86Parser backend can read. + * + * + * Modeline strings have this format: + * + * "mode_name" dot_clock timings flags + * + **/ + +nvModeLinePtr parse_modeline(const char *modeline_str) +{ + nvModeLinePtr modeline = NULL; + const char *str = modeline_str; + char *tmp; + char *tokens; + + + if (!str) return NULL; + + modeline = (nvModeLinePtr)calloc(1, sizeof(nvModeLine)); + if (!modeline) return NULL; + + /* Parse the modeline tokens */ + tmp = strstr(str, "::"); + if (tmp) { + tokens = strdup(str); + tokens[ tmp-str ] = '\0'; + str = tmp +2; + parse_tokens(tokens, apply_modeline_token, (void *)modeline); + free(tokens); + } + + /* Read the mode name */ + str = skip_whitespace(str); + if (!str || *str != '"') goto fail; + str++; + str = read_name(str, &(modeline->data.identifier), '"'); + if (!str) goto fail; + + /* Read dot clock */ + { + int digits = 100; + + str = read_integer(str, &(modeline->data.clock)); + modeline->data.clock *= 1000; + if (*str == '.') { + str++; + while (digits && + *str && + *str != ' ' && *str != '\t' && + *str != '\n' && *str != '\r') { + + modeline->data.clock += digits * (*str - '0'); + digits /= 10; + str++; + } + } + str = skip_whitespace(str); + } + + str = read_integer(str, &(modeline->data.hdisplay)); + str = read_integer(str, &(modeline->data.hsyncstart)); + str = read_integer(str, &(modeline->data.hsyncend)); + str = read_integer(str, &(modeline->data.htotal)); + str = read_integer(str, &(modeline->data.vdisplay)); + str = read_integer(str, &(modeline->data.vsyncstart)); + str = read_integer(str, &(modeline->data.vsyncend)); + str = read_integer(str, &(modeline->data.vtotal)); + + + /* Parse modeline flags */ + while ((str = read_name(str, &tmp, ' ')) && strlen(tmp)) { + + if (!xconfigNameCompare(tmp, "+hsync")) { + modeline->data.flags |= XCONFIG_MODE_PHSYNC; + } + else if (!xconfigNameCompare(tmp, "-hsync")) { + modeline->data.flags |= XCONFIG_MODE_NHSYNC; + } + else if (!xconfigNameCompare(tmp, "+vsync")) { + modeline->data.flags |= XCONFIG_MODE_PVSYNC; + } + else if (!xconfigNameCompare(tmp, "-vsync")) { + modeline->data.flags |= XCONFIG_MODE_NVSYNC; + } + else if (!xconfigNameCompare(tmp, "interlace")) { + modeline->data.flags |= XCONFIG_MODE_INTERLACE; + } + else if (!xconfigNameCompare(tmp, "doublescan")) { + modeline->data.flags |= XCONFIG_MODE_DBLSCAN; + } + else if (!xconfigNameCompare(tmp, "composite")) { + modeline->data.flags |= XCONFIG_MODE_CSYNC; + } + else if (!xconfigNameCompare(tmp, "+csync")) { + modeline->data.flags |= XCONFIG_MODE_PCSYNC; + } + else if (!xconfigNameCompare(tmp, "-csync")) { + modeline->data.flags |= XCONFIG_MODE_NCSYNC; + } + else if (!xconfigNameCompare(tmp, "hskew")) { + str = read_integer(str, &(modeline->data.hskew)); + if (!str) { + free(tmp); + goto fail; + } + modeline->data.flags |= XCONFIG_MODE_HSKEW; + } + else if (!xconfigNameCompare(tmp, "bcast")) { + modeline->data.flags |= XCONFIG_MODE_BCAST; + } + else if (!xconfigNameCompare(tmp, "CUSTOM")) { + modeline->data.flags |= XCONFIG_MODE_CUSTOM; + } + else if (!xconfigNameCompare(tmp, "vscan")) { + str = read_integer(str, &(modeline->data.vscan)); + if (!str) { + free(tmp); + goto fail; + } + modeline->data.flags |= XCONFIG_MODE_VSCAN; + } + else { + nv_warning_msg("Invalid modeline keyword '%s' in modeline '%s'", + tmp, modeline_str); + goto fail; + } + free(tmp); + } + + return modeline; + + + /* Handle failures */ + fail: + free(modeline); + return NULL; + +} /* parse_modeline() */ + + + +/** parse_mode() ***************************************************** + * + * Makes a mode structure from the mode string given. + * + * + * Currently supported mode syntax: + * + * "mode_name" +X+Y @WxH + * + **/ + +nvModePtr parse_mode(nvDisplayPtr display, const char *mode_str) +{ + nvModePtr mode; + char *mode_name; /* Modeline reference name */ + const char *str = mode_str; + + + + if (!str || !display || !display->modelines) return NULL; + + + /* Allocate a Mode structure */ + mode = (nvModePtr)calloc(1, sizeof(nvMode)); + if (!mode) return NULL; + + mode->display = display; + + + /* Read the mode name */ + str = read_name(str, &mode_name, ' '); + if (!str || !mode_name) goto fail; + + + /* Match the mode name to one of the modelines */ + mode->modeline = display->modelines; + while (mode->modeline) { + if (!strcmp(mode_name, mode->modeline->data.identifier)) { + break; + } + mode->modeline = mode->modeline->next; + } + free(mode_name); + + + /* If we can't find a matching modeline, show device as off + * using the width & height of whatever the first modeline is. + * XXX Hopefully this is the default width/height. + */ + if (!mode->modeline) { + if (strcmp(mode_str, "NULL")) { + nv_warning_msg("Mode name '%s' does not match any modelines for " + "display device '%s' in modeline '%s'.", + mode_name, display->name, mode_str); + } + mode->dim[W] = display->modelines->data.hdisplay; + mode->dim[H] = display->modelines->data.vdisplay; + mode->pan[W] = mode->dim[W]; + mode->pan[H] = mode->dim[H]; + return mode; + } + + + /* Setup default size and panning of display */ + mode->dim[W] = mode->modeline->data.hdisplay; + mode->dim[H] = mode->modeline->data.vdisplay; + mode->pan[W] = mode->dim[W]; + mode->pan[H] = mode->dim[H]; + + + /* Read mode information */ + while (*str) { + + /* Read panning */ + if (*str == '@') { + str++; + str = read_pair(str, 'x', + &(mode->pan[W]), &(mode->pan[H])); + } + + /* Read position */ + else if (*str == '+') { + str++; + str = read_pair(str, 0, + &(mode->dim[X]), &(mode->dim[Y])); + } + + /* Mode parse error - Ack! */ + else { + str = NULL; + } + + /* Catch errors */ + if (!str) goto fail; + } + + + /* These are the same for now */ + mode->pan[X] = mode->dim[X]; + mode->pan[Y] = mode->dim[Y]; + + + /* Panning can't be smaller than dimensions */ + if (mode->pan[W] < mode->dim[W]) { + mode->pan[W] = mode->dim[W]; + } + if (mode->pan[W] < mode->dim[W]) { + mode->pan[W] = mode->dim[W]; + } + + return mode; + + + /* Handle failures */ + fail: + if (mode) { + free(mode); + } + + return NULL; + +} /* parse_mode() */ + + + +/** xconfigPrint() ****************************************************** + * + * xconfigPrint() - this is the one entry point that a user of the + * XF86Config-Parser library must provide. + * + **/ + +void xconfigPrint(MsgType t, const char *msg) +{ + typedef struct { + MsgType msg_type; + char *prefix; + FILE *stream; + int newline; + } MessageTypeAttributes; + + char *prefix = NULL; + int i, newline = FALSE; + FILE *stream = stdout; + + const MessageTypeAttributes msg_types[] = { + { ParseErrorMsg, "PARSE ERROR: ", stderr, TRUE }, + { ParseWarningMsg, "PARSE WARNING: ", stderr, TRUE }, + { ValidationErrorMsg, "VALIDATION ERROR: ", stderr, TRUE }, + { InternalErrorMsg, "INTERNAL ERROR: ", stderr, TRUE }, + { WriteErrorMsg, "ERROR: ", stderr, TRUE }, + { WarnMsg, "WARNING: ", stderr, TRUE }, + { ErrorMsg, "ERROR: ", stderr, TRUE }, + { DebugMsg, "DEBUG: ", stdout, FALSE }, + { UnknownMsg, NULL, stdout, FALSE }, + }; + + for (i = 0; msg_types[i].msg_type != UnknownMsg; i++) { + if (msg_types[i].msg_type == t) { + prefix = msg_types[i].prefix; + newline = msg_types[i].newline; + stream = msg_types[i].stream; + break; + } + } + + if (newline) printf("\n"); + printf("%s %s\n", prefix, msg); + if (newline) printf("\n"); + +} /* xconfigPrint */ + + + +/* Layout save/write functions ***************************************/ + + +/** get_display_mode_str() ******************************************* + * + * Returns the mode string of the display's 'mode_idx''s + * mode. + * + **/ +static gchar *get_display_mode_str(nvDisplayPtr display, int mode_idx, + int be_generic) +{ + nvModePtr mode = display->modes; + + while (mode && mode_idx) { + mode = mode->next; + mode_idx--; + } + + if (mode) { + return get_mode_str(mode, be_generic); + } + + return NULL; + +} /* get_display_mode_str() */ + + + +/** get_screen_metamode_str() **************************************** + * + * Returns a screen's metamode string for the given metamode index + * as: + * + * "mode1_1, mode1_2, mode1_3 ... " + * + **/ + +static gchar *get_screen_metamode_str(nvScreenPtr screen, int metamode_idx, + int be_generic) +{ + nvDisplayPtr display; + + gchar *metamode_str = NULL; + gchar *mode_str; + gchar *tmp; + + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; /* Display not in screen */ + + mode_str = get_display_mode_str(display, metamode_idx, be_generic); + if (!mode_str) continue; + + if (!metamode_str) { + metamode_str = mode_str; + } else { + tmp = g_strdup_printf("%s, %s", metamode_str, mode_str); + g_free(mode_str); + g_free(metamode_str); + metamode_str = tmp; + } + } + + return metamode_str; + +} /* get_screen_metamode_str() */ + + + +/** get_screen_metamode_strs() *************************************** + * + * Returns the metamode strings of a screen: + * + * "mode1_1, mode1_2, mode1_3 ... ; mode 2_1, mode 2_2, mode 2_3 ... ; ..." + * + **/ + +static gchar *get_screen_metamode_strs(nvScreenPtr screen, int be_generic, + int cur_mode_first) +{ + gchar *metamode_strs = NULL; + gchar *metamode_str; + gchar *tmp; + int metamode_idx; + nvMetaModePtr metamode; + + + /* The current mode should appear first in the list */ + if (cur_mode_first) { + metamode_strs = get_screen_metamode_str(screen, + screen->cur_metamode_idx, + be_generic); + } + + for (metamode_idx = 0, metamode = screen->metamodes; + (metamode_idx < screen->num_metamodes) && metamode; + metamode_idx++, metamode = metamode->next) { + + /* Only write out metamodes that were specified by the user */ + if (!(metamode->source & METAMODE_SOURCE_USER)) continue; + + /* The current mode was already included */ + if (cur_mode_first && (metamode_idx == screen->cur_metamode_idx)) + continue; + + metamode_str = get_screen_metamode_str(screen, metamode_idx, + be_generic); + if (!metamode_str) continue; + + if (!metamode_strs) { + metamode_strs = metamode_str; + } else { + tmp = g_strconcat(metamode_strs, "; ", metamode_str, NULL); + g_free(metamode_str); + g_free(metamode_strs); + metamode_strs = tmp; + } + } + + return metamode_strs; + +} /* get_screen_metamode_strs() */ + + + + +/* Metamode functions ************************************************/ + + +/** remove_modes_from_display() ************************************** + * + * Removes all modes currently referenced by this screen, also + * freeing any memory used. + * + **/ + +static void remove_modes_from_display(nvDisplayPtr display) +{ + nvModePtr mode; + + if (display) { + while (display->modes) { + mode = display->modes; + display->modes = mode->next; + free(mode); + } + display->num_modes = 0; + display->cur_mode = NULL; + } + +} /* remove_modes_from_display() */ + + + +/** add_metamode_to_screen() ***************************************** + * + * Parses a metamode string and adds the appropreate modes to the + * screen's display devices (at the end of the list) + * + */ + +static Bool add_metamode_to_screen(nvScreenPtr screen, char *metamode_str, + gchar **err_str) +{ + char *mode_str; + char *str = NULL; + char *tmp; + char *tokens; + nvMetaModePtr metamode; + + + if (!screen || !screen->gpu || !metamode_str) goto fail; + + + metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode)); + if (!metamode) goto fail; + + + /* Copy the string so we can split it up */ + str = strdup(metamode_str); + if (!str) goto fail; + + + /* Read the MetaMode ID */ + tmp = strstr(str, "::"); + if (tmp) { + tokens = strdup(str); + tokens[ tmp-str ] = '\0'; + tmp += 2; + parse_tokens(tokens, apply_metamode_token, (void *)metamode); + free(tokens); + } else { + /* No tokens? Try the old "ID: METAMODE_STR" syntax */ + tmp = (char *)read_integer(str, &(metamode->id)); + metamode->source = METAMODE_SOURCE_NVCONTROL; + if (*tmp == ':') { + tmp++; + } + } + + + /* Add the metamode at the end of the screen's metamode list */ + screen->metamodes = + (nvMetaModePtr)xconfigAddListItem((GenericListPtr)screen->metamodes, + (GenericListPtr)metamode); + + + /* Split up the metamode into separate modes */ + for (mode_str = strtok(tmp, ","); + mode_str; + mode_str = strtok(NULL, ",")) { + + nvModePtr mode; + unsigned int device_mask; + nvDisplayPtr display; + const char *orig_mode_str = skip_whitespace(mode_str); + + + /* Parse the display device bitmask from the name */ + mode_str = (char *)read_display_name(mode_str, &device_mask); + if (!mode_str) { + *err_str = g_strdup_printf("Failed to read a display device name " + "on screen %d (on GPU-%d)\nwhile " + "parsing metamode:\n\n'%s'", + screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle), + orig_mode_str); + nv_error_msg(*err_str); + goto fail; + } + + + /* Match device bitmask to an existing display */ + display = get_display_from_gpu(screen->gpu, device_mask); + if (!display) { + *err_str = g_strdup_printf("Failed to find display device 0x%08x " + "on screen %d (on GPU-%d)\nwhile " + "parsing metamode:\n\n'%s'", + device_mask, + screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle), + orig_mode_str); + nv_error_msg(*err_str); + goto fail; + } + + + /* Parse the mode */ + mode = parse_mode(display, mode_str); + if (!mode) { + *err_str = g_strdup_printf("Failed to parse mode '%s'\non " + "screen %d (on GPU-%d)\nfrom " + "metamode:\n\n'%s'", + mode_str, screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle), + orig_mode_str); + nv_error_msg(*err_str); + goto fail; + } + + + /* Make the mode part of the metamode */ + mode->metamode = metamode; + + + /* Make the display part of the screen */ + display->screen = screen; + + + /* Set the panning offset */ + mode->pan[X] = mode->dim[X]; + mode->pan[Y] = mode->dim[Y]; + + + /* Add the mode at the end of the display's mode list */ + display->modes = + (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes, + (GenericListPtr)mode); + display->num_modes++; + + } /* Done parsing a single metamode */ + + free(str); + return TRUE; + + + /* Failure case */ + fail: + + /* XXX We should probably track which modes were added and remove + * them at this point. For now, just assume the caller will + * remove all the modes and bail. + */ + + free(str); + return FALSE; + +} /* add_metamode_to_screen() */ + + + +/** check_screen_metamodes() ***************************************** + * + * Makes sure all displays associated with the screen have the right + * number of mode entries. + * + **/ + +static Bool check_screen_metamodes(nvScreenPtr screen) +{ + nvDisplayPtr display; + nvMetaModePtr metamode; + nvModePtr mode; + nvModePtr last_mode = NULL; + + + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + if (display->num_modes == screen->num_metamodes) continue; + + mode = display->modes; + metamode = screen->metamodes; + while (mode && metamode) { + mode = mode->next; + metamode = metamode->next; + if (mode) { + last_mode = mode; + } + } + + /* Each display must have as many modes as it's screen has metamodes */ + while (metamode) { + + /* Create a dumy mode */ + mode = parse_mode(display, "NULL"); + mode->dummy = 1; + mode->metamode = metamode; + + /* Duplicate position information of the last mode */ + if (last_mode) { + mode->dim[X] = last_mode->dim[X]; + mode->dim[Y] = last_mode->dim[Y]; + mode->pan[X] = last_mode->pan[X]; + mode->pan[Y] = last_mode->pan[Y]; + mode->position_type = last_mode->position_type; + mode->relative_to = last_mode->relative_to; + } + + /* Add the mode at the end of display's mode list */ + display->modes = + (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes, + (GenericListPtr)mode); + display->num_modes++; + + metamode = metamode->next; + } + + /* XXX Shouldn't need to remove extra modes. + while (mode) { + } + */ + } + + return TRUE; + +} /* check_screen_metamodes() */ + + + +/** assign_dummy_metamode_positions() ******************************** + * + * Assign the initial (top left) position of dummy modes to + * match the top left of the first non-dummy mode + * + */ + +static void assign_dummy_metamode_positions(nvScreenPtr screen) +{ + nvDisplayPtr display; + nvModePtr ok_mode; + nvModePtr mode; + + + for (display = screen->gpu->displays; display; display = display->next) { + if (display->screen != screen) continue; + + /* Get the first non-dummy mode */ + for (ok_mode = display->modes; ok_mode; ok_mode = ok_mode->next) { + if (!ok_mode->dummy) break; + } + + if (ok_mode) { + for (mode = display->modes; mode; mode = mode->next) { + if (!mode->dummy) continue; + mode->dim[X] = ok_mode->dim[X]; + mode->pan[X] = ok_mode->dim[X]; + mode->dim[Y] = ok_mode->dim[Y]; + mode->pan[Y] = ok_mode->dim[Y]; + } + } + } + +} /* assign_dummy_metamode_positions() */ + + + +/** remove_metamodes_from_screen() *********************************** + * + * Removes all metamodes currently referenced by this screen, also + * freeing any memory used. + * + **/ + +static void remove_metamodes_from_screen(nvScreenPtr screen) +{ + nvGpuPtr gpu; + nvDisplayPtr display; + nvMetaModePtr metamode; + + if (screen) { + gpu = screen->gpu; + + /* Remove the modes from this screen's displays */ + if (gpu) { + for (display = gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + remove_modes_from_display(display); + } + } + + /* Clear the screen's metamode list */ + while (screen->metamodes) { + metamode = screen->metamodes; + screen->metamodes = metamode->next; + free(metamode->string); + free(metamode); + } + screen->num_metamodes = 0; + screen->cur_metamode = NULL; + screen->cur_metamode_idx = -1; + } + +} /* remove_metamodes_from_screen() */ + + + +/** add_metamodes_to_screen() **************************************** + * + * Adds all the appropreate modes on all display devices of this + * screen by parsing all the metamode strings. + * + */ + +static Bool add_metamodes_to_screen(nvScreenPtr screen, gchar **err_str) +{ + nvDisplayPtr display; + + char *metamode_strs = NULL; /* Screen's list metamode strings */ + char *cur_metamode_str; /* Current metamode */ + + char *str; /* Temp pointer for parsing */ + int len; + ReturnStatus ret; + int i; + + + + /* Get the list of metamodes for the screen */ + ret = NvCtrlGetBinaryAttribute(screen->handle, 0, + NV_CTRL_BINARY_DATA_METAMODES, + (unsigned char **)&metamode_strs, + &len); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query list of metamodes on\n" + "screen %d (on GPU-%d).", + screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle)); + nv_error_msg(*err_str); + goto fail; + } + + + /* Get the current metamode for the screen */ + ret = NvCtrlGetStringAttribute(screen->handle, + NV_CTRL_STRING_CURRENT_METAMODE, + &cur_metamode_str); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query current metamode of\n" + "screen %d (on GPU-%d).", + screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle)); + nv_error_msg(*err_str); + goto fail; + } + + + /* Remove any existing modes on all displays */ + remove_metamodes_from_screen(screen); + + + /* Parse each mode in the metamode strings */ + str = metamode_strs; + while (str && strlen(str)) { + + /* Add the individual metamodes to the screen, + * This populates the display device's mode list. + */ + if (!add_metamode_to_screen(screen, str, err_str)) { + nv_warning_msg("Failed to add metamode '%s' to screen %d (on " + "GPU-%d).", + str, screen->scrnum, + NvCtrlGetTargetId(screen->gpu->handle)); + goto fail; + } + + /* Keep track of the current metamode */ + if (!strcmp(str, cur_metamode_str)) { + screen->cur_metamode_idx = screen->num_metamodes; + } + + /* Keep count of the metamode */ + screen->num_metamodes++; + + /* Make sure each display device gets a mode */ + check_screen_metamodes(screen); + + /* Go to the next metamode */ + str += strlen(str) +1; + } + XFree(metamode_strs); + + + /* Assign the top left position of dummy modes */ + assign_dummy_metamode_positions(screen); + + + /* Make the screen point at the current metamode */ + screen->cur_metamode = screen->metamodes; + for (i = 0; i < screen->cur_metamode_idx; i++) { + screen->cur_metamode = screen->cur_metamode->next; + } + + + /* Make each display within the screen point to the current mode. + * Also, count the number of displays on the screen + */ + screen->num_displays = 0; + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; /* Display not in screen */ + + screen->num_displays++; + screen->displays_mask |= display->device_mask; + + display->cur_mode = display->modes; + for (i = 0; i < screen->cur_metamode_idx; i++) { + display->cur_mode = display->cur_mode->next; + } + } + + return TRUE; + + + /* Failure case */ + fail: + + /* Remove modes we may have added */ + remove_metamodes_from_screen(screen); + + XFree(metamode_strs); + return FALSE; + +} /* add_metamodes_to_screen() */ + + + +/* Screen functions **************************************************/ + + +/** remove_display_from_screen() ************************************* + * + * Removes a display device from the screen + * + */ +static void remove_display_from_screen(nvDisplayPtr display) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + nvDisplayPtr other; + nvModePtr mode; + + + if (display && display->screen) { + screen = display->screen; + gpu = display->gpu; + + /* Make any display relative to this one use absolute position */ + for (other = gpu->displays; other; other = other->next) { + + if (other == display) continue; + if (other->screen != screen) continue; + + for (mode = other->modes; mode; mode = mode->next) { + if (mode->relative_to == display) { + mode->position_type = CONF_ADJ_ABSOLUTE; + mode->relative_to = NULL; + } + } + } + + /* Remove the display from the screen */ + screen->displays_mask &= ~(display->device_mask); + screen->num_displays--; + + /* Clean up old references to the screen in the display */ + remove_modes_from_display(display); + display->screen = NULL; + } + +} /* remove_display_from_screen() */ + + + +/** remove_displays_from_screen() ************************************ + * + * Removes all displays currently pointing at this screen, also + * freeing any memory used. + * + **/ + +void remove_displays_from_screen(nvScreenPtr screen) +{ + nvGpuPtr gpu; + nvDisplayPtr display; + + if (screen && screen->gpu) { + gpu = screen->gpu; + + for (display = gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + remove_display_from_screen(display); + } + } + +} /* remove_displays_from_screen() */ + + + +/** free_screen() **************************************************** + * + * Frees memory used by a screen structure + * + */ +static void free_screen(nvScreenPtr screen) +{ + if (screen) { + + remove_metamodes_from_screen(screen); + remove_displays_from_screen(screen); + + if (screen->handle) { + NvCtrlAttributeClose(screen->handle); + } + + free(screen); + } + +} /* free_screens() */ + + + +/** add_screen_to_gpu() ********************************************** + * + * Adds screen 'screen_id' that is connected to the gpu. + * + */ +static int add_screen_to_gpu(nvGpuPtr gpu, int screen_id, gchar **err_str) +{ + Display *display; + nvScreenPtr screen; + int val; + ReturnStatus ret; + + + /* Create the screen structure */ + screen = (nvScreenPtr)calloc(1, sizeof(nvScreen)); + if (!screen) goto fail; + + screen->gpu = gpu; + screen->scrnum = screen_id; + + + /* Make an NV-CONTROL handle to talk to the screen */ + display = NvCtrlGetDisplayPtr(gpu->handle); + screen->handle = + NvCtrlAttributeInit(display, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen_id, + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM | + NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM); + if (!screen->handle) { + *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for\n" + "screen %d (on GPU-%d).", + screen_id, NvCtrlGetTargetId(gpu->handle)); + nv_error_msg(*err_str); + goto fail; + } + + + /* Make sure this screen supports dynamic twinview */ + ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_DYNAMIC_TWINVIEW, + &val); + if (ret != NvCtrlSuccess || !val) { + *err_str = g_strdup_printf("Dynamic TwinView is disabled on " + "screen %d.", + screen_id); + nv_error_msg(*err_str); + goto fail; + } + + + /* The display owner GPU gets the screen(s) */ + ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_MULTIGPU_DISPLAY_OWNER, + &val); + if (ret != NvCtrlSuccess || val != NvCtrlGetTargetId(gpu->handle)) { + free_screen(screen); + return TRUE; + } + + + /* Listen to NV-CONTROL events on this screen handle */ + screen->ctk_event = CTK_EVENT(ctk_event_new(screen->handle)); + + + /* Query the depth of the screen */ + screen->depth = NvCtrlGetScreenPlanes(screen->handle); + + + /* Parse the screen's metamodes (ties displays on the gpu to the screen) */ + if (!add_metamodes_to_screen(screen, err_str)) { + nv_warning_msg("Failed to add metamodes to screen %d (on GPU-%d).", + screen_id, NvCtrlGetTargetId(gpu->handle)); + goto fail; + } + + + /* Add the screen at the end of the gpu's screen list */ + gpu->screens = + (nvScreenPtr)xconfigAddListItem((GenericListPtr)gpu->screens, + (GenericListPtr)screen); + gpu->num_screens++; + return TRUE; + + + fail: + free_screen(screen); + return FALSE; + +} /* add_screen_to_gpu() */ + + + +/** remove_screen_from_gpu() ***************************************** + * + * Removes a screen from a gpu. + * + */ +static void remove_screen_from_gpu(nvScreenPtr screen) +{ + nvGpuPtr gpu; + nvScreenPtr other; + + if (!screen || !screen->gpu) return; + + /* Remove the screen from the GPU */ + gpu = screen->gpu; + + gpu->screens = + (nvScreenPtr)xconfigRemoveListItem((GenericListPtr)gpu->screens, + (GenericListPtr)screen); + gpu->num_screens--; + + /* Make sure other screens in the layout aren't relative + * to this screen + */ + for (gpu = screen->gpu->layout->gpus; gpu; gpu = gpu->next) { + for (other = gpu->screens; other; other = other->next) { + if (other->relative_to == screen) { + other->position_type = CONF_ADJ_ABSOLUTE; + other->relative_to = NULL; + } + } + } + + screen->gpu = NULL; + + /* XXX May want to remove metamodes here */ + /* XXX May want to remove displays here */ + +} /* remove_screen_from_gpu() */ + + + +/** remove_screens_from_gpu() **************************************** + * + * Removes all screens from a gpu. + * + */ +static void remove_screens_from_gpu(nvGpuPtr gpu) +{ + nvScreenPtr screen; + + if (gpu) { + while (gpu->screens) { + screen = gpu->screens; + gpu->screens = screen->next; + free_screen(screen); + } + gpu->num_screens = 0; + } + +} /* remove_screens_from_gpu() */ + + + +/** add_screens_to_gpu() ********************************************* + * + * Queries the list of screens on the gpu. + * + */ +static Bool add_screens_to_gpu(nvGpuPtr gpu, gchar **err_str) +{ + ReturnStatus ret; + int *pData; + int len; + int i; + + + /* Clean up the GPU list */ + remove_screens_from_gpu(gpu); + + + /* Query the list of X Screens this GPU is driving */ + ret = NvCtrlGetBinaryAttribute(gpu->handle, 0, + NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU, + (unsigned char **)(&pData), &len); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query list of screens driven\n" + "by GPU-%d '%s'.", + NvCtrlGetTargetId(gpu->handle), gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + + /* Add each X Screen */ + for (i = 1; i <= pData[0]; i++) { + if (!add_screen_to_gpu(gpu, pData[i], err_str)) { + nv_warning_msg("Failed to add screen %d to GPU-%d '%s'.", + pData[i], NvCtrlGetTargetId(gpu->handle), + gpu->name); + goto fail; + } + } + + return TRUE; + + + /* Failure case */ + fail: + remove_screens_from_gpu(gpu); + return FALSE; + +} /* add_screens_to_gpu() */ + + + +/* Display device functions ******************************************/ + + +/** remove_modelines_from_display() ********************************** + * + * Clears the display device's modeline list. + * + **/ + +static void remove_modelines_from_display(nvDisplayPtr display) +{ + nvModeLinePtr modeline; + + if (display) { + while (display->modelines) { + modeline = display->modelines; + display->modelines = display->modelines->next; + free(modeline); + } + display->num_modelines = 0; + } + +} /* remove_modelines_from_display() */ + + + +/** add_modelines_to_display() *************************************** + * + * Queries the display's current modepool (modelines list). + * + **/ + +static Bool add_modelines_to_display(nvDisplayPtr display, gchar **err_str) +{ + nvModeLinePtr modeline; + char *modeline_strs = NULL; + char *str; + int len; + ReturnStatus ret; + + + /* Free any old mode lines */ + remove_modelines_from_display(display); + + + /* Get the validated modelines for the display */ + ret = NvCtrlGetBinaryAttribute(display->gpu->handle, + display->device_mask, + NV_CTRL_BINARY_DATA_MODELINES, + (unsigned char **)&modeline_strs, &len); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query modelines of display " + "device 0x%08x '%s'\nconnected to " + "GPU-%d '%s'.", + display->device_mask, display->name, + NvCtrlGetTargetId(display->gpu->handle), + display->gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + + /* Parse each modeline */ + str = modeline_strs; + while (strlen(str)) { + + modeline = parse_modeline(str); + if (!modeline) { + *err_str = g_strdup_printf("Failed to parse the following " + "modeline of display device\n" + "0x%08x '%s' connected to GPU-%d " + "'%s':\n\n%s", + display->device_mask, + display->name, + NvCtrlGetTargetId(display->gpu->handle), + display->gpu->name, + str); + nv_error_msg(*err_str); + goto fail; + } + + /* Add the modeline at the end of the display's modeline list */ + display->modelines = (nvModeLinePtr)xconfigAddListItem + ((GenericListPtr)display->modelines, (GenericListPtr)modeline); + display->num_modelines++; + + /* Get next modeline string */ + str += strlen(str) +1; + } + + XFree(modeline_strs); + return TRUE; + + + /* Handle the failure case */ + fail: + remove_modelines_from_display(display); + XFree(modeline_strs); + return FALSE; + +} /* add_modelines_to_display() */ + + + +/** free_display() *************************************************** + * + * Frees memory used by a display + * + */ +static void free_display(nvDisplayPtr display) +{ + if (display) { + remove_modes_from_display(display); + remove_modelines_from_display(display); + XFree(display->name); + free(display); + } + +} /* free_display(display) */ + + + +/** add_display_to_gpu() ********************************************* + * + * Adds the display with the device mask given to the GPU structure. + * + */ +static nvDisplayPtr add_display_to_gpu(nvGpuPtr gpu, unsigned int device_mask, + gchar **err_str) +{ + ReturnStatus ret; + nvDisplayPtr display = NULL; + + + /* Create the display structure */ + display = (nvDisplayPtr)calloc(1, sizeof(nvDisplay)); + if (!display) goto fail; + + + /* Init the display structure */ + display->gpu = gpu; + display->device_mask = device_mask; + + + /* Query the display information */ + ret = NvCtrlGetStringDisplayAttribute(gpu->handle, + device_mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &(display->name)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query name of display device\n" + "0x%08x connected to GPU-%d '%s'.", + device_mask, NvCtrlGetTargetId(gpu->handle), + gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + + /* Query the modelines for the display device */ + if (!add_modelines_to_display(display, err_str)) { + nv_warning_msg("Failed to add modelines to display device 0x%08x " + "'%s'\nconnected to GPU-%d '%s'.", + device_mask, display->name, + NvCtrlGetTargetId(gpu->handle), gpu->name); + goto fail; + } + + + /* Add the display at the end of gpu's display list */ + gpu->displays = + (nvDisplayPtr)xconfigAddListItem((GenericListPtr)gpu->displays, + (GenericListPtr)display); + gpu->connected_displays |= device_mask; + gpu->num_displays++; + return display; + + + /* Failure case */ + fail: + free_display(display); + return NULL; + +} /* add_display_to_gpu() */ + + + +/** remove_display_from_gpu() **************************************** + * + * Removes a display from the gpu + * + */ +static void remove_display_from_gpu(nvDisplayPtr display) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + + + if (display && display->gpu) { + gpu = display->gpu; + screen = display->screen; + + /* Remove the display from the screen it may be in */ + if (screen) { + remove_display_from_screen(display); + + /* If the screen is empty, remove it too */ + if (!screen->num_displays) { + remove_screen_from_gpu(screen); + free_screen(screen); + } + } + + /* Remove the display from the gpu */ + gpu->displays = + (nvDisplayPtr)xconfigRemoveListItem((GenericListPtr)gpu->displays, + (GenericListPtr)display); + gpu->connected_displays &= ~(display->device_mask); + gpu->num_displays--; + } + +} /* remove_display_from_gpu() */ + + + +/** remove_displays_from_gpu() *************************************** + * + * Removes all displays from the gpu + * + */ +static void remove_displays_from_gpu(nvGpuPtr gpu) +{ + nvDisplayPtr display; + + if (gpu) { + while (gpu->displays) { + display = gpu->displays; + remove_display_from_screen(display); + gpu->displays = display->next; + free_display(display); + } + gpu->num_displays = 0; + } + +} /* remove_displays_from_gpu() */ + + + +/** add_displays_to_gpu() ******************************************** + * + * Adds the display devices connected on the GPU to the GPU structure + * + */ +static Bool add_displays_to_gpu(nvGpuPtr gpu, gchar **err_str) +{ + unsigned int mask; + + + /* Clean up the GPU list */ + remove_displays_from_gpu(gpu); + + + /* Add each connected display */ + for (mask = 1; mask; mask <<= 1) { + + if (!(mask & (gpu->connected_displays))) continue; + + if (!add_display_to_gpu(gpu, mask, err_str)) { + nv_warning_msg("Failed to add display device 0x%08x to GPU-%d " + "'%s'.", + mask, NvCtrlGetTargetId(gpu->handle), gpu->name); + goto fail; + } + } + + return TRUE; + + + /* Failure case */ + fail: + remove_displays_from_gpu(gpu); + return FALSE; + +} /* add_displays_to_gpu() */ + + + +/* GPU functions *****************************************************/ + + +/** add_screenless_modes_to_displays() ******************************* + * + * Adds fake modes to display devices that have no screens so we + * can show them on the layout page. + * + */ +static Bool add_screenless_modes_to_displays(nvGpuPtr gpu) +{ + nvDisplayPtr display; + nvModePtr mode; + + for (display = gpu->displays; display; display = display->next) { + if (display->screen) continue; + + /* Create a fake mode */ + mode = (nvModePtr)calloc(1, sizeof(nvMode)); + if (!mode) return FALSE; + + mode->display = display; + mode->dummy = 1; + + mode->dim[W] = 800; + mode->dim[H] = 600; + mode->pan[W] = mode->dim[W]; + mode->pan[H] = mode->dim[H]; + + /* Add the mode to the display */ + display->modes = mode; + display->cur_mode = mode; + display->num_modes = 1; + } + + return TRUE; + +} /* add_screenless_modes_to_displays() */ + + + +/** free_gpu() ******************************************************* + * + * Frees memory used by the gpu. + * + **/ +static void free_gpu(nvGpuPtr gpu) +{ + if (gpu) { + remove_screens_from_gpu(gpu); + remove_displays_from_gpu(gpu); + XFree(gpu->name); + if (gpu->handle) { + NvCtrlAttributeClose(gpu->handle); + } + free(gpu); + } + +} /* free_gpu() */ + + + +/** add_gpu_to_layout() ********************************************** + * + * Adds a GPU to the layout structure. + * + **/ +static Bool add_gpu_to_layout(nvLayoutPtr layout, unsigned int gpu_id, + gchar **err_str) +{ + ReturnStatus ret; + Display *dpy; + nvGpuPtr gpu = NULL; + + + /* Create the GPU structure */ + gpu = (nvGpuPtr)calloc(1, sizeof(nvGpu)); + if (!gpu) goto fail; + + + /* Make an NV-CONTROL handle to talk to the GPU */ + dpy = NvCtrlGetDisplayPtr(layout->handle); + gpu->layout = layout; + gpu->handle = NvCtrlAttributeInit(dpy, NV_CTRL_TARGET_TYPE_GPU, gpu_id, + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + if (!gpu->handle) { + *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for " + "GPU-%d.", gpu_id); + nv_error_msg(*err_str); + goto fail; + } + + gpu->ctk_event = CTK_EVENT(ctk_event_new(gpu->handle)); + + + /* Query the GPU information */ + ret = NvCtrlGetStringAttribute(gpu->handle, NV_CTRL_STRING_PRODUCT_NAME, + &gpu->name); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query GPU name of GPU-%d.", + gpu_id); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_CONNECTED_DISPLAYS, + (int *)&(gpu->connected_displays)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query connected display " + "devices on GPU-%d '%s'.", + gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_BUS, + (int *)&(gpu->pci_bus)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query PCI BUS on GPU-%d '%s'.", + gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_DEVICE, + (int *)&(gpu->pci_device)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query PCI DEVICE on " + "GPU-%d '%s'.", gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_FUNCTION, + (int *)&(gpu->pci_func)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query PCI FUNCTION on " + "GPU-%d '%s'.", gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_WIDTH, + (int *)&(gpu->max_width)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query MAX SCREEN WIDTH on " + "GPU-%d '%s'.", gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_HEIGHT, + (int *)&(gpu->max_height)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query MAX SCREEN HEIGHT on " + "GPU-%d '%s'.", gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_DISPLAYS, + (int *)&(gpu->max_displays)); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup_printf("Failed to query MAX DISPLAYS on " + "GPU-%d '%s'.", gpu_id, gpu->name); + nv_error_msg(*err_str); + goto fail; + } + + + /* Add the display devices to the GPU */ + if (!add_displays_to_gpu(gpu, err_str)) { + nv_warning_msg("Failed to add displays to GPU-%d '%s'.", + gpu_id, gpu->name); + goto fail; + } + + + /* Add the X Screens to the GPU */ + if (!add_screens_to_gpu(gpu, err_str)) { + nv_warning_msg("Failed to add screens to GPU-%d '%s'.", + gpu_id, gpu->name); + goto fail; + } + + + /* Add fake modes to screenless display devices */ + if (!add_screenless_modes_to_displays(gpu)) { + nv_warning_msg("Failed to add screenless modes to GPU-%d '%s'.", + gpu_id, gpu->name); + goto fail; + } + + + /* Add the GPU at the end of the layout's GPU list */ + layout->gpus = (nvGpuPtr)xconfigAddListItem((GenericListPtr)layout->gpus, + (GenericListPtr)gpu); + layout->num_gpus++; + return TRUE; + + + /* Failure case */ + fail: + free_gpu(gpu); + return FALSE; + +} /* add_gpu_to_layout() */ + + + +/** remove_gpus_from_layout() **************************************** + * + * Removes all GPUs from the layout structure. + * + **/ +static void remove_gpus_from_layout(nvLayoutPtr layout) +{ + nvGpuPtr gpu; + + if (layout) { + while (layout->gpus) { + gpu = layout->gpus; + layout->gpus = gpu->next; + free_gpu(gpu); + } + layout->num_gpus = 0; + } + +} /* remove_gpus_from_layout() */ + + + +/** add_gpus_to_layout() ********************************************* + * + * Adds the GPUs found on the server to the layout structure. + * + **/ + +static int add_gpus_to_layout(nvLayoutPtr layout, gchar **err_str) +{ + ReturnStatus ret; + int ngpus; + int i; + + + /* Clean up the GPU list */ + remove_gpus_from_layout(layout); + + + /* Query the number of GPUs on the server */ + ret = NvCtrlQueryTargetCount(layout->handle, NV_CTRL_TARGET_TYPE_GPU, + &ngpus); + if (ret != NvCtrlSuccess || !ngpus) { + *err_str = g_strdup("Failed to query number of GPUs (or no GPUs " + "found) in the system."); + nv_error_msg(*err_str); + goto fail; + } + + + /* Add each GPU */ + for (i = 0; i < ngpus; i++) { + if (!add_gpu_to_layout(layout, i, err_str)) { + nv_warning_msg("Failed to add GPU-%d to layout.", i); + goto fail; + } + } + + return layout->num_gpus; + + + /* Failure case */ + fail: + remove_gpus_from_layout(layout); + return 0; + +} /* add_gpus_to_layout() */ + + + +/* Layout functions **************************************************/ + + +/** assign_screen_positions() **************************************** + * + * Assign the initial position of the X Screens. + * + * - If Xinerama is enabled, query the XINERAMA_SCREEN_INFO. + * + * - If Xinerama is disabled, assume "right-of" orientation. (bleh!) + * + **/ + +static void assign_screen_positions(CtkDisplayConfig *ctk_object) +{ + nvGpuPtr gpu; + nvScreenPtr prev_screen = NULL; + nvScreenPtr screen; + int xinerama; + int initialize = 0; + + char *screen_info; + ScreenInfo screen_parsed_info; + ReturnStatus ret; + + + /* If xinerama is enabled, we can get the screen size! */ + ret = NvCtrlGetAttribute(ctk_object->handle, NV_CTRL_XINERAMA, &xinerama); + if (ret != NvCtrlSuccess) { + initialize = 1; /* Fallback to right-of positioning */ + } + + + /* Setup screen positions */ + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + + screen_info = NULL; + if (screen->handle && !initialize) { + ret = NvCtrlGetStringAttribute + (screen->handle, + NV_CTRL_STRING_XINERAMA_SCREEN_INFO, + &screen_info); + + if (ret != NvCtrlSuccess) { + screen_info = NULL; + } + } + + if (screen_info) { + + /* Parse the positioning information */ + + screen_parsed_info.x = -1; + screen_parsed_info.y = -1; + screen_parsed_info.width = -1; + screen_parsed_info.height = -1; + + parse_tokens(screen_info, apply_screen_info_token, + &screen_parsed_info); + + if (screen_parsed_info.x >= 0 && + screen_parsed_info.y >= 0 && + screen_parsed_info.width >= 0 && + screen_parsed_info.height) { + + ctk_display_layout_set_screen_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, CONF_ADJ_ABSOLUTE, NULL, + screen_parsed_info.x, + screen_parsed_info.y); + } + XFree(screen_info); + + } else if (prev_screen) { + /* Set this screen right of the previous */ + ctk_display_layout_set_screen_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, CONF_ADJ_RIGHTOF, prev_screen, 0, 0); + } + + prev_screen = screen; + } + } + +} /* assign_screen_positions() */ + + + +/** load_server_layout() ********************************************* + * + * Loads layout information from the X server. + * + **/ + +nvLayoutPtr load_server_layout(NvCtrlAttributeHandle *handle, gchar **err_str) +{ + nvLayoutPtr layout; + ReturnStatus ret; + + + /* Allocate the layout structure */ + layout = (nvLayoutPtr)calloc(1, sizeof(nvLayout)); + if (!layout) goto fail; + + + /* Cache the handle for talking to the X Server */ + layout->handle = handle; + + + /* Is Xinerma enabled? */ + ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA, + &layout->xinerama_enabled); + if (ret != NvCtrlSuccess) { + *err_str = g_strdup("Failed to query status of Xinerama."); + nv_error_msg(*err_str); + goto fail; + } + + + /* Add GPUs to the layout */ + if (!add_gpus_to_layout(layout, err_str)) { + nv_warning_msg("Failed to add GPU(s) to layout for display " + "configuration page."); + goto fail; + } + + return layout; + + + /* Failure case */ + fail: + if (layout) { + remove_gpus_from_layout(layout); + free(layout); + } + return NULL; + +} /* load_server_layout() */ + + + +/* Widget creation functions *****************************************/ + + +/** ctk_display_config_get_type() ************************************ + * + * Returns the display configuration type. + * + **/ + +GType ctk_display_config_get_type(void) +{ + static GType ctk_display_config_type = 0; + + if (!ctk_display_config_type) { + static const GTypeInfo ctk_display_config_info = { + sizeof (CtkDisplayConfigClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(CtkDisplayConfig), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_display_config_type = g_type_register_static + (GTK_TYPE_VBOX, "CtkDisplayConfig", &ctk_display_config_info, 0); + } + + return ctk_display_config_type; + +} /* ctk_display_config_get_type() */ + + + +/** create_validation_dialog() *************************************** + * + * Creates the Validation Information dialog widget. + * + **/ + +GtkWidget * create_validation_dialog(CtkDisplayConfig *ctk_object) +{ + GtkWidget *dialog; + GtkWidget *image; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *button; + GtkWidget *scrolled_window; + GtkWidget *textview; + GtkTextBuffer *buffer; + + + /* Display validation override confirmation dialog */ + dialog = gtk_dialog_new_with_buttons + ("Layout Inconsistencie(s)", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + NULL); + + /* Main horizontal box */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), + hbox, TRUE, TRUE, 5); + + /* Pack the information icon */ + image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(image), 0.0f, 0.0f); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 5); + + /* Main vertical box */ + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); + + /* Pack the main message */ + label = gtk_label_new("The current layout has some inconsistencies."); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.0f); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + /* Details button */ + button = gtk_button_new(); + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(validation_details_clicked), + (gpointer) ctk_object); + ctk_object->btn_validation_override_show = button; + + /* Text view */ + textview = gtk_text_view_new(); + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview), FALSE); + gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), GTK_WRAP_WORD); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textview), 5); + gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textview), 5); + + buffer = gtk_text_buffer_new(NULL); + gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), + GTK_TEXT_BUFFER(buffer)); + + ctk_object->buf_validation_override = buffer; + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type + (GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(scrolled_window), textview); + + /* Pack the scrolled window */ + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + ctk_object->box_validation_override_details = hbox; + + /* Action Buttons */ + gtk_dialog_add_button(GTK_DIALOG(dialog), "Auto Fix", GTK_RESPONSE_APPLY); + gtk_dialog_add_button(GTK_DIALOG(dialog), "Ignore", GTK_RESPONSE_ACCEPT); + /* Keep track of the cancel button so we can set focus on it */ + button = gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", + GTK_RESPONSE_REJECT); + ctk_object->btn_validation_override_cancel = button; + + gtk_widget_show_all(GTK_DIALOG(dialog)->vbox); + + return dialog; + +} /* create_validation_dialog() */ + + + +/** create_validation_apply_dialog() ********************************* + * + * Creates the Validation Apply Information dialog widget. + * + **/ + +GtkWidget * create_validation_apply_dialog(CtkDisplayConfig *ctk_object) +{ + GtkWidget *dialog; + GtkWidget *image; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + gchar bullet[8]; // UTF8 Bullet string + int len; + gchar *str; + + + /* Convert the Unicode "Bullet" Character into a UTF8 string */ + len = g_unichar_to_utf8(0x2022, bullet); + bullet[len] = '\0'; + + /* Display validation override confirmation dialog */ + dialog = gtk_dialog_new_with_buttons + ("Cannot Apply", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + NULL); + ctk_object->dlg_validation_apply = dialog; + + /* Main horizontal box */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), + hbox, TRUE, TRUE, 5); + + /* Pack the information icon */ + image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(image), 0.0f, 0.0f); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 5); + + /* Main vertical box */ + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); + + /* Pack the main message */ + str = g_strdup_printf("The current settings cannot be completely applied\n" + "due to one or more of the following reasons:\n" + "\n" + "%s The location an X Screens has changed.\n" + "%s The location type of an X Screens has changed.\n" + "%s The color depth of an X Screen has changed.\n" + "%s An X Screen has been added or removed.\n" + "%s Xinerama is being enabled/disabled.\n" + "\n" + "For all the requested settings to take effect,\n" + "you must save the configuration to the X Config\n" + "file and restart the X Server.", + bullet, bullet, bullet, bullet, bullet); + label = gtk_label_new(str); + g_free(str); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.0f); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + /* Action Buttons */ + gtk_dialog_add_button(GTK_DIALOG(dialog), "Apply What Is Possible", + GTK_RESPONSE_ACCEPT); + gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", GTK_RESPONSE_REJECT); + + gtk_widget_show_all(GTK_DIALOG(dialog)->vbox); + + return dialog; + +} /* create_validation_apply_dialog() */ + + + +/** ctk_display_config_new() ***************************************** + * + * Display Configuration widget creation. + * + **/ + +GtkWidget* ctk_display_config_new(NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config) +{ + GObject *object; + CtkDisplayConfig *ctk_object; + + GtkWidget *banner; + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *hbox2; + GtkWidget *vbox; + GtkWidget *label; + + GtkRequisition req; + + GtkWidget *vpanel; + GtkWidget *scrolled_window; + GtkWidget *viewport; + + GtkWidget *menu; + GtkWidget *menu_item; + + gchar *err_str = NULL; + + + /* + * Create the ctk object + * + */ + + object = g_object_new(CTK_TYPE_DISPLAY_CONFIG, NULL); + ctk_object = CTK_DISPLAY_CONFIG(object); + + ctk_object->handle = handle; + ctk_object->ctk_config = ctk_config; + + ctk_object->apply_possible = TRUE; + ctk_object->advanced_mode = FALSE; + + /* Set container properties of the object & pack the banner */ + gtk_box_set_spacing(GTK_BOX(ctk_object), 5); + + banner = ctk_banner_image_new(&blank_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); + + + + /* + * Create the display configuration widgets + * + */ + + /* Load the layout structure from the X server */ + ctk_object->layout = load_server_layout(handle, &err_str); + + /* If we failed to load, tell the user why */ + if (err_str || !ctk_object->layout) { + gchar *str; + + if (!err_str) { + str = g_strdup("Failed to load X Server Display Configuration."); + } else { + str = g_strdup_printf("Error while loading X Server Display " + "Configuration:\n\n%s", err_str); + g_free(err_str); + } + + label = gtk_label_new(str); + g_free(str); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_container_add(GTK_CONTAINER(object), label); + + /* Show the GUI */ + gtk_widget_show_all(GTK_WIDGET(ctk_object)); + + return GTK_WIDGET(ctk_object); + } + + /* Create the layout widget */ + ctk_object->obj_layout = ctk_display_layout_new(handle, ctk_config, + ctk_object->layout, + 300, /* min width */ + 225, /* min height */ + layout_selected_callback, + (void *)ctk_object, + layout_modified_callback, + (void *)ctk_object); + + /* Make sure we have some kind of positioning */ + assign_screen_positions(ctk_object); + + /* Grab the current screen position for "apply possible" tracking */ + get_cur_screen_pos(ctk_object); + + + /* + * Create the widgets + * + */ + + /* Xinerama button */ + + ctk_object->chk_xinerama_enabled = + gtk_check_button_new_with_label("Enable Xinerama"); + ctk_config_set_tooltip(ctk_config, ctk_object->chk_xinerama_enabled, + __layout_xinerama_button_help); + g_signal_connect(G_OBJECT(ctk_object->chk_xinerama_enabled), "toggled", + G_CALLBACK(xinerama_state_toggled), + (gpointer) ctk_object); + + + /* Display model name */ + ctk_object->txt_display_model = gtk_label_new(""); + gtk_label_set_selectable(GTK_LABEL(ctk_object->txt_display_model), TRUE); + gtk_misc_set_alignment(GTK_MISC(ctk_object->txt_display_model), 0.0f, 0.5f); + + /* Display configuration (Disabled, TwinView, Separate X Screen */ + ctk_object->btn_display_config = + gtk_button_new_with_label("Configure..."); + g_signal_connect(G_OBJECT(ctk_object->btn_display_config), "clicked", + G_CALLBACK(display_config_clicked), + (gpointer) ctk_object); + ctk_object->txt_display_config = gtk_label_new("Disabled"); + gtk_misc_set_alignment(GTK_MISC(ctk_object->txt_display_config), 0.0f, 0.5f); + + + /* Display configuration dialog */ + ctk_object->dlg_display_config = gtk_dialog_new_with_buttons + ("Configure Display Device", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT + | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + ctk_object->btn_display_config_cancel = + gtk_dialog_add_button(GTK_DIALOG(ctk_object->dlg_display_config), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + ctk_object->rad_display_config_disabled = + gtk_radio_button_new_with_label(NULL, "Disabled"); + ctk_object->rad_display_config_xscreen = + gtk_radio_button_new_with_label_from_widget + (GTK_RADIO_BUTTON(ctk_object->rad_display_config_disabled), + "Separate X Screen"); + ctk_object->rad_display_config_twinview = + gtk_radio_button_new_with_label_from_widget + (GTK_RADIO_BUTTON(ctk_object->rad_display_config_disabled), + "TwinView"); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_display_config), + FALSE); + + /* Display disable dialog */ + ctk_object->txt_display_disable = gtk_label_new(""); + ctk_object->dlg_display_disable = gtk_dialog_new_with_buttons + ("Disable Display Device", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT + | GTK_DIALOG_NO_SEPARATOR, + NULL); + ctk_object->btn_display_disable_off = + gtk_dialog_add_button(GTK_DIALOG(ctk_object->dlg_display_disable), + "Remove", + GTK_RESPONSE_ACCEPT); + ctk_object->btn_display_disable_cancel = + gtk_dialog_add_button(GTK_DIALOG(ctk_object->dlg_display_disable), + "Ignore", + GTK_RESPONSE_CANCEL); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_display_disable), + FALSE); + + + /* Display resolution */ + ctk_object->mnu_display_resolution = gtk_option_menu_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->mnu_display_resolution, + __dpy_resolution_mnu_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_display_resolution), "changed", + G_CALLBACK(display_resolution_changed), + (gpointer) ctk_object); + + + /* Display refresh */ + ctk_object->mnu_display_refresh = gtk_option_menu_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->mnu_display_refresh, + __dpy_refresh_mnu_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_display_refresh), "changed", + G_CALLBACK(display_refresh_changed), + (gpointer) ctk_object); + + /* Display modeline modename */ + ctk_object->txt_display_modename = gtk_label_new(""); + + /* Display Position Type (Absolute/Relative Menu) */ + ctk_object->mnu_display_position_type = gtk_option_menu_new(); + menu = gtk_menu_new(); + menu_item = gtk_menu_item_new_with_label("Absolute"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Right of"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Left of"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Above"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Below"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Clones"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_display_position_type), menu); + ctk_config_set_tooltip(ctk_config, ctk_object->mnu_display_position_type, + __dpy_position_type_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_display_position_type), + "changed", G_CALLBACK(display_position_type_changed), + (gpointer) ctk_object); + + /* Display Position Relative (Display device to be relative to) */ + ctk_object->mnu_display_position_relative = gtk_option_menu_new(); + ctk_config_set_tooltip(ctk_config, + ctk_object->mnu_display_position_relative, + __dpy_position_relative_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_display_position_relative), + "changed", + G_CALLBACK(display_position_relative_changed), + (gpointer) ctk_object); + + /* Display Position Offset (Absolute position) */ + ctk_object->txt_display_position_offset = gtk_entry_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->txt_display_position_offset, + __dpy_position_offset_help); + g_signal_connect(G_OBJECT(ctk_object->txt_display_position_offset), + "activate", G_CALLBACK(display_position_offset_activate), + (gpointer) ctk_object); + + /* Display Panning */ + ctk_object->txt_display_panning = gtk_entry_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->txt_display_panning, + __dpy_panning_help); + g_signal_connect(G_OBJECT(ctk_object->txt_display_panning), "activate", + G_CALLBACK(display_panning_activate), + (gpointer) ctk_object); + + + /* X Screen number */ + ctk_object->txt_screen_num = gtk_label_new(""); + gtk_label_set_selectable(GTK_LABEL(ctk_object->txt_screen_num), TRUE); + gtk_misc_set_alignment(GTK_MISC(ctk_object->txt_screen_num), 0.0f, 0.5f); + + /* X Screen depth */ + ctk_object->mnu_screen_depth = gtk_option_menu_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->mnu_screen_depth, + __screen_depth_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_screen_depth), "changed", + G_CALLBACK(screen_depth_changed), + (gpointer) ctk_object); + + /* Screen Position Type (Absolute/Relative Menu) */ + ctk_object->mnu_screen_position_type = gtk_option_menu_new(); + menu = gtk_menu_new(); + menu_item = gtk_menu_item_new_with_label("Absolute"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Right of"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Left of"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Above"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + menu_item = gtk_menu_item_new_with_label("Below"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + // XXX Add better support for this later. + //menu_item = gtk_menu_item_new_with_label("Relative to"); + //gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_type), menu); + ctk_config_set_tooltip(ctk_config, ctk_object->mnu_screen_position_type, + __screen_position_type_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_screen_position_type), + "changed", G_CALLBACK(screen_position_type_changed), + (gpointer) ctk_object); + + /* Screen Position Relative (Screen to be relative to) */ + ctk_object->mnu_screen_position_relative = gtk_option_menu_new(); + ctk_config_set_tooltip(ctk_config, + ctk_object->mnu_screen_position_relative, + __screen_position_relative_help); + g_signal_connect(G_OBJECT(ctk_object->mnu_screen_position_relative), + "changed", + G_CALLBACK(screen_position_relative_changed), + (gpointer) ctk_object); + + /* Screen Position Offset (Absolute position) */ + ctk_object->txt_screen_position_offset = gtk_entry_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->txt_screen_position_offset, + __screen_position_offset_help); + g_signal_connect(G_OBJECT(ctk_object->txt_screen_position_offset), + "activate", G_CALLBACK(screen_position_offset_activate), + (gpointer) ctk_object); + + /* X Screen metamode */ + ctk_object->btn_screen_metamode = gtk_button_new(); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_screen_metamode, + __screen_metamode_help); + g_signal_connect(G_OBJECT(ctk_object->btn_screen_metamode), "clicked", + G_CALLBACK(screen_metamode_clicked), + (gpointer) ctk_object); + + ctk_object->btn_screen_metamode_add = gtk_button_new_with_label("Add"); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_screen_metamode_add, + __screen_metamode_add_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_screen_metamode_add), "clicked", + G_CALLBACK(screen_metamode_add_clicked), + (gpointer) ctk_object); + + ctk_object->btn_screen_metamode_delete = + gtk_button_new_with_label("Delete"); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_screen_metamode_delete, + __screen_metamode_delete_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_screen_metamode_delete), + "clicked", + G_CALLBACK(screen_metamode_delete_clicked), + (gpointer) ctk_object); + + + /* Create the Validation dialog */ + ctk_object->dlg_validation_override = create_validation_dialog(ctk_object); + + + /* Create the Apply Validation dialog */ + ctk_object->dlg_validation_apply = + create_validation_apply_dialog(ctk_object); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_validation_apply), + FALSE); + + + /* Reset confirmation dialog */ + ctk_object->dlg_reset_confirm = gtk_dialog_new_with_buttons + ("Confirm Reset", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT + | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + ctk_object->btn_reset_cancel = + gtk_dialog_add_button(GTK_DIALOG(ctk_object->dlg_reset_confirm), + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_reset_confirm), + FALSE); + + + /* Display ModeSwitch confirmation dialog */ + ctk_object->dlg_display_confirm = gtk_dialog_new_with_buttons + ("Confirm ModeSwitch", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT + | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + NULL); + ctk_object->btn_display_apply_cancel = + gtk_dialog_add_button(GTK_DIALOG(ctk_object->dlg_display_confirm), + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_display_confirm), + FALSE); + + + /* Display confirm dialog text (Dynamically generated) */ + ctk_object->txt_display_confirm = gtk_label_new(""); + + + /* X config save dialog */ + ctk_object->dlg_xconfig_save = gtk_dialog_new_with_buttons + ("Save X Configuration", + GTK_WINDOW(gtk_widget_get_parent(GTK_WIDGET(ctk_object))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_SAVE, + GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + NULL); + gtk_dialog_set_default_response(GTK_DIALOG(ctk_object->dlg_xconfig_save), + GTK_RESPONSE_REJECT); + + ctk_object->btn_xconfig_preview = gtk_button_new(); + g_signal_connect(G_OBJECT(ctk_object->btn_xconfig_preview), "clicked", + G_CALLBACK(xconfig_preview_clicked), + (gpointer) ctk_object); + + ctk_object->txt_xconfig_save = gtk_text_view_new(); + gtk_text_view_set_left_margin + (GTK_TEXT_VIEW(ctk_object->txt_xconfig_save), 5); + + ctk_object->buf_xconfig_save = gtk_text_buffer_new(NULL); + gtk_text_view_set_buffer(GTK_TEXT_VIEW(ctk_object->txt_xconfig_save), + GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save)); + + ctk_object->scr_xconfig_save = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type + (GTK_SCROLLED_WINDOW(ctk_object->scr_xconfig_save), GTK_SHADOW_IN); + + ctk_object->txt_xconfig_file = gtk_entry_new(); + gtk_widget_set_size_request(ctk_object->txt_xconfig_file, 300, -1); + + ctk_object->btn_xconfig_file = gtk_button_new_with_label("Browse..."); + g_signal_connect(G_OBJECT(ctk_object->btn_xconfig_file), "clicked", + G_CALLBACK(xconfig_file_clicked), + (gpointer) ctk_object); + ctk_object->dlg_xconfig_file = gtk_file_selection_new + ("Please select the X configuration file"); + + + + /* Apply button */ + ctk_object->btn_apply = gtk_button_new_with_label("Apply"); + gtk_widget_set_sensitive(ctk_object->btn_apply, False); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_apply, + __apply_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_apply), "clicked", + G_CALLBACK(apply_clicked), + (gpointer) ctk_object); + + + /* Probe button */ + ctk_object->btn_probe = gtk_button_new_with_label("Detect Displays"); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_probe, + __probe_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_probe), "clicked", + G_CALLBACK(probe_clicked), + (gpointer) ctk_object); + + + /* Advanced button */ + ctk_object->btn_advanced = gtk_button_new_with_label("Advanced..."); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_advanced, + __advanced_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_advanced), "clicked", + G_CALLBACK(advanced_clicked), + (gpointer) ctk_object); + + + /* Reset button */ + ctk_object->btn_reset = gtk_button_new_with_label("Reset"); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_reset, + __reset_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_reset), "clicked", + G_CALLBACK(reset_clicked), + (gpointer) ctk_object); + + + /* Save button */ + ctk_object->btn_save = gtk_button_new_with_label + ("Save to X Configuration File"); + ctk_config_set_tooltip(ctk_config, ctk_object->btn_save, + __save_button_help); + g_signal_connect(G_OBJECT(ctk_object->btn_save), "clicked", + G_CALLBACK(save_clicked), + (gpointer) ctk_object); + + + + /**** + * + * Pack the widgets + * + ***/ + + { /* Layout section */ + + frame = gtk_frame_new("Layout"); + hbox = gtk_hbox_new(FALSE, 5); /* main panel */ + vbox = gtk_vbox_new(FALSE, 5); /* layout panel */ + gtk_box_pack_start(GTK_BOX(ctk_object), hbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); + + hbox = gtk_hbox_new(FALSE, 5); /* layout panel */ + gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(frame), hbox); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); + + /* Pack the layout widget */ + gtk_box_pack_start(GTK_BOX(vbox), ctk_object->obj_layout, + FALSE, FALSE, 0); + + /* Xinerama checkbox */ + gtk_box_pack_start(GTK_BOX(vbox), ctk_object->chk_xinerama_enabled, + FALSE, FALSE, 0); + } + + + /* Scrolled window */ + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(ctk_object), scrolled_window, TRUE, TRUE, 0); + gtk_widget_set_size_request(scrolled_window, -1, 200); + + viewport = gtk_viewport_new(NULL, NULL); + gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); + gtk_container_add(GTK_CONTAINER(scrolled_window), viewport); + + + /* Panel for the display/screen sections */ + vpanel = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(viewport), vpanel); + + + { /* Display section */ + GtkWidget *longest_hbox; + + /* Create the display frame */ + frame = gtk_frame_new("Display"); + ctk_object->display_frame = frame; + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vpanel), hbox, FALSE, FALSE, 0); + + /* Generate the major vbox for the display section */ + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + /* Display Configuration */ + hbox = gtk_hbox_new(FALSE, 5); + /* XXX Pack widget later. Create it here so we can get its size */ + longest_hbox = hbox; + label = gtk_label_new("Configuration:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_size_request(label, &req); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_config, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_display_config, + FALSE, FALSE, 0); + + /* Display model name */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("Model:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_model, + TRUE, TRUE, 0); + + /* Pack the display configuration line */ + gtk_box_pack_start(GTK_BOX(vbox), longest_hbox, FALSE, TRUE, 0); + + /* Display resolution and refresh dropdowns */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + label = gtk_label_new("Resolution:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->mnu_display_resolution, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->mnu_display_refresh, + TRUE, TRUE, 0); + ctk_object->box_display_resolution = hbox; + + /* Modeline modename info */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("Mode Name:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_modename, + FALSE, FALSE, 0); + ctk_object->box_display_modename = hbox; + + /* Display positioning */ + label = gtk_label_new("Position:"); + hbox = gtk_hbox_new(FALSE, 5); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->mnu_display_position_type, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->mnu_display_position_relative, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->txt_display_position_offset, + TRUE, TRUE, 0); + ctk_object->box_display_position = hbox; + + /* Display panning text entry */ + label = gtk_label_new("Panning:"); + hbox = gtk_hbox_new(FALSE, 5); + + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_panning, + TRUE, TRUE, 0); + ctk_object->box_display_panning = hbox; + + } /* Display sub-section */ + + + { /* X Screen */ + + /* Create the X screen frame */ + frame = gtk_frame_new("X Screen"); + ctk_object->screen_frame = frame; + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vpanel), hbox, FALSE, FALSE, 5); + + /* Generate the major vbox for the display section */ + vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + /* X Screen number */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("Screen Number:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_size_request(label, &req); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_screen_num, + TRUE, TRUE, 0); + + /* X Screen depth dropdown */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("Color Depth:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->mnu_screen_depth, + TRUE, TRUE, 0); + ctk_object->box_screen_depth = hbox; + + /* X Screen positioning */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("Position:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->mnu_screen_position_type, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->mnu_screen_position_relative, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->txt_screen_position_offset, + TRUE, TRUE, 0); + ctk_object->box_screen_position = hbox; + + /* X Screen metamode drop down & buttons */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + label = gtk_label_new("MetaMode:"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_widget_set_size_request(label, req.width, -1); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->btn_screen_metamode, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->btn_screen_metamode_add, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->btn_screen_metamode_delete, + TRUE, TRUE, 0); + ctk_object->box_screen_metamode = hbox; + + } /* X Screen sub-section */ + + + { /* Buttons */ + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_object), hbox, FALSE, FALSE, 0); + + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_reset, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_advanced, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_probe, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_apply, + FALSE, FALSE, 0); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_object), hbox, FALSE, FALSE, 0); + + gtk_box_pack_end(GTK_BOX(hbox), ctk_object->btn_save, + FALSE, FALSE, 0); + } + + + { /* Dialogs */ + + /* Display Configuration Dialog */ + label = gtk_label_new("How should this display device be configured?"); + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 20); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_config)->vbox), + hbox, TRUE, TRUE, 20); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_config)->vbox), + ctk_object->rad_display_config_disabled, FALSE, FALSE, 0); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_config)->vbox), + ctk_object->rad_display_config_xscreen, FALSE, FALSE, 0); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_config)->vbox), + ctk_object->rad_display_config_twinview, FALSE, FALSE, 0); + gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_display_config)->vbox); + + /* Display Disable Dialog */ + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_disable, + FALSE, FALSE, 20); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_disable)->vbox), + hbox, TRUE, TRUE, 20); + gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_display_disable)->vbox); + + /* Reset Confirm Dialog */ + label = gtk_label_new("Do you really want to reset the " + "configuration?"); + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 20); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_reset_confirm)->vbox), + hbox, TRUE, TRUE, 20); + gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_reset_confirm)->vbox); + + /* Apply Confirm Dialog */ + hbox = gtk_hbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->txt_display_confirm, + TRUE, TRUE, 20); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_display_confirm)->vbox), + hbox, TRUE, TRUE, 20); + gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_display_confirm)->vbox); + + /* X Config Save Dialog */ + gtk_dialog_set_has_separator(GTK_DIALOG(ctk_object->dlg_xconfig_save), + TRUE); + + /* Preview button */ + hbox = gtk_hbox_new(FALSE, 0); + hbox2 = gtk_hbox_new(FALSE, 0); + + gtk_box_pack_start(GTK_BOX(hbox), ctk_object->btn_xconfig_preview, + FALSE, FALSE, 5); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox), + hbox, FALSE, FALSE, 5); + + /* Preview window */ + hbox = gtk_hbox_new(TRUE, 0); + + gtk_container_add(GTK_CONTAINER(ctk_object->scr_xconfig_save), + ctk_object->txt_xconfig_save); + gtk_box_pack_start(GTK_BOX(hbox), + ctk_object->scr_xconfig_save, + TRUE, TRUE, 5); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox), + hbox, + TRUE, TRUE, 0); + ctk_object->box_xconfig_save = hbox; + + /* Filename */ + hbox = gtk_hbox_new(FALSE, 0); + hbox2 = gtk_hbox_new(FALSE, 5); + + gtk_box_pack_end(GTK_BOX(hbox2), ctk_object->btn_xconfig_file, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox2), ctk_object->txt_xconfig_file, + TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(hbox), hbox2, + TRUE, TRUE, 5); + gtk_box_pack_start + (GTK_BOX(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox), + hbox, + FALSE, FALSE, 5); + + gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox); + } + + + /* Show the GUI */ + gtk_widget_show_all(GTK_WIDGET(ctk_object)); + + + /* Setup the GUI */ + setup_layout_frame(ctk_object); + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + + return GTK_WIDGET(ctk_object); + +} /* ctk_display_config_new() */ + + + +/** ctk_display_config_create_help() ********************************* + * + * Creates the Display Configuration help page. + * + **/ + +GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *table, + CtkDisplayConfig *ctk_object) +{ + GtkTextIter i; + GtkTextBuffer *b; + + + b = gtk_text_buffer_new(table); + + gtk_text_buffer_get_iter_at_offset(b, &i, 0); + + ctk_help_title(b, &i, "Display Configuration Help"); + ctk_help_para(b, &i, "This page gives access to configuration of " + "the X Server's display devices."); + + ctk_help_para(b, &i, ""); + ctk_help_heading(b, &i, "Layout Section"); + ctk_help_para(b, &i, "This section shows information and configuration " + "settings for the X server layout."); + ctk_help_heading(b, &i, "Layout Image"); + ctk_help_para(b, &i, "The layout image shows the geomertic relationship " + "that display devices and X screens have to each other. " + "You may drag display devices around to reposition them. " + "When in advanced view, the display's panning domain may " + "be resized by holding shift while dragging."); + ctk_help_heading(b, &i, "Enable Xinerama"); + ctk_help_para(b, &i, "%s. This setting is only available when multiple " + "X screens are present.", __layout_xinerama_button_help); + + + ctk_help_para(b, &i, ""); + ctk_help_heading(b, &i, "Display Section"); + ctk_help_para(b, &i, "This section shows information and configuration " + "settings for the currently selected display device."); + ctk_help_heading(b, &i, "Model"); + ctk_help_para(b, &i, "The Model name is the name of the display device."); + ctk_help_heading(b, &i, "Resolution"); + ctk_help_para(b, &i, __dpy_resolution_mnu_help); + ctk_help_heading(b, &i, "Refresh"); + ctk_help_para(b, &i, "The Refresh drop-down is to the right of the " + "Resolution drop-down. %s", __dpy_refresh_mnu_help); + ctk_help_heading(b, &i, "Mode Name"); + ctk_help_para(b, &i, "The Mode name is the name of the modeline that is " + "currently chosen for the selected display device. " + "(Advanced view only)"); + ctk_help_heading(b, &i, "Position Type"); + ctk_help_para(b, &i, __dpy_position_type_help); + ctk_help_heading(b, &i, "Position Relative"); + ctk_help_para(b, &i, __dpy_position_relative_help); + ctk_help_heading(b, &i, "Position Offset"); + ctk_help_para(b, &i, __dpy_position_offset_help); + ctk_help_heading(b, &i, "Panning"); + ctk_help_para(b, &i, "%s. (Advanced view only)", __dpy_panning_help); + + + ctk_help_para(b, &i, ""); + ctk_help_heading(b, &i, "Screen Section"); + ctk_help_para(b, &i, "This section shows information and configuration " + "settings for the currently selected X Screen."); + ctk_help_heading(b, &i, "Screen Depth"); + ctk_help_para(b, &i, __screen_depth_help); + ctk_help_heading(b, &i, "Position Type"); + ctk_help_para(b, &i, __screen_position_type_help); + ctk_help_heading(b, &i, "Position Relative"); + ctk_help_para(b, &i, __screen_position_relative_help); + ctk_help_heading(b, &i, "Position Offset"); + ctk_help_para(b, &i, __screen_position_offset_help); + ctk_help_heading(b, &i, "MetaMode Selection"); + ctk_help_para(b, &i, "%s. (Advanced view only)", __screen_metamode_help); + ctk_help_heading(b, &i, "Add Metamode"); + ctk_help_para(b, &i, "%s. (Advanced view only)", + __screen_metamode_add_button_help); + ctk_help_heading(b, &i, "Delete Metamode"); + ctk_help_para(b, &i, "%s. (Advanced view only)", + __screen_metamode_delete_button_help); + + + ctk_help_para(b, &i, ""); + ctk_help_heading(b, &i, "Buttons"); + ctk_help_heading(b, &i, "Probe"); + ctk_help_para(b, &i, __apply_button_help); + ctk_help_heading(b, &i, "Detect Displays"); + ctk_help_para(b, &i, __probe_button_help); + ctk_help_heading(b, &i, "Advanced/Basic..."); + ctk_help_para(b, &i, "%s. The Basic view modifies the currently active " + "MetaMode for an X screen, while the Advanced view exposes " + "all the MetaModes available on an X screen, and lets you " + "modify each of them", __advanced_button_help); + ctk_help_heading(b, &i, "Reset"); + ctk_help_para(b, &i, __reset_button_help); + ctk_help_heading(b, &i, "Save to X Configuration File"); + ctk_help_para(b, &i, __save_button_help); + + ctk_help_finish(b); + + return b; + +} /* ctk_display_config_create_help() */ + + + +/* Widget setup & helper functions ***********************************/ + + +/** setup_layout_frame() ********************************************* + * + * Sets up the layout frame to reflect the currently selected layout. + * + **/ + +static void setup_layout_frame(CtkDisplayConfig *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + int num_screens; + + + /* Only allow Xinerama when there are multiple X Screens */ + num_screens = 0; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + num_screens += gpu->num_screens; + } + + /* Unselect Xinerama if only one (or no) X Screen */ + if (num_screens <= 1) { + layout->xinerama_enabled = 0; + gtk_widget_hide(ctk_object->chk_xinerama_enabled); + return; + } + gtk_widget_show(ctk_object->chk_xinerama_enabled); + + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->chk_xinerama_enabled), + G_CALLBACK(xinerama_state_toggled), (gpointer) ctk_object); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_object->chk_xinerama_enabled), + layout->xinerama_enabled); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->chk_xinerama_enabled), + G_CALLBACK(xinerama_state_toggled), (gpointer) ctk_object); + +} /* setup_layout_frame() */ + + + +/** setup_display_modename() ***************************************** + * + * Updates the modeline modename of the selected display + * + **/ + +static void setup_display_modename(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + if (!display || !display->screen || !ctk_object->advanced_mode) { + gtk_widget_hide(ctk_object->box_display_modename); + return; + } + gtk_widget_show(ctk_object->box_display_modename); + + + if (!display->cur_mode || !display->cur_mode->modeline) { + gtk_label_set(GTK_LABEL(ctk_object->txt_display_modename), ""); + gtk_widget_set_sensitive(ctk_object->box_display_modename, FALSE); + return; + } + gtk_widget_set_sensitive(ctk_object->box_display_modename, TRUE); + + + gtk_label_set(GTK_LABEL(ctk_object->txt_display_modename), + display->cur_mode->modeline->data.identifier); + +} /* setup_display_modename() */ + + + +/** setup_display_config() ******************************************* + * + * Updates the text of the configure button to reflect the current + * setting of the selected display. + * + **/ + +static void setup_display_config(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!display) return; + + if (!display->screen) { + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_config), + "Disabled"); + } else if (display->screen->num_displays == 1) { + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_config), + "Separate X Screen"); + } else { + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_config), + "TwinView"); + } + +} /* setup_display_config() */ + + + +/** setup_display_refresh_dropdwon() ********************************* + * + * Generates the refresh rate dropdown based on the currently selected + * display. + * + **/ + +static void setup_display_refresh_dropdown(CtkDisplayConfig *ctk_object) +{ + GtkWidget *menu; + GtkWidget *menu_item; + nvModeLinePtr modeline; + nvModeLinePtr auto_modeline; + nvModeLinePtr modelines; + nvModeLinePtr cur_modeline; + float cur_rate; /* Refresh Rate */ + int cur_idx = 0; /* Currently selected modeline */ + + gchar *name; /* Modeline's label for the dropdown menu */ + + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + + /* Get selection information */ + if (!display || + !display->cur_mode || + !display->cur_mode->modeline) { + goto fail; + } + modelines = display->modelines; + cur_modeline = display->cur_mode->modeline; + cur_rate = GET_MODELINE_REFRESH_RATE(cur_modeline); + + + /* Create the menu index -> modeline pointer lookup table */ + if (ctk_object->refresh_table) { + free(ctk_object->refresh_table); + ctk_object->refresh_table_len = 0; + } + ctk_object->refresh_table = + (nvModeLinePtr *)calloc(1, display->num_modelines + * sizeof(nvModeLinePtr)); + if (!ctk_object->refresh_table) { + goto fail; + } + + + /* Generate the refresh dropdown */ + menu = gtk_menu_new(); + + + /* Special case the 'nvidia-auto-select' mode. */ + if (IS_NVIDIA_DEFAULT_MODE(cur_modeline)) { + menu_item = gtk_menu_item_new_with_label("Auto"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + ctk_object->refresh_table[ctk_object->refresh_table_len++] = + cur_modeline; + modelines = NULL; /* Skip building rest of refresh dropdown */ + } + + /* Generate the refresh rate dropdown from the modelines list */ + auto_modeline = NULL; + for (modeline = modelines; modeline; modeline = modeline->next) { + + float modeline_rate; + nvModeLinePtr m; + int count_ref; /* # modelines with similar refresh rates */ + int num_ref; /* Modeline # in a group of similar refresh rates */ + int is_doublescan; + int is_interlaced; + + + /* Ignore modelines of different resolution */ + if (modeline->data.hdisplay != cur_modeline->data.hdisplay || + modeline->data.vdisplay != cur_modeline->data.vdisplay) { + continue; + } + + /* Ignore special modes */ + if (IS_NVIDIA_DEFAULT_MODE(modeline)) { + continue; + } + + modeline_rate = GET_MODELINE_REFRESH_RATE(modeline); + is_doublescan = (modeline->data.flags & V_DBLSCAN); + is_interlaced = (modeline->data.flags & V_INTERLACE); + + name = g_strdup_printf("%.0f Hz", modeline_rate); + + + /* Get a unique number for this modeline */ + count_ref = 0; /* # modelines with similar refresh rates */ + num_ref = 0; /* Modeline # in a group of similar refresh rates */ + for (m = modelines; m; m = m->next) { + float m_rate = GET_MODELINE_REFRESH_RATE(m); + gchar *tmp = g_strdup_printf("%.0f Hz", m_rate); + + if (!IS_NVIDIA_DEFAULT_MODE(m) && + m->data.hdisplay == modeline->data.hdisplay && + m->data.vdisplay == modeline->data.vdisplay && + !g_ascii_strcasecmp(tmp, name) && + m != auto_modeline) { + + count_ref++; + /* Modelines with similar refresh rates get a unique # (num_ref) */ + if (m == modeline) { + num_ref = count_ref; /* This modeline's # */ + } + } + g_free(tmp); + } + + /* Is default refresh rate for resolution */ + if (!ctk_object->refresh_table_len) { + auto_modeline = modeline; + g_free(name); + name = g_strdup("Auto"); + + /* In advanced mode, all modelines are selectable */ + } else if (count_ref > 1 && ctk_object->advanced_mode) { + gchar *tmp; + tmp = g_strdup_printf("%s (%d)", name, num_ref); + g_free(name); + name = tmp; + + /* in simple mode only show one refresh rate */ + } else if (num_ref > 1 && !ctk_object->advanced_mode) { + continue; + } + + + /* Add "DoubleScan" and "Interlace" information */ + if (g_ascii_strcasecmp(name, "Auto")) { + gchar *extra = NULL; + gchar *tmp; + + if (modeline->data.flags & V_DBLSCAN) { + extra = g_strdup_printf("DoubleScan"); + } + + if (modeline->data.flags & V_INTERLACE) { + if (extra) { + tmp = g_strdup_printf("%s, Interlace", extra); + g_free(extra); + extra = tmp; + } else { + extra = g_strdup_printf("Interlace"); + } + } + + if (extra) { + tmp = g_strdup_printf("%s (%s)", name, extra); + g_free(extra); + g_free(name); + name = tmp; + } + } + + + /* Keep track of the selected modeline */ + if (cur_modeline == modeline) { + cur_idx = ctk_object->refresh_table_len; + + /* Find a close match to the selected modeline */ + } else if (ctk_object->refresh_table_len && + ctk_object->refresh_table[cur_idx] != cur_modeline) { + + /* Found a better resolution */ + if (modeline->data.hdisplay == cur_modeline->data.hdisplay && + modeline->data.vdisplay == cur_modeline->data.vdisplay) { + + float prev_rate = GET_MODELINE_REFRESH_RATE(ctk_object->refresh_table[cur_idx]); + float rate = GET_MODELINE_REFRESH_RATE(modeline); + + if (ctk_object->refresh_table[cur_idx]->data.hdisplay != cur_modeline->data.hdisplay || + ctk_object->refresh_table[cur_idx]->data.vdisplay != cur_modeline->data.vdisplay) { + cur_idx = ctk_object->refresh_table_len; + } + + /* Found a better refresh rate */ + if (rate == cur_rate && prev_rate != cur_rate) { + cur_idx = ctk_object->refresh_table_len; + } + } + } + + + /* Add the modeline entry to the dropdown */ + menu_item = gtk_menu_item_new_with_label(name); + g_free(name); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + ctk_object->refresh_table[ctk_object->refresh_table_len++] = modeline; + } + + + + + /* Setup the menu and select the current modeline */ + g_signal_handlers_block_by_func(G_OBJECT(ctk_object->mnu_display_refresh), + G_CALLBACK(display_refresh_changed), + (gpointer) ctk_object); + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_display_refresh), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(ctk_object->mnu_display_refresh), cur_idx); + gtk_widget_set_sensitive(ctk_object->mnu_display_refresh, True); + + g_signal_handlers_unblock_by_func(G_OBJECT(ctk_object->mnu_display_refresh), + G_CALLBACK(display_refresh_changed), + (gpointer) ctk_object); + + + /* If dropdown only has one item, disable it */ + if (ctk_object->refresh_table_len > 1) { + gtk_widget_set_sensitive(ctk_object->mnu_display_refresh, True); + } else { + gtk_widget_set_sensitive(ctk_object->mnu_display_refresh, False); + } + + + /* Update the nodename label */ + setup_display_modename(ctk_object); + return; + + + /* Handle failures */ + fail: + gtk_widget_set_sensitive(ctk_object->mnu_display_refresh, False); + + setup_display_modename(ctk_object); + +} /* setup_display_refresh_dropdown() */ + + + +/** setup_display_resolution_dropdwon() ****************************** + * + * Generates the resolution dropdown based on the currently selected + * display. + * + **/ + +static void setup_display_resolution_dropdown(CtkDisplayConfig *ctk_object) +{ + GtkWidget *menu; + GtkWidget *menu_item; + + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + nvModeLinePtr modeline; + nvModeLinePtr modelines; + nvModeLinePtr cur_modeline; + + int cur_idx = 0; /* Currently selected modeline (resolution) */ + + + + /* Get selection information */ + if (!display || !display->screen || !display->cur_mode) { + gtk_widget_hide(ctk_object->box_display_resolution); + return; + } + gtk_widget_show(ctk_object->box_display_resolution); + gtk_widget_set_sensitive(ctk_object->box_display_resolution, TRUE); + + + cur_modeline = display->cur_mode->modeline; + + + /* Create the modeline lookup table for the dropdown */ + if (ctk_object->resolution_table) { + free(ctk_object->resolution_table); + ctk_object->resolution_table_len = 0; + } + ctk_object->resolution_table = + (nvModeLinePtr *)calloc(1, (display->num_modelines +1) + *sizeof(nvModeLinePtr)); + if (!ctk_object->resolution_table) { + goto fail; + } + + + /* Start the menu generation */ + menu = gtk_menu_new(); + + + /* Add the off mode */ + menu_item = gtk_menu_item_new_with_label("Off"); + if (display->screen->num_displays <= 1) { + gtk_widget_set_sensitive(menu_item, False); + } + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + ctk_object->resolution_table[ctk_object->resolution_table_len++] = NULL; + + + /* Add the 'nvidia-auto-select' modeline */ + modelines = display->modelines; + if (IS_NVIDIA_DEFAULT_MODE(modelines)) { + menu_item = gtk_menu_item_new_with_label("Auto"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + ctk_object->resolution_table[ctk_object->resolution_table_len++] = + modelines; + modelines = modelines->next; + } + + /* Set the selected modeline index */ + if (cur_modeline) { + cur_idx = 1; /* Modeline is set, start off as 'nvidia-auto-select' */ + } else { + cur_idx = 0; /* Modeline not set, start off as 'off'. */ + } + + + /* Generate the resolution menu */ + modeline = modelines; + while (modeline) { + nvModeLinePtr m; + gchar *name; + + /* Find the first resolution that matches the current res W & H */ + m = modelines; + while (m != modeline) { + if (modeline->data.hdisplay == m->data.hdisplay && + modeline->data.vdisplay == m->data.vdisplay) { + break; + } + m = m->next; + } + + /* Add resolution if it is the first of its kind */ + if (m == modeline) { + + /* Set the current modeline idx if not already set by default */ + if (cur_modeline) { + if (!IS_NVIDIA_DEFAULT_MODE(cur_modeline) && + cur_modeline->data.hdisplay == modeline->data.hdisplay && + cur_modeline->data.vdisplay == modeline->data.vdisplay) { + cur_idx = ctk_object->resolution_table_len; + } + } + + name = g_strdup_printf("%dx%d", modeline->data.hdisplay, + modeline->data.vdisplay); + menu_item = gtk_menu_item_new_with_label(name); + g_free(name); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + ctk_object->resolution_table[ctk_object->resolution_table_len++] = + modeline; + } + modeline = modeline->next; + } + + + /* Setup the menu and select the current mode */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->mnu_display_resolution), + G_CALLBACK(display_resolution_changed), (gpointer) ctk_object); + + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_display_resolution), menu); + + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_display_resolution), cur_idx); + + /* If dropdown has only one item, disable menu selection */ + if (ctk_object->resolution_table_len > 1) { + gtk_widget_set_sensitive(ctk_object->mnu_display_resolution, True); + } else { + gtk_widget_set_sensitive(ctk_object->mnu_display_resolution, False); + } + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->mnu_display_resolution), + G_CALLBACK(display_resolution_changed), (gpointer) ctk_object); + + /* Update refresh dropdown */ + setup_display_refresh_dropdown(ctk_object); + return; + + + + /* Handle failures */ + fail: + + gtk_option_menu_remove_menu + (GTK_OPTION_MENU(ctk_object->mnu_display_resolution)); + + gtk_widget_set_sensitive(ctk_object->mnu_display_resolution, False); + + setup_display_refresh_dropdown(ctk_object); + +} /* setup_display_resolution_dropdown() */ + + + +/** setup_display_position_type() ************************************ + * + * Sets up the display position type dropdown to reflect the position + * settings for the currently selected display (absolute/relative/ + * none). + * + **/ + +static void setup_display_position_type(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Handle cases where the position type should be hidden */ + if (!display || !display->screen || !display->cur_mode) { + gtk_widget_hide(ctk_object->mnu_display_position_type); + return; + } + gtk_widget_show(ctk_object->mnu_display_position_type); + + + /* Set absolute/relative positioning */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->mnu_display_position_type), + G_CALLBACK(display_position_type_changed), (gpointer) ctk_object); + + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_type), + display->cur_mode->position_type); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->mnu_display_position_type), + G_CALLBACK(display_position_type_changed), (gpointer) ctk_object); + +} /* setup_display_position_type() */ + + + +/** setup_display_position_relative() ******************************** + * + * Setup which display the selected display is relative to. + * + **/ + +static void setup_display_position_relative(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display; + nvDisplayPtr relative_to; + int idx; + int selected_idx; + GtkWidget *menu; + GtkWidget *menu_item; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!display || !display->screen || !display->cur_mode || !display->gpu) { + return; + } + + + /* Allocate the display lookup table for the dropdown */ + if (ctk_object->display_position_table) { + free(ctk_object->display_position_table); + } + + ctk_object->display_position_table_len = + display->screen->num_displays -1; + + ctk_object->display_position_table = + (nvDisplayPtr *)calloc(1, ctk_object->display_position_table_len * + sizeof(nvDisplayPtr)); + + if (!ctk_object->display_position_table) { + ctk_object->display_position_table_len = 0; + gtk_widget_hide(ctk_object->mnu_display_position_relative); + return; + } + + + /* Generate the lookup table and display dropdown */ + idx = 0; + selected_idx = 0; + menu = gtk_menu_new(); + for (relative_to = display->gpu->displays; + relative_to; + relative_to = relative_to->next) { + + if (relative_to == display || relative_to->screen != display->screen) { + continue; + } + + if (relative_to == display->cur_mode->relative_to) { + selected_idx = idx; + } + + ctk_object->display_position_table[idx] = relative_to; + + menu_item = gtk_menu_item_new_with_label(relative_to->name); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + idx++; + } + + + /* Set the menu and the selected display */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->mnu_display_position_relative), + G_CALLBACK(display_position_relative_changed), (gpointer) ctk_object); + + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_display_position_relative), menu); + + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_relative), + selected_idx); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->mnu_display_position_relative), + G_CALLBACK(display_position_relative_changed), (gpointer) ctk_object); + + + /* Disable the widget if there is only one possibility */ + gtk_widget_set_sensitive + (ctk_object->mnu_display_position_relative, + (idx > 1)); + + + /* Handle cases where the position relative dropdown should be hidden */ + if (display->cur_mode->position_type == CONF_ADJ_ABSOLUTE) { + gtk_widget_hide(ctk_object->mnu_display_position_relative); + return; + } + gtk_widget_show(ctk_object->mnu_display_position_relative); + +} /* setup_display_position_relative() */ + + + +/** setup_display_position_offset() ********************************** + * + * Sets up the display position offset text entry to reflect the + * currently selected display device. + * + **/ + +static void setup_display_position_offset(CtkDisplayConfig *ctk_object) +{ + char *tmp_str; + nvDisplayPtr display; + nvModePtr mode; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Handle cases where the position offset should be hidden */ + if (!display || !display->screen || !display->cur_mode || + !display->cur_mode->modeline || + display->cur_mode->position_type != CONF_ADJ_ABSOLUTE) { + gtk_widget_hide(ctk_object->txt_display_position_offset); + return; + } + gtk_widget_show(ctk_object->txt_display_position_offset); + + + /* Update the position text */ + mode = display->cur_mode; + + tmp_str = g_strdup_printf("%+d%+d", + mode->dim[X] - mode->metamode->edim[X], + mode->dim[Y] - mode->metamode->edim[Y]); + + gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_display_position_offset), + tmp_str); + + g_free(tmp_str); + +} /* setup_display_position_offset() */ + + + +/** setup_display_position() ***************************************** + * + * Sets up the display position section to reflect the position + * settings for the currently selected display (absolute/relative/ + * none). + * + **/ + +static void setup_display_position(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Hide the position box if this screen only has one display */ + if (!display || !display->screen || display->screen->num_displays <= 1) { + gtk_widget_hide(ctk_object->box_display_position); + return; + } + gtk_widget_show(ctk_object->box_display_position); + + + /* If the display is off, disable the position widgets */ + if (!display->cur_mode || !display->cur_mode->modeline) { + gtk_widget_set_sensitive(ctk_object->box_display_position, FALSE); + return; + } + gtk_widget_set_sensitive(ctk_object->box_display_position, TRUE); + + + /* Setup the display position widgets */ + setup_display_position_type(ctk_object); + + setup_display_position_relative(ctk_object); + + setup_display_position_offset(ctk_object); + +} /* setup_display_position */ + + + +/** setup_display_panning() ****************************************** + * + * Sets up the display panning text entry to reflect the currently + * selected display. + * + **/ + +static void setup_display_panning(CtkDisplayConfig *ctk_object) +{ + char *tmp_str; + nvDisplayPtr display; + nvModePtr mode; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + if (!display || !display->screen || !ctk_object->advanced_mode) { + gtk_widget_hide(ctk_object->box_display_panning); + return; + } + gtk_widget_show(ctk_object->box_display_panning); + + + if (!display->cur_mode || !display->cur_mode->modeline) { + gtk_widget_set_sensitive(ctk_object->box_display_panning, FALSE); + return; + } + gtk_widget_set_sensitive(ctk_object->box_display_panning, TRUE); + + + /* Update the panning text */ + mode = display->cur_mode; + tmp_str = g_strdup_printf("%dx%d", mode->pan[W], mode->pan[H]); + + gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_display_panning), + tmp_str); + g_free(tmp_str); + +} /* setup_display_panning */ + + + +/** setup_display_frame() ******************************************** + * + * Sets up the display frame to reflect the currently selected + * display. + * + **/ + +static void setup_display_frame(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gchar *type; + gchar *str; + + + + /* If no display is selected or there is no screen, hide the frame */ + if (!display) { + gtk_widget_set_sensitive(ctk_object->display_frame, False); + gtk_widget_hide(ctk_object->display_frame); + return; + } + + + /* Enable display widgets and setup widget information */ + gtk_widget_set_sensitive(ctk_object->display_frame, True); + + + /* Setup the display name */ + type = get_display_type_str(display->device_mask, 0); + str = g_strdup_printf("%s (%s)", display->name, type); + g_free(type); + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_model), str); + g_free(str); + + + /* Setp the seleted mode modename */ + setup_display_config(ctk_object); + + + /* Setp the seleted mode modename */ + setup_display_modename(ctk_object); + + + /* Setup display resolution menu */ + setup_display_resolution_dropdown(ctk_object); + + + /* Setup position */ + setup_display_position(ctk_object); + + + /* Setup panning */ + setup_display_panning(ctk_object); + + + gtk_widget_show(ctk_object->display_frame); + +} /* setup_display_frame() */ + + + +/** setup_screen_depth_dropdown() ************************************ + * + * Generates the color depth dropdown based on the currently selected + * display device. + * + **/ + +static void setup_screen_depth_dropdown(CtkDisplayConfig *ctk_object) +{ + GtkWidget *menu; + GtkWidget *menu_item; + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!display || !display->screen) { + gtk_widget_hide(ctk_object->box_screen_depth); + return; + } + + + menu = gtk_menu_new(); + menu_item = gtk_menu_item_new_with_label("Millions of Colors (32 bpp)"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + menu_item = gtk_menu_item_new_with_label("Thousands of Colors (16 bpp)"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + menu_item = gtk_menu_item_new_with_label("256 Colors (8 bpp)"); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + + g_signal_handlers_block_by_func(G_OBJECT(ctk_object->mnu_screen_depth), + G_CALLBACK(screen_depth_changed), + (gpointer) ctk_object); + + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_screen_depth), menu); + + if (display->screen->depth == 24) { + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_depth), 0); + } else if (display->screen->depth == 16) { + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_depth), 1); + } else { + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_depth), 2); + } + + g_signal_handlers_unblock_by_func(G_OBJECT(ctk_object->mnu_screen_depth), + G_CALLBACK(screen_depth_changed), + (gpointer) ctk_object); + + gtk_widget_show(ctk_object->box_screen_depth); + + return; + +} /* setup_screen_depth_dropdown() */ + + + +/** setup_screen_position_type() ************************************* + * + * Configures the screen position type dropdown to reflect the + * position setting for the currently selected screen. + * + **/ + +static void setup_screen_position_type(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Handle cases where the position type should be hidden */ + if (!display || !display->screen) { + gtk_widget_hide(ctk_object->mnu_screen_position_type); + return; + } + gtk_widget_show(ctk_object->mnu_screen_position_type); + + + /* Set the selected positioning type */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->mnu_screen_position_type), + G_CALLBACK(screen_position_type_changed), (gpointer) ctk_object); + + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_type), + display->screen->position_type); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->mnu_screen_position_type), + G_CALLBACK(screen_position_type_changed), (gpointer) ctk_object); + +} /* setup_screen_position_type() */ + + + +/** setup_screen_position_relative() ********************************* + * + * Setup which screen the selected screen is relative to. + * + **/ + +static void setup_screen_position_relative(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display; + nvScreenPtr screen; + nvScreenPtr relative_to; + nvGpuPtr gpu; + int idx; + int selected_idx; + GtkWidget *menu; + GtkWidget *menu_item; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!display || !display->cur_mode || !display->gpu || !display->screen) { + return; + } + + screen = display->screen; + + + /* Allocate the screen lookup table for the dropdown */ + if (ctk_object->screen_position_table) { + free(ctk_object->screen_position_table); + } + + /* Count the number of screens */ + ctk_object->screen_position_table_len = 0; + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + ctk_object->screen_position_table_len += gpu->num_screens; + } + + /* Don't count the current screen */ + if (ctk_object->screen_position_table_len >= 1) { + ctk_object->screen_position_table_len--; + } + + ctk_object->screen_position_table = + (nvScreenPtr *)calloc(1, ctk_object->screen_position_table_len * + sizeof(nvScreenPtr)); + + if (!ctk_object->screen_position_table) { + ctk_object->screen_position_table_len = 0; + gtk_widget_hide(ctk_object->mnu_screen_position_relative); + return; + } + + + /* Generate the lookup table and screen dropdown */ + idx = 0; + selected_idx = 0; + menu = gtk_menu_new(); + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + for (relative_to = gpu->screens; + relative_to; + relative_to = relative_to->next) { + + gchar *tmp_str; + + if (relative_to == screen) continue; + + if (relative_to == screen->relative_to) { + selected_idx = idx; + } + + ctk_object->screen_position_table[idx] = relative_to; + + tmp_str = g_strdup_printf("X Screen %d", + relative_to->scrnum); + menu_item = gtk_menu_item_new_with_label(tmp_str); + g_free(tmp_str); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + idx++; + } + } + + + /* Set the menu and the selected display */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_object->mnu_screen_position_relative), + G_CALLBACK(screen_position_relative_changed), (gpointer) ctk_object); + + gtk_option_menu_set_menu + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_relative), menu); + + gtk_option_menu_set_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_relative), + selected_idx); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_object->mnu_screen_position_relative), + G_CALLBACK(screen_position_relative_changed), (gpointer) ctk_object); + + + /* Disable the widget if there is only one possibility */ + gtk_widget_set_sensitive + (ctk_object->mnu_screen_position_relative, + (idx > 1)); + + + /* Handle cases where the position relative dropdown should be hidden */ + if (display->screen->position_type == CONF_ADJ_ABSOLUTE) { + gtk_widget_hide(ctk_object->mnu_screen_position_relative); + return; + } + gtk_widget_show(ctk_object->mnu_screen_position_relative); + +} /* setup_screen_position_relative() */ + + + +/** setup_screen_position_offset() *********************************** + * + * Sets up the screen position offset text entry to reflect the + * currently selected screen. + * + **/ + +static void setup_screen_position_offset(CtkDisplayConfig *ctk_object) +{ + char *tmp_str; + nvDisplayPtr display; + nvScreenPtr screen; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Handle cases where the position offset should be hidden */ + if (!display || !display->screen || + (display->screen->position_type != CONF_ADJ_ABSOLUTE && + display->screen->position_type != CONF_ADJ_RELATIVE)) { + gtk_widget_hide(ctk_object->txt_screen_position_offset); + return; + } + gtk_widget_show(ctk_object->txt_screen_position_offset); + + + /* Update the position text */ + screen = display->screen; + + tmp_str = g_strdup_printf("%+d%+d", screen->dim[X], screen->dim[Y]); + + gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_screen_position_offset), + tmp_str); + + g_free(tmp_str); + +} /* setup_screen_position_offset() */ + + + +/** setup_screen_position() ****************************************** + * + * Sets up the the screen position section to reflect the position + * settings for the currently selected screen. + * + **/ + +static void setup_screen_position(CtkDisplayConfig *ctk_object) +{ + nvGpuPtr gpu; + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + int num_screens; + + + /* Count the number of screens */ + num_screens = 0; + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + num_screens += gpu->num_screens; + } + + + /* Hide the position box if there is only one screen */ + if (!display || !display->screen || num_screens <= 1) { + gtk_widget_hide(ctk_object->box_screen_position); + return; + } + gtk_widget_show(ctk_object->box_screen_position); + + + /* Setup the screen position widgets */ + setup_screen_position_type(ctk_object); + + setup_screen_position_relative(ctk_object); + + setup_screen_position_offset(ctk_object); + +} /* setup_screen_position() */ + + + +/** setup_screen_metamode() ****************************************** + * + * Generates the metamode dropdown for the selected screen + * + **/ + +static void setup_screen_metamode(CtkDisplayConfig *ctk_object) +{ + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gchar *str; + + + if (!screen || !ctk_object->advanced_mode) { + gtk_widget_hide(ctk_object->box_screen_metamode); + return; + } + + + /* Update the meatamode selector button */ + str = g_strdup_printf("%d - ...", screen->cur_metamode_idx +1); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_screen_metamode), str); + g_free(str); + + /* Only allow deletes if there are more than 1 metamodes */ + gtk_widget_set_sensitive(ctk_object->btn_screen_metamode_delete, + ((screen->num_metamodes > 1) ? True : False)); + + gtk_widget_show(ctk_object->box_screen_metamode); + +} /* setup_screen_metamode() */ + + + +/** setup_screen_frame() ********************************************* + * + * Sets up the screen frame to reflect the currently selected screen. + * + **/ + +static void setup_screen_frame(CtkDisplayConfig *ctk_object) +{ + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gchar *tmp; + + + /* If there is no display or no screen selected, hide the frame */ + if (!display || !display->screen) { + gtk_widget_set_sensitive(ctk_object->screen_frame, False); + gtk_widget_hide(ctk_object->screen_frame); + return; + } + + + /* Enable display widgets and setup widget information */ + gtk_widget_set_sensitive(ctk_object->screen_frame, True); + + + /* Setup the screen number */ + tmp = g_strdup_printf("%d", display->screen->scrnum); + gtk_label_set_text(GTK_LABEL(ctk_object->txt_screen_num), tmp); + g_free(tmp); + + + /* Setup depth menu */ + setup_screen_depth_dropdown(ctk_object); + + + /* Setup position */ + setup_screen_position(ctk_object); + + + /* Setup metamode menu */ + setup_screen_metamode(ctk_object); + + + gtk_widget_show(ctk_object->screen_frame); + +} /* setup_screen_frame() */ + + + +/** validation_fix_crowded_metamodes() ******************************* + * + * Goes through each screen's metamodes and ensures that at most + * two display devices are active (have a modeline set) per metamode. + * This function also checks to make sure that there is at least + * one display device active for each metamode. + * + **/ + +static gint validation_fix_crowded_metamodes(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + nvDisplayPtr display; + nvModePtr first_mode = NULL; + nvModePtr mode; + int num; + int i, j; + + + /* Verify each metamode with the metamodes that come before it */ + for (i = 0; i < screen->num_metamodes; i++) { + + /* Keep track of the first mode in case we need to assign + * a default resolution + */ + first_mode = NULL; + + /* Count the number of display devices that have a mode + * set for this metamode. NULL out the modes of extra + * display devices once we've counted 2 display devices + * that have a (non NULL) mode set. + */ + num = 0; + for (display = screen->gpu->displays; + display; + display = display->next) { + + if (display->screen != screen) continue; + + /* Check the mode that corresponds with the metamode */ + mode = display->modes; + for (j = 0; j < i; j++) { + mode = mode->next; + } + + if (!first_mode) { + first_mode = mode; + } + + if (mode->modeline) { + num++; + } + + /* Disable extra modes */ + if (num > 2) { + ctk_display_layout_set_mode_modeline + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + mode, NULL); + + nv_info_msg(TAB, "Setting display device '%s' as Off " + "for MetaMode %d on Screen %d. (There are " + "already two active display devices for this " + "MetaMode.", display->name, i, screen->scrnum); + } + } + + /* Handle the case where a metamode has no active display device */ + if (!num) { + + /* There are other modelines, so we can safely delete this one */ + if (screen->num_metamodes > 1) { + + /* Delete the metamode */ + ctk_display_layout_delete_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), screen, i); + + nv_info_msg(TAB, "Removed MetaMode %d on Screen %d (No " + "active display devices)\n", i, + screen->scrnum); + + /* Since we just deleted the current metamode, we + * need to check the i'th metamode "again" since this + * is effectively the next metamode. + */ + i--; + + /* This is the only modeline, activate the first display */ + } else if (first_mode) { + + /* Select the first modeline in the modepool */ + ctk_display_layout_set_mode_modeline + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + first_mode, + first_mode->display->modelines); + + nv_info_msg(TAB, "Activating display device '%s' for MetaMode " + "%d on Screen %d. (Minimally, a Screen must have " + "one MetaMode with at least one active display " + "device.)", + first_mode->display->name, i, screen->scrnum); + } + } + } + + return 1; + +} /* validation_fix_crowded_metamodes() */ + + + +/** validation_fix_crowded_metamodes() ******************************* + * + * Goes through each screen's metamodes and ensures that each + * metamode string is unique. If a metamode string is not unique, + * the duplicate metamode is removed. + * + **/ + +static gint validation_remove_dupe_metamodes(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + int i, j; + char *metamode_str; + + /* Verify each metamode with the metamodes that come before it */ + for (i = 1; i < screen->num_metamodes; i++) { + + metamode_str = get_screen_metamode_str(screen, i, 0); + for (j = 0; j < i; j++) { + char *tmp; + tmp = get_screen_metamode_str(screen, j, 0); + + /* Remove duplicates */ + if (!strcmp(metamode_str, tmp)) { + + /* Delete the metamode */ + ctk_display_layout_delete_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), screen, i); + + nv_info_msg(TAB, "Removed MetaMode %d on Screen %d (Is " + "Duplicate of MetaMode %d)\n", i+1, screen->scrnum, + j+1); + g_free(tmp); + i--; /* Check the new metamode in i'th position */ + break; + } + g_free(tmp); + } + g_free(metamode_str); + } + + return 1; + +} /* validation_remove_dupe_metamodes() */ + + + +/** validation_auto_fix_screen() ************************************* + * + * Do what we can to make this screen conform to validation. + * + **/ + +static gint validation_auto_fix_screen(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + gint status = 1; + + status &= validation_fix_crowded_metamodes(ctk_object, screen); + status &= validation_remove_dupe_metamodes(ctk_object, screen); + + return status; + +} /* validation_auto_fix_screen() */ + + + +/** validation_auto_fix() ******************************************** + * + * Attempts to fix any problems found in the layout. Returns 1 if + * the layout is in a valid state when done. Returns 0 if there + * was a problem and the layout validation error could not be fixed + * by this function. + * + **/ + +static gint validation_auto_fix(CtkDisplayConfig *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + nvScreenPtr screen; + gint success = 1; + + + /* Auto fix each screen */ + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + if (!validation_auto_fix_screen(ctk_object, screen)) { + success = 0; + break; + } + } + } + + if (!success) { + nv_warning_msg("Failed to auto fix X configuration."); + /* XXX We should pop up a dialog box to let the user know + * there are still problems. + */ + } + + return success; + +} /* validation_auto_fix() */ + + + +/** validate_screen() ************************************************ + * + * This function returns NULL if the screen is found to be in a + * valid state. To be in a valid state the screen's metamodes must + * adhear to the following: + * + * - Have at least 1 display device activated for all metamodes. + * + * - Have at most 2 display devices activated for all metamodes. + * + * - All metamodes must be unique. + * + * - All metamodes must have a coherent offset (The top left corner + * of the bounding box of all the metamodes must be the same.) + * + * If the screen is found to be in an invalid state, a string + * describing the problem is returned. This string should be freed + * by the user when done with it. + * + **/ + +static gchar * validate_screen(nvScreenPtr screen) +{ + nvDisplayPtr display; + nvModePtr mode; + int i, j; + int num_displays; + char *metamode_str; + gchar *err_str = NULL; + gchar *tmp; + gchar *tmp2; + + gchar bullet[8]; // UTF8 Bullet string + int len; + + + + /* Convert the Unicode "Bullet" Character into a UTF8 string */ + len = g_unichar_to_utf8(0x2022, bullet); + bullet[len] = '\0'; + + + for (i = 0; i < screen->num_metamodes; i++) { + + /* Count the number of display devices used in the metamode */ + num_displays = 0; + for (display = screen->gpu->displays; + display; + display = display->next) { + + if (display->screen != screen) continue; + + mode = display->modes; + for (j = 0; j < i; j++) { + mode = mode->next; + } + if (mode->modeline) { + num_displays++; + } + } + + + /* There must be at least one display active in the metamode. */ + if (!num_displays) { + tmp = g_strdup_printf("%s MetaMode %d of Screen %d does not have " + "an active display devices.\n\n", + bullet, i+1, screen->scrnum); + tmp2 = g_strconcat((err_str ? err_str : ""), tmp, NULL); + g_free(err_str); + g_free(tmp); + err_str = tmp2; + } + + + /* There can be at most two displays active in the metamode. */ + if (num_displays > 2) { + tmp = g_strdup_printf("%s MetaMode %d of Screen %d has more than " + "two active display devices.\n\n", + bullet, i+1, screen->scrnum); + tmp2 = g_strconcat((err_str ? err_str : ""), tmp, NULL); + g_free(err_str); + g_free(tmp); + err_str = tmp2; + } + + + /* Verify that the metamode is unique */ + metamode_str = get_screen_metamode_str(screen, i, 0); + for (j = 0; j < i; j++) { + char *tmp = get_screen_metamode_str(screen, j, 0); + + /* Make sure the metamode is unique */ + if (!strcmp(metamode_str, tmp)) { + g_free(tmp); + tmp = g_strdup_printf("%s MetaMode %d of Screen %d is the " + "same as MetaMode %d. All MetaModes " + "must be unique.\n\n", + bullet, i+1, screen->scrnum, j+1); + tmp2 = g_strconcat((err_str ? err_str : ""), tmp, NULL); + g_free(err_str); + err_str = tmp2; + g_free(tmp); + break; + } + g_free(tmp); + } + g_free(metamode_str); + } + + return err_str; + +} /* validate_screen() */ + + + +/** validate_layout() ************************************************ + * + * Makes sure that the layout is ready for applying/saving. + * + * If the layout is found to be invalid the user is prompted to + * cancel the operation or to ignore and continue despite the + * errors. + * + **/ + +static int validate_layout(CtkDisplayConfig *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + nvScreenPtr screen; + gchar *err_strs = NULL; + gchar *err_str; + gchar *tmp; + gint result; + + + /* Validate each screen */ + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + err_str = validate_screen(screen); + if (err_str) { + tmp = g_strconcat((err_strs ? err_strs : ""), err_str, NULL); + g_free(err_strs); + g_free(err_str); + err_strs = tmp; + } + } + } + + /* Layout is valid */ + if (!err_strs) { + return 1; + } + + /* Layout is not valid, ask the user what we should do */ + gtk_text_buffer_set_text + (GTK_TEXT_BUFFER(ctk_object->buf_validation_override), err_strs, -1); + g_free(err_strs); + + gtk_widget_hide(ctk_object->box_validation_override_details); + gtk_window_resize(GTK_WINDOW(ctk_object->dlg_validation_override), + 350, 1); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_validation_override), + FALSE); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_validation_override_show), + "Show Details..."); + + /* Show the confirm dialog */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_validation_override), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_grab_focus(ctk_object->btn_validation_override_cancel); + gtk_widget_show(ctk_object->dlg_validation_override); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_validation_override)); + gtk_widget_hide(ctk_object->dlg_validation_override); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + /* User wants to ignore the validation warnings */ + return 1; + + case GTK_RESPONSE_APPLY: + /* User wants to auto fix the warnings */ + result = validation_auto_fix(ctk_object); + + /* Update the GUI to reflect any updates made by auto fix */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + return result; + + case GTK_RESPONSE_REJECT: + default: + /* User wants to heed the validation warnings */ + return 0; + } + + return 0; + +} /* validate_layout() */ + + + +/** validate_apply() ************************************************* + * + * Informs the user if we can't apply for whatever reason. This + * function returns FALSE if we should not continue the apply or + * TRUE if we should continue the apply operation(s). + * + **/ + +static gboolean validate_apply(CtkDisplayConfig *ctk_object) +{ + gint result; + + if (ctk_object->apply_possible) { + return TRUE; + } + + /* Show the "can't apply" dialog */ + + /* If we can't apply, let the user know. + * + * XXX - Show more details as to why exactly we can't apply. + */ + + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_validation_apply), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_show(ctk_object->dlg_validation_apply); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_validation_apply)); + gtk_widget_hide(ctk_object->dlg_validation_apply); + + + switch (result) { + case GTK_RESPONSE_ACCEPT: + /* User wants to ignore the validation warnings */ + return TRUE; + + case GTK_RESPONSE_REJECT: + default: + return FALSE; + } + + + return FALSE; + +} /* validate_apply() */ + + + +/* Callback handlers *************************************************/ + + +/** layout_selected_callback() *************************************** + * + * Called every time the user selects a new display from the layout + * image. + * + **/ + +void layout_selected_callback(nvLayoutPtr layout, void *data) +{ + CtkDisplayConfig *ctk_object = (CtkDisplayConfig *)data; + + + /* Reconfigure GUI to display information about the selected screen. */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + get_cur_screen_pos(ctk_object); + +} /* layout_selected_callback() */ + + + +/** layout_modified_callback() *************************************** + * + * Called every time the user moves a screen/display in the layout + * image. + * + **/ + +void layout_modified_callback(nvLayoutPtr layout, void *data) +{ + CtkDisplayConfig *ctk_object = (CtkDisplayConfig *)data; + + + /* Sync the information displayed by the GUI to match the settings + * of the currently selected display device. + */ + + /* Setup position */ + setup_display_position(ctk_object); + + + /* Setup panning */ + setup_display_panning(ctk_object); + + setup_screen_position(ctk_object); + + /* If the positioning of the X Screen changes, we cannot apply */ + check_screen_pos_changed(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* layout_modified_callback() */ + + + +/* Widget signal handlers ********************************************/ + + +/** do_enable_display_for_xscreen() ********************************** + * + * Adds the display device to a separate X Screen in the layout. + * + **/ + +void do_enable_display_for_xscreen(CtkDisplayConfig *ctk_object, + nvDisplayPtr display) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + nvScreenPtr screen; + nvMetaModePtr metamode; + nvModePtr mode; + int scrnum; + + + /* Get the next available screen number */ + scrnum = 0; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + scrnum++; + } + } + + + /* Get resources */ + screen = (nvScreenPtr)calloc(1, sizeof(nvScreen)); + metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode)); + if (!screen) return; + if (!metamode) { + free(screen); + return; + } + + + /* Setup the display */ + display->screen = screen; + + + /* Setup the mode */ + mode = display->modes; + + mode->modeline = display->modelines; + mode->metamode = metamode; + + /* XXX Hopefully display->modelines is 'nvidia-auto-select' */ + mode->dim[W] = display->modelines->data.hdisplay; + mode->dim[H] = display->modelines->data.vdisplay; + mode->pan[W] = mode->dim[W]; + mode->pan[H] = mode->dim[H]; + mode->position_type = CONF_ADJ_ABSOLUTE; + + + /* Setup the initial metamode */ + metamode->id = -1; + metamode->source = METAMODE_SOURCE_NVCONTROL; + metamode->switchable = True; + + + /* Setup the screen */ + screen->scrnum = scrnum; + screen->gpu = display->gpu; + screen->depth = 24; + screen->displays_mask = display->device_mask; + screen->num_displays = 1; + screen->metamodes = metamode; + screen->num_metamodes = 1; + screen->cur_metamode = metamode; + screen->cur_metamode_idx = 0; + + /* XXX Should we position it "RightOf" the right-most screen by default? */ + screen->dim[X] = mode->dim[X]; + screen->dim[Y] = mode->dim[Y]; + screen->position_type = CONF_ADJ_ABSOLUTE; + + + /* Add the screen at the end of the gpu's screen list */ + gpu = display->gpu; + gpu->screens = + (nvScreenPtr)xconfigAddListItem((GenericListPtr)gpu->screens, + (GenericListPtr)screen); + gpu->num_screens++; + + + /* We can't dynamically add new X Screens */ + ctk_object->apply_possible = FALSE; + +} /* do_enable_display_for_xscreen() */ + + + +/** do_enable_display_for_twinview() ********************************* + * + * Adds the display device to the TwinView setup that already exists + * on the GPU. + * + **/ + +static void do_enable_display_for_twinview(CtkDisplayConfig *ctk_object, + nvDisplayPtr display) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + nvMetaModePtr metamode; + nvModePtr mode; + guint new_mask; + + + /* Make sure a screen exists */ + gpu = display->gpu; + screen = gpu->screens; + + if (!screen) return; + + + /* Associate the display device with the screen */ + new_mask = screen->displays_mask | display->device_mask; + if (screen->handle) { + ReturnStatus ret; + ret = NvCtrlSetAttribute(screen->handle, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + new_mask); + if (ret != NvCtrlSuccess) { + nv_error_msg("Failed to associate display device '%s' with " + "X Screen %d!", display->name, screen->scrnum); + } else { + /* Make sure other parts of nvidia-settings get updated */ + ctk_event_emit(screen->ctk_event, 0, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, new_mask); + } + } + + + /* Fix up the display's metamode list */ + remove_modes_from_display(display); + + for (metamode = screen->metamodes; metamode; metamode = metamode->next) { + + /* Create the nvidia-auto-select mode fo the display */ + mode = parse_mode(display, "nvidia-auto-select"); + mode->metamode = metamode; + + /* Set the currently selected mode */ + if (metamode == screen->cur_metamode) { + display->cur_mode = mode; + } + + /* Position the new mode at the top right of the metamode */ + mode->position_type = CONF_ADJ_ABSOLUTE; + mode->dim[X] = metamode->dim[X] + metamode->dim[W]; + mode->dim[Y] = metamode->dim[Y]; + mode->pan[X] = mode->dim[X]; + mode->pan[Y] = mode->dim[Y]; + + /* Add the mode at the end of the display's mode list */ + display->modes = + (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes, + (GenericListPtr)mode); + display->num_modes++; + } + + + /* Link the screen and display together */ + screen->displays_mask = new_mask; + screen->num_displays++; + display->screen = screen; + +} /* do_enable_display_for_twinview() */ + + + +/** do_configure_display_for_xscreen() ******************************* + * + * Configures the display's GPU for Multiple X Screens + * + **/ + +static void do_configure_display_for_xscreen(CtkDisplayConfig *ctk_object, + nvDisplayPtr display) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + nvScreenPtr screen; + nvMetaModePtr metamode; + nvModePtr mode; + int scrnum = 0; + + + if (!display || !display->gpu) return; + + + /* Get the next available screen number */ + scrnum = 0; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + scrnum++; + } + } + + gpu = display->gpu; + + + /* Make sure there is just one display device per X Screen */ + for (display = gpu->displays; display; display = display->next) { + + nvScreenPtr new_screen; + + screen = display->screen; + if (!screen || screen->num_displays == 1) continue; + + /* Create a new X Screen for this display */ + new_screen = (nvScreenPtr)calloc(1, sizeof(nvScreen)); + if (!new_screen) continue; /* XXX Fail */ + + new_screen->gpu = gpu; + new_screen->scrnum = scrnum++; + + new_screen->depth = screen->depth; + + new_screen->displays_mask = display->device_mask; + new_screen->num_displays = 1; + + /* Create a metamode for each mode on the display */ + new_screen->num_metamodes = 0; + for (mode = display->modes; mode; mode = mode->next) { + + /* Create the metamode */ + metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode)); + if (!metamode) continue; /* XXX Fail ! */ + + metamode->source = METAMODE_SOURCE_NVCONTROL; + + /* Make the mode point to the new metamode */ + mode->metamode = metamode; + + /* Set the current metamode if this is the current mode */ + if (display->cur_mode == mode) { + new_screen->cur_metamode = metamode; + new_screen->cur_metamode_idx = new_screen->num_metamodes; + } + + /* Append the metamode */ + new_screen->metamodes = + (nvMetaModePtr)xconfigAddListItem((GenericListPtr)new_screen->metamodes, + (GenericListPtr)metamode); + new_screen->num_metamodes++; + } + + /* Move the display to the new screen */ + screen->num_displays--; + screen->displays_mask &= ~(display->device_mask); + + display->screen = new_screen; + + /* Append the screen to the gpu */ + gpu->screens = + (nvScreenPtr)xconfigAddListItem((GenericListPtr)gpu->screens, + (GenericListPtr)new_screen); + gpu->num_screens++; + + /* Earlier display devices get first dibs on low screen numbers */ + new_screen->handle = screen->handle; + new_screen->ctk_event = screen->ctk_event; + new_screen->scrnum = screen->scrnum; + screen->handle = NULL; + screen->ctk_event = NULL; + screen->scrnum = scrnum -1; + + /* Can't apply creation of new screens */ + ctk_object->apply_possible = FALSE; + } + + + /* Translate mode positional relationships to screen relationships */ + for (display = gpu->displays; display; display = display->next) { + + if (!display->screen) continue; + + for (mode = display->modes; mode; mode = mode->next) { + if (mode->relative_to && + (mode->relative_to->gpu == mode->display->gpu)) { + display->screen->position_type = mode->position_type; + display->screen->relative_to = mode->relative_to->screen; + } + mode->position_type = CONF_ADJ_ABSOLUTE; + mode->relative_to = NULL; + } + } + +} /* do_configure_display_for_xscreen() */ + + + +/** do_configure_display_for_twinview() ****************************** + * + * Configures the display's GPU for TwinView + * + **/ + +static void do_configure_display_for_twinview(CtkDisplayConfig *ctk_object, + nvDisplayPtr display) +{ + nvScreenPtr screen; + nvMetaModePtr metamode; + nvModePtr mode; + nvModePtr last_mode; + nvGpuPtr gpu = display->gpu; + int m; + + + /* We need at least one screen to activate TwinView */ + if (!gpu || !gpu->screens) return; + + + /* Make sure the screen has enough metamodes */ + screen = gpu->screens; + for (display = gpu->displays; display; display = display->next) { + + /* Only add enabled displays to TwinView setup */ + if (!display->screen) continue; + + /* Make sure the screen has enough metamodes */ + for (m = display->num_modes - screen->num_metamodes; m > 0; m--) { + + metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode)); + if (!metamode) break; // XXX Sigh. + + metamode->source = METAMODE_SOURCE_NVCONTROL; + + /* Add the metamode at the end of the screen's metamode list */ + screen->metamodes = + (nvMetaModePtr)xconfigAddListItem((GenericListPtr)screen->metamodes, + (GenericListPtr)metamode); + screen->num_metamodes++; + } + } + + + /* Make sure each display has the right number of modes and that + * the modes point to the right metamode in the screen. + */ + for (display = gpu->displays; display; display = display->next) { + + /* Only add enabled displays to TwinView setup */ + if (!display->screen) continue; + + /* Make the display mode point to the right metamode */ + metamode = screen->metamodes; + mode = display->modes; + last_mode = NULL; + while (metamode && mode) { + + if (metamode == screen->cur_metamode) { + display->cur_mode = mode; + } + + /* Keep the relationship between displays if possible. If + * this display's screen is relative to another screen + * on the same gpu, translate the relationship to the + * display's mode. + */ + if (display->screen->relative_to && + (display->screen->relative_to->gpu == gpu)) { + + nvDisplayPtr other; + + /* Make the display relative to the other display */ + for (other = gpu->displays; other; other = other->next) { + if (other->screen == display->screen->relative_to) { + mode->position_type = display->screen->position_type; + mode->relative_to = other; + break; + } + } + } + mode->metamode = metamode; + + if (mode && !mode->next) { + last_mode = mode; + } + metamode = metamode->next; + mode = mode->next; + } + + /* Add dummy modes */ + while (metamode) { + + mode = parse_mode(display, "NULL"); + mode->dummy = 1; + mode->metamode = metamode; + + if (metamode == screen->cur_metamode) { + display->cur_mode = mode; + } + + /* Duplicate position information of the last mode */ + if (last_mode) { + mode->dim[X] = last_mode->dim[X]; + mode->dim[Y] = last_mode->dim[Y]; + mode->pan[X] = last_mode->pan[X]; + mode->pan[Y] = last_mode->pan[Y]; + mode->position_type = last_mode->position_type; + mode->relative_to = last_mode->relative_to; + } + + /* Add the mode at the end of display's mode list */ + display->modes = + (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes, + (GenericListPtr)mode); + display->num_modes++; + metamode = metamode->next; + } + } + + + /* Make the displays part of the screen */ + for (display = gpu->displays; display; display = display->next) { + + /* Only add enabled displays to TwinView setup */ + if (!display->screen) continue; + + if (display->screen != screen) { + display->screen = screen; + screen->displays_mask |= display->device_mask; + screen->num_displays++; + } + } + + + /* Delete extra screens on the GPU */ + while (gpu->screens->next) { + nvScreenPtr other; + + /* Delete screens that come before 'screen' */ + if (gpu->screens != screen) { + other = gpu->screens; + gpu->screens = other->next; + + /* Delete screens that comes after 'screen' */ + } else { + other = gpu->screens->next; + gpu->screens->next = other->next; + } + + /* Handle positional relationships going away */ + if (screen->relative_to == other) { + screen->position_type = CONF_ADJ_ABSOLUTE; + screen->relative_to = NULL; + } + + /* Clean up memory used by the screen */ + while (other->metamodes) { + nvMetaModePtr metamode = other->metamodes; + other->metamodes = metamode->next; + free(metamode); + } + + /* Keep the lowest screen number */ + if (other->scrnum < screen->scrnum) { + if (screen->handle) { + NvCtrlAttributeClose(screen->handle); + } + screen->scrnum = other->scrnum; + screen->handle = other->handle; + } else { + if (other->handle) { + NvCtrlAttributeClose(other->handle); + } + } + + free(other); + gpu->num_screens--; + } + +} /* do_configure_display_for_twinview() */ + + + +/** do_query_remove_display() **************************************** + * + * Asks the user about removing a display device from the layout. + * + **/ + +static gboolean do_query_remove_display(CtkDisplayConfig *ctk_object, + nvDisplayPtr display) +{ + gint result; + + + /* Show the display disable dialog */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_display_disable), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_show_all(ctk_object->dlg_display_disable); + gtk_widget_grab_focus(ctk_object->btn_display_disable_cancel); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_display_disable)); + gtk_widget_hide(ctk_object->dlg_display_disable); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + return True; + + case GTK_RESPONSE_CANCEL: + default: + /* Cancel */ + return False; + } + + return False; + +} /* do_query_remove_display() */ + + + +/** do_disable_display() ********************************************* + * + * Confirms disabling of the display device. + * + **/ + +void do_disable_display(CtkDisplayConfig *ctk_object, nvDisplayPtr display) +{ + nvGpuPtr gpu = display->gpu; + nvScreenPtr screen = display->screen; + gchar *str; + gchar *type = get_display_type_str(display->device_mask, 0); + + + /* Setup the remove display dialog */ + if (ctk_object->advanced_mode) { + str = g_strdup_printf("Disable the display device %s (%s) " + "on GPU-%d (%s)?", + display->name, type, + NvCtrlGetTargetId(gpu->handle), gpu->name); + } else { + str = g_strdup_printf("Disable the display device %s (%s)?", + display->name, type); + } + g_free(type); + + gtk_label_set_text + (GTK_LABEL(ctk_object->txt_display_disable), str); + g_free(str); + + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_display_disable_off), + "Disable"); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_display_disable_cancel), + "Cancel"); + + + /* Ask user what to do */ + if (do_query_remove_display(ctk_object, display)) { + + /* Remove display from the X Screen */ + remove_display_from_screen(display); + + /* If the screen is empty, remove it */ + if (!screen->num_displays) { + remove_screen_from_gpu(screen); + free_screen(screen); + } + + /* Add the fake mode to the display */ + add_screenless_modes_to_displays(display->gpu); + } + +} /* do_disable_display() */ + + + +/** display_config_clicked() ***************************************** + * + * Called when user clicks on the display configuration button. + * + **/ + +static void display_config_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gint result; + gboolean update = FALSE; + nvGpuPtr gpu; + int num_screens; + + + if (!display) return; + + + /* Don't allow disabling the last display device */ + num_screens = 0; + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + num_screens += gpu->num_screens; + } + if (num_screens == 1 && display->screen && + display->screen->num_displays == 1) { + gtk_widget_set_sensitive(ctk_object->rad_display_config_disabled, + FALSE); + } else { + gtk_widget_set_sensitive(ctk_object->rad_display_config_disabled, + TRUE); + } + + + /* We can only enable as many X Screens as the GPU supports */ + if (!display->screen && + (display->gpu->num_screens >= display->gpu->max_displays)) { + gtk_widget_set_sensitive(ctk_object->rad_display_config_xscreen, + FALSE); + } else { + gtk_widget_set_sensitive(ctk_object->rad_display_config_xscreen, + TRUE); + } + + + /* We can't setup TwinView if there is only one display connected, + * there are no existing X Screens on the GPU, or this display is + * the only enabled device on the GPU. + */ + if (display->gpu->num_displays == 1 || !display->gpu->num_screens || + (display->gpu->num_screens == 1 && + display->gpu->screens->num_displays == 1 && + display->screen == display->gpu->screens)) { + gtk_widget_set_sensitive(ctk_object->rad_display_config_twinview, + FALSE); + } else { + gtk_widget_set_sensitive(ctk_object->rad_display_config_twinview, + TRUE); + } + + + /* Setup the button state */ + if (!display->screen) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_disabled), + TRUE); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_disabled), + "Disabled"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_xscreen), + "Separate X Screen (Requires X restart)"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_twinview), + "TwinView"); + + } else if (display->screen->num_displays > 1) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_twinview), + TRUE); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_disabled), + "Disabled"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_xscreen), + "Separate X Screen (Requires X restart)"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_twinview), + "TwinView"); + + } else { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_xscreen), + TRUE); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_disabled), + "Disabled (Requires X restart)"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_xscreen), + "Separate X Screen"); + gtk_button_set_label + (GTK_BUTTON(ctk_object->rad_display_config_twinview), + "TwinView (Requires X restart)"); + } + + + /* Show the display config dialog */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_display_config), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_show_all(ctk_object->dlg_display_config); + gtk_widget_grab_focus(ctk_object->btn_display_config_cancel); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_display_config)); + gtk_widget_hide(ctk_object->dlg_display_config); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + /* OK */ + break; + + case GTK_RESPONSE_CANCEL: + default: + /* Cancel */ + return; + } + + + + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_disabled))) { + if (display->screen) { + do_disable_display(ctk_object, display); + update = TRUE; + } + } else { + + /* Make sure the display has modelines */ + if (!display->modelines) { + char *tokens; + gchar *err_str = NULL; + NvCtrlStringOperation(display->gpu->handle, display->device_mask, + NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL, + "", &tokens); + update = TRUE; + if (!add_modelines_to_display(display, &err_str)) { + nv_warning_msg(err_str); + g_free(err_str); + return; + } + } + if (!display->modelines) return; + + if (!display->screen) { + + /* Enable display as a separate X Screen */ + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_xscreen))) { + do_enable_display_for_xscreen(ctk_object, display); + update = TRUE; + } + + /* Enable display in TwinView with an existing screen */ + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_twinview))) { + do_enable_display_for_twinview(ctk_object, display); + update = TRUE; + } + + } else { + + /* Move display to a new X Screen */ + if (display->screen->num_displays > 1 && + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_xscreen))) { + do_configure_display_for_xscreen(ctk_object, display); + update = TRUE; + } + + /* Setup TwinView on the first X Screen */ + if (display->screen->num_displays == 1 && + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_object->rad_display_config_twinview))) { + do_configure_display_for_twinview(ctk_object, display); + update = TRUE; + } + } + } + + + /* Sync the GUI */ + if (update) { + + /* Recaltulate */ + ctk_display_layout_redraw(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + /* Auto fix all screens on the gpu */ + { + nvGpuPtr gpu = display->gpu; + nvScreenPtr screen; + + for (screen = gpu->screens; screen; screen = screen->next) { + validation_auto_fix_screen(ctk_object, screen); + } + } + + /* Redraw */ + ctk_display_layout_redraw(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + /* Update GUI */ + setup_layout_frame(ctk_object); + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + } + +} /* display_config_clicked() */ + + + +/** display_refresh_changed() **************************************** + * + * Called when user selects a new refresh rate for a display. + * + **/ + +static void display_refresh_changed(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gint idx; + nvModeLinePtr modeline; + nvDisplayPtr display; + + + /* Get the modeline and display to set */ + idx = gtk_option_menu_get_history(GTK_OPTION_MENU(widget)); + modeline = ctk_object->refresh_table[idx]; + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* In Basic view, we assume the user most likely wants + * to change which metamode is being used. + */ + if (!ctk_object->advanced_mode && (display->screen->num_displays == 1)) { + int metamode_idx = find_closest_mode_with_modeline(display, modeline); + + /* Select the new metamode */ + if (metamode_idx >= 0) { + ctk_display_layout_set_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display->screen, metamode_idx); + } + } + + + /* Update the display's currently selected mode */ + ctk_display_layout_set_mode_modeline + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display->cur_mode, modeline); + + + /* Update the modename */ + setup_display_modename(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* display_refresh_changed() */ + + + +/** display_resolution_changed() ************************************* + * + * Called when user selects a new resolution for a display device. + * + **/ + +static void display_resolution_changed(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gint idx; + nvModeLinePtr modeline; + nvDisplayPtr display; + + + /* Get the modeline and display to set */ + idx = gtk_option_menu_get_history(GTK_OPTION_MENU(widget)); + modeline = ctk_object->resolution_table[idx]; + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + /* Ignore selecting same resolution */ + if (display->cur_mode->modeline == modeline) { + return; + } + + + /* In Basic view, we assume the user most likely wants + * to change which metamode is being used. + */ + if (!ctk_object->advanced_mode && (display->screen->num_displays == 1)) { + int metamode_idx = find_closest_mode_with_modeline(display, modeline); + + /* Select the new metamode */ + if (metamode_idx >= 0) { + ctk_display_layout_set_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display->screen, metamode_idx); + } + } + + + /* Select the new modeline for its resolution */ + ctk_display_layout_set_mode_modeline + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display->cur_mode, modeline); + + + /* Regenerate the refresh menu */ + setup_display_refresh_dropdown(ctk_object); + + + /* Sync the display position */ + setup_display_position(ctk_object); + + + /* Sync the panning domain */ + setup_display_panning(ctk_object); + + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* display_resolution_changed() */ + + + +/** display_position_type_changed() ********************************** + * + * Called when user selects a new display position method (relative/ + * absolute) + * + **/ + +static void display_position_type_changed(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvDisplayPtr display; + gint position_idx; + int position_type; + gint relative_to_idx; + nvDisplayPtr relative_to; + + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + /* Get the new position type */ + position_idx = + gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_type)); + + position_type = __position_table[position_idx]; + + relative_to_idx = + gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_relative)); + + if (relative_to_idx >= 0 && + relative_to_idx < ctk_object->display_position_table_len) { + + relative_to = + ctk_object->display_position_table[relative_to_idx]; + + /* Update the layout */ + ctk_display_layout_set_display_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display, position_type, relative_to, + display->cur_mode->dim[X], + display->cur_mode->dim[Y]); + } + + + /* Cannot apply if the screen position changed */ + check_screen_pos_changed(ctk_object); + + + /* Update GUI */ + setup_display_position_relative(ctk_object); + + setup_display_position_offset(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* display_position_type_changed() */ + + + +/** display_position_relative_changed() ****************************** + * + * Called when user selects a new display to be positioned relative + * to. + * + **/ + +static void display_position_relative_changed(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvDisplayPtr display; + gint position_idx; + gint relative_to_idx; + int position_type; + nvDisplayPtr relative_to; + + display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + /* Get the new display to be relative to */ + position_idx = gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_type)); + + position_type = __position_table[position_idx]; + + relative_to_idx = gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_display_position_relative)); + + if (relative_to_idx >= 0 && + relative_to_idx < ctk_object->display_position_table_len) { + + relative_to = ctk_object->display_position_table[relative_to_idx]; + + /* Update the relative position */ + ctk_display_layout_set_display_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display, position_type, relative_to, 0, 0); + } + + + /* Cannot apply if we change the relative position */ + check_screen_pos_changed(ctk_object); + + + /* Update the GUI */ + setup_display_position_offset(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* display_position_relative_changed() */ + + + +/** display_position_offset_activate() ******************************* + * + * Called when user modifies the display position offset text entry. + * + **/ + +static void display_position_offset_activate(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + const gchar *str = gtk_entry_get_text(GTK_ENTRY(widget)); + int x, y; + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + if (!display) return; + + /* Parse user input */ + str = read_pair(str, 0, &x, &y); + if (!str) { + /* Reset the display position */ + setup_display_position_offset(ctk_object); + return; + } + + /* Make coordinates relative to top left of Screen */ + x += display->cur_mode->metamode->edim[X]; + y += display->cur_mode->metamode->edim[Y]; + + + /* Update the absolute position */ + ctk_display_layout_set_display_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + display, CONF_ADJ_ABSOLUTE, NULL, x, y); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* display_position_offset_activate() */ + + + +/** display_panning_activate() *************************************** + * + * Called when user modifies the display position text entry. + * + **/ + +static void display_panning_activate(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + const gchar *str = gtk_entry_get_text(GTK_ENTRY(widget)); + int x, y; + nvDisplayPtr display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + + if (!display) { + return; + } + + str = read_pair(str, 'x', &x, &y); + if (!str) { + /* Reset the display panning */ + setup_display_panning(ctk_object); + return; + } + + ctk_display_layout_set_display_panning + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), display, x, y); + +} /* display_panning_activate() */ + + + +/** screen_depth_changed() ******************************************* + * + * Called when user selects a new color depth for a screen. + * + **/ + +static void screen_depth_changed(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gint idx = gtk_option_menu_get_history(GTK_OPTION_MENU(widget)); + int depth = 8; + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!screen) return; + + /* Set the new default depth of the screen */ + if (idx == 0) { + depth = 24; + } else if (idx == 1) { + depth = 16; + } + ctk_display_layout_set_screen_depth + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), screen, depth); + + /* Can't apply screen depth changes */ + ctk_object->apply_possible = FALSE; + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_depth_changed() */ + + + +/** screen_position_type_changed() *********************************** + * + * Called when user selects a new screen position method (relative/ + * absolute) + * + **/ + +static void screen_position_type_changed(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gint position_idx; + int position_type; + gint relative_to_idx; + nvScreenPtr relative_to; + + if (!screen) return; + + /* Get the new position type */ + position_idx = + gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_type)); + + position_type = __position_table[position_idx]; + + relative_to_idx = + gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_relative)); + + if (relative_to_idx >= 0 && + relative_to_idx < ctk_object->screen_position_table_len) { + + relative_to = + ctk_object->screen_position_table[relative_to_idx]; + + /* Update the layout */ + ctk_display_layout_set_screen_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, position_type, relative_to, + screen->dim[X], + screen->dim[Y]); + } + + + /* Cannot apply changes to screen positioning */ + ctk_object->apply_possible = FALSE; + + + /* Update the GUI */ + setup_screen_position_relative(ctk_object); + + setup_screen_position_offset(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_position_type_changed() */ + + + +/** screen_position_relative_changed() ******************************* + * + * Called when user selects a new screen to be positioned relative + * to. + * + **/ + +static void screen_position_relative_changed(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + gint position_idx; + gint relative_to_idx; + int position_type; + nvScreenPtr relative_to; + + if (!screen) return; + + /* Get the new X Screen to be relative to */ + position_idx = gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_type)); + + position_type = __position_table[position_idx]; + + relative_to_idx = gtk_option_menu_get_history + (GTK_OPTION_MENU(ctk_object->mnu_screen_position_relative)); + + if (relative_to_idx >= 0 && + relative_to_idx < ctk_object->screen_position_table_len) { + + relative_to = ctk_object->screen_position_table[relative_to_idx]; + + /* Update the relative position */ + ctk_display_layout_set_screen_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, position_type, relative_to, 0, 0); + } + + + /* Cannot apply changes to screen positioning */ + ctk_object->apply_possible = FALSE; + + + /* Update the GUI */ + setup_screen_position_offset(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_position_relative_changed() */ + + + +/** screen_position_offset_activate() ******************************** + * + * Called when user modifies the screen position offset text entry. + * + **/ + +static void screen_position_offset_activate(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + const gchar *str = gtk_entry_get_text(GTK_ENTRY(widget)); + int x, y; + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!screen) return; + + + /* Parse user input */ + str = read_pair(str, 0, &x, &y); + if (!str) { + /* Reset the display position */ + setup_screen_position_offset(ctk_object); + return; + } + + + /* Cannot apply changes to screen positioning */ + ctk_object->apply_possible = FALSE; + + + /* Update the absolute position */ + ctk_display_layout_set_screen_position + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, screen->position_type, screen->relative_to, x, y); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_position_offset_activate() */ + + + +/** screen_metamode_clicked() **************************************** + * + * Called when user selects a new metamode for the selected screen + * + **/ + +static void screen_metamode_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + GtkWidget *menu; + GtkWidget *menu_item; + int i; + gchar *str; + gchar *tmp; + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!screen) return; + + /* Generate the popup menu */ + menu = gtk_menu_new(); + for (i = 0; i < screen->num_metamodes; i++) { + + /* Setup the menu item text */ + tmp = get_screen_metamode_str(screen, i, 1); + str = g_strdup_printf("%d - \"%s\"", i+1, tmp); + menu_item = gtk_menu_item_new_with_label(str); + g_free(str); + g_free(tmp); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); + gtk_widget_show(menu_item); + g_signal_connect(G_OBJECT(menu_item), + "activate", + G_CALLBACK(screen_metamode_activate), + (gpointer) ctk_object); + } + + /* Show the popup menu */ + gtk_menu_popup(GTK_MENU(menu), + NULL, NULL, NULL, NULL, + 1, gtk_get_current_event_time()); + +} /* screen_metamode_clicked() */ + + + +/** screen_metamode_activate() *************************************** + * + * Called when user selects a new metamode for the selected screen + * + **/ + +static void screen_metamode_activate(GtkWidget *widget, gpointer user_data) +{ + GtkMenuItem *item = (GtkMenuItem *) widget; + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + const gchar *str = + gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item)))); + int idx; + gchar *name; + + if (!screen || !str) return; + + idx = atoi(str) -1; + + name = g_strdup_printf("%d - ...", idx+1); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_screen_metamode), name); + g_free(name); + + + ctk_display_layout_set_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), screen, idx); + + + /* Sync the display frame */ + setup_display_frame(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_metamode_activate() */ + + + +/** screen_metamode_add_clicked() ************************************ + * + * Called when user clicks on the display's "Add" metamode button. + * + **/ + +static void screen_metamode_add_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!screen) return; + + + /* Add a new metamode to the screen */ + ctk_display_layout_add_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), screen); + + + /* Update the GUI */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_metamode_add_clicked() */ + + + +/** screen_metamode_delete_clicked() ********************************* + * + * Called when user clicks on the display's "Delete" metamode button. + * + **/ + +static void screen_metamode_delete_clicked(GtkWidget *widget, + gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvScreenPtr screen = ctk_display_layout_get_selected_screen + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + if (!screen) return; + + + ctk_display_layout_delete_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, screen->cur_metamode_idx); + + /* Update the GUI */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* screen_metamode_delete_clicked() */ + + + +/** xinerama_state_toggled() ***************************************** + * + * Called when user toggles the state of the "Enable Xinerama" + * button. + * + **/ + +static void xinerama_state_toggled(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + + ctk_object->layout->xinerama_enabled = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + + /* Can't dynamically enable Xinerama */ + ctk_object->apply_possible = FALSE; + + /* Make the apply button sensitive to user input */ + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + +} /* xinerama_state_toggled() */ + + + +/** update_display_confirm_text() ************************************ + * + * Generates the text used in the confirmation dialog. + * + **/ + +static void update_display_confirm_text(CtkDisplayConfig *ctk_object, + int screen) +{ + gchar *str; + str = g_strdup_printf("The Mode on X Screen %d has been set.\n" + "Would you like to keep the current settings?\n\n" + "Reverting in %d seconds...", + screen, ctk_object->display_confirm_countdown); + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_confirm), str); + g_free(str); + +} /* update_display_confirm_text() */ + + + +/** do_display_confirm_countdown() *********************************** + * + * timeout callback for reverting a modeline setting. + * + **/ + +static gboolean do_display_confirm_countdown(gpointer data) +{ + SwitchModeCallbackInfo *info = (SwitchModeCallbackInfo *) data; + CtkDisplayConfig *ctk_object = info->ctk_object; + int screen = info->screen; + + ctk_object->display_confirm_countdown--; + if (ctk_object->display_confirm_countdown > 0) { + update_display_confirm_text(ctk_object, screen); + return True; + } + + /* Force dialog to cancel */ + gtk_dialog_response(GTK_DIALOG(ctk_object->dlg_display_confirm), + GTK_RESPONSE_REJECT); + + return False; + +} /* do_display_confirm_countdown() */ + + + +/** switch_to_current_metamode() ************************************* + * + * Switches to the current screen metamode using XRandR + * + **/ + +static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + ReturnStatus ret; + gint result; + nvMetaModePtr metamode; + int new_width; + int new_height; + int new_rate; + int old_width; + int old_height; + int old_rate; + static SwitchModeCallbackInfo info; + GtkWidget *dlg; + GtkWidget *parent; + gchar *msg; + + + if (!screen->handle || !screen->cur_metamode) goto fail; + + metamode = screen->cur_metamode; + + new_width = metamode->edim[W]; + new_height = metamode->edim[H]; + new_rate = metamode->id; + + + /* Find the parent window for displaying dialogs */ + + parent = gtk_widget_get_parent(GTK_WIDGET(ctk_object)); + while (!GTK_IS_WINDOW(parent)) { + GtkWidget *old = parent; + parent = gtk_widget_get_parent(GTK_WIDGET(old)); + if (!parent || old == parent) { + /* GTK Error, can't find parent window! */ + goto fail; + } + } + + + /* XRandR must be available to do mode switching */ + + if (!NvCtrlGetXrandrEventBase(screen->handle)) { + dlg = gtk_message_dialog_new + (GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + "The XRandR X extension was not found. This extension must " + "be supported by the X server and enabled for display " + "configuration settings to be dynamically applicable."); + + gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy(dlg); + + nv_warning_msg("XRandR X extension not enabled, " + "cannot apply settings!"); + goto fail; + } + + + /* Get the current mode so we can fall back on that if the + * mode switch fails, or the user does not confirm. + */ + + ret = NvCtrlXrandrGetScreenMode(screen->handle, &old_width, &old_height, + &old_rate); + if (ret != NvCtrlSuccess) { + nv_warning_msg("Failed to get current (fallback) mode for " + "display device!"); + goto fail; + } + + nv_info_msg(TAB, "Current mode: %dx%d (id: %d)", + old_width, old_height, old_rate); + + + /* Switch to the new mode */ + + nv_info_msg(TAB, "Switching to mode: %dx%d (id: %d)...", + new_width, new_height, new_rate); + + ret = NvCtrlXrandrSetScreenMode(screen->handle, new_width, new_height, + new_rate); + if (ret != NvCtrlSuccess) { + + nv_warning_msg("Failed to set MetaMode (%d) '%s' " + "(mode: %dx%d, id: %d) on X Screen %d!", + screen->cur_metamode_idx+1, metamode->string, new_width, + new_height, new_rate, + NvCtrlGetTargetId(screen->handle)); + + if (screen->num_metamodes > 1) { + msg = g_strdup_printf("Failed to set MetaMode (%d) '%s' " + "(Mode %dx%d, id: %d) on X Screen %d\n\n" + "Would you like to remove this MetaMode?", + screen->cur_metamode_idx+1, metamode->string, + new_width, new_height, new_rate, + NvCtrlGetTargetId(screen->handle)); + dlg = gtk_message_dialog_new + (GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_YES_NO, + msg); + } else { + msg = g_strdup_printf("Failed to set MetaMode (%d) '%s' " + "(Mode %dx%d, id: %d) on X Screen %d.", + screen->cur_metamode_idx+1, metamode->string, + new_width, new_height, new_rate, + NvCtrlGetTargetId(screen->handle)); + dlg = gtk_message_dialog_new + (GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + msg); + } + + result = gtk_dialog_run(GTK_DIALOG(dlg)); + + switch (result) { + case GTK_RESPONSE_YES: + ctk_display_layout_delete_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, screen->cur_metamode_idx); + + nv_info_msg(TAB, "Removed MetaMode %d on Screen %d.\n", + screen->cur_metamode_idx+1, + NvCtrlGetTargetId(screen)); + + /* Update the GUI */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + break; + case GTK_RESPONSE_OK: + /* Nothing to do with last metamode */ + default: + /* Ignore the bad metamode */ + break; + } + + g_free(msg); + gtk_widget_destroy(dlg); + goto fail; + } + + + /* Setup the counter callback data */ + info.ctk_object = ctk_object; + info.screen = NvCtrlGetTargetId(screen->handle); + + /* Start the countdown timer */ + ctk_object->display_confirm_countdown = DEFAULT_SWITCH_MODE_TIMEOUT; + update_display_confirm_text(ctk_object, info.screen); + ctk_object->display_confirm_timer = + g_timeout_add(1000, + (GSourceFunc)do_display_confirm_countdown, + (gpointer)(&info)); + + /* Show the confirm dialog */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_display_confirm), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_show_all(ctk_object->dlg_display_confirm); + gtk_widget_grab_focus(ctk_object->btn_display_apply_cancel); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_display_confirm)); + gtk_widget_hide(ctk_object->dlg_display_confirm); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + /* Kill the timer */ + g_source_remove(ctk_object->display_confirm_timer); + break; + + case GTK_RESPONSE_REJECT: + default: + /* Fall back to previous settings */ + nv_info_msg(TAB, "Switching back to mode: %dx%d (id: %d)...", + old_width, old_height, old_rate); + + NvCtrlXrandrSetScreenMode(screen->handle, old_width, old_height, + old_rate); + /* Good luck! */ + goto fail; + } + + return TRUE; + + fail: + return FALSE; + +} /* switch_to_current_metamode() */ + + + +/** find_metamode_string() ******************************************* + * + * Finds "metamode_str" in the list of strings in metamode_strs. + * If metamode_str is found, a pointer to the full metamode string + * is returned (including tokens, if any.) + * + * if "metamode_str" is not found in "metamode_strs", NULL is + * returned. + * + **/ + +static char *find_metamode_string(char *metamode_str, char *metamode_strs) +{ + char *m; + char *str; + + for (m = metamode_strs; m && strlen(m); m += strlen(m) +1) { + + /* Skip tokens if any */ + str = strstr(m, "::"); + if (str) { + str = (char *)skip_whitespace(str +2); + } else { + str = m; + } + + /* See if metamode strings match */ + if (!strcmp(str, metamode_str)) return m; + } + + return NULL; + +} /* find_metamode_string() */ + + + +/** preprocess_metamodes() ******************************************* + * + * Does preprocess work to the metamode strings: + * + * - Generates the metamode strings for the screen's metamodes + * that will be used for creating the metamode list on the X + * Server. + * + * - Whites out each string in the metamode_strs list that should + * not be deleted (it has a matching metamode in "screen".) + * + * - Adds new metamodes to the X Server screen that are specified + * in "screen". + * + **/ + +static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs) +{ + nvMetaModePtr metamode; + ReturnStatus ret; + char *str = NULL; + char *tokens; + int metamode_idx; + + + for (metamode = screen->metamodes, metamode_idx = 0; + metamode; + metamode = metamode->next, metamode_idx++) { + + /* Generate the metamore's string */ + free(metamode->string); + metamode->string = get_screen_metamode_str(screen, metamode_idx, 0); + if (!metamode->string) continue; + + /* Look for the metamode string in metamode_strs */ + str = find_metamode_string(metamode->string, metamode_strs); + if (str) { + + /* Grab the metamode id from the tokens */ + tokens = strdup(str); + if (tokens) { + char *tmp = strstr(tokens, "::"); + if (tmp) { + *tmp = '\0'; + parse_tokens(tokens, apply_metamode_token, metamode); + } + free(tokens); + } + + /* The metamode was found, white out the metamode string + * so it does not get deleted and continue. + */ + while (*str) { + *str = ' '; + str++; + } + continue; + } + + /* The metamode was not found, so add it to the X Screen's list */ + tokens = NULL; + ret = NvCtrlStringOperation(screen->handle, 0, + NV_CTRL_STRING_OPERATION_ADD_METAMODE, + metamode->string, &tokens); + + /* Grab the metamode ID from the returned tokens */ + if (ret == NvCtrlSuccess) { + if (tokens) { + parse_tokens(tokens, apply_metamode_token, metamode); + free(tokens); + } + nv_info_msg(TAB, "Added > %s", metamode->string); + } + } + +} /* preprocess_metamodes() */ + + + +/** order_metamodes() ************************************************ + * + * Makes sure the metamodes are ordered properly by moving each + * metamode to its correct location in the server's metamode list. + * + **/ + +static void order_metamodes(nvScreenPtr screen) +{ + nvMetaModePtr metamode; + int metamode_idx; + char *metamode_str; + char *update_str; + int len; + ReturnStatus ret; + + + for (metamode = screen->metamodes, metamode_idx = 0; + metamode; + metamode = metamode->next, metamode_idx++) { + + metamode_str = get_screen_metamode_str(screen, metamode_idx, + 0); + if (!metamode_str) continue; + + /* Append the index we want */ + len = 24 + strlen(metamode_str); + update_str = malloc(len); + snprintf(update_str, len, "index=%d :: %s", metamode_idx, + metamode_str); + + ret = NvCtrlSetStringAttribute(screen->handle, + NV_CTRL_STRING_MOVE_METAMODE, + update_str, NULL); + if (ret == NvCtrlSuccess) { + nv_info_msg(TAB, "Moved > %s", metamode_str); + } + free(metamode_str); + } + +} /* order_metamodes() */ + + + +/** postprocess_metamodes() ****************************************** + * + * Does post processing work on the metamode list: + * + * - Deletes any metamode left in the metamode_strs + * + **/ + +static void postprocess_metamodes(nvScreenPtr screen, char *metamode_strs) +{ + char *metamode_str; + char *str; + ReturnStatus ret; + + + /* Delete metamodes that were not cleared out from the metamode_strs */ + for (metamode_str = metamode_strs; + metamode_str && strlen(metamode_str); + metamode_str += strlen(metamode_str) +1) { + + /* Skip tokens */ + str = strstr(metamode_str, "::"); + if (!str) continue; + + str = (char *)skip_whitespace(str +2); + + + /* Delete the metamode */ + ret = NvCtrlSetStringAttribute(screen->handle, + NV_CTRL_STRING_DELETE_METAMODE, + str, NULL); + if (ret == NvCtrlSuccess) { + nv_info_msg(TAB, "Removed > %s", str); + } + } + + /* Reorder the list of metamodes */ + order_metamodes(screen); + +} /* postprocess_metamodes() */ + + + +/** update_screen_metamodes() **************************************** + * + * Updates the screen's metamode list. + * + **/ + +static int update_screen_metamodes(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + char *metamode_strs = NULL; + char *cur_metamode_str = NULL; + char *metamode_str; + int len; + + int clear_apply = 0; /* Set if we should clear the apply button */ + ReturnStatus ret; + + + /* Make sure the screen has a valid handle to make the updates */ + if (!screen->handle) { + return 1; + } + + nv_info_msg("", "Updating Screen %d's MetaModes:", + NvCtrlGetTargetId(screen->handle)); + + /* To update the metamode list of the screen: + * + * (preprocess) + * - Get the current list of metamodes for this screen + * - Add all the new metamodes at the end of the list + * + * (mode switch) + * - Do a modeswitch, if we need to + * + * (postprocess) + * - Delete any unused mode + * - Move metamodes to the correct location + **/ + + /* Get the list of the current metamodes */ + + ret = NvCtrlGetBinaryAttribute(screen->handle, + 0, + NV_CTRL_BINARY_DATA_METAMODES, + (unsigned char **)&metamode_strs, + &len); + if (ret != NvCtrlSuccess) goto done; + + /* Get the current metamode for the screen */ + + ret = NvCtrlGetStringAttribute(screen->handle, + NV_CTRL_STRING_CURRENT_METAMODE, + &cur_metamode_str); + if (ret != NvCtrlSuccess) goto done; + + /* Skip tokens */ + metamode_str = strstr(cur_metamode_str, "::"); + if (metamode_str) { + metamode_str = (char *)skip_whitespace(metamode_str +2); + } else { + metamode_str = cur_metamode_str; + } + + /* Preprocess the new metamodes list */ + + preprocess_metamodes(screen, metamode_strs); + + /* If we need to switch metamodes, do so now */ + + if (strcmp(screen->cur_metamode->string, metamode_str)) { + if (switch_to_current_metamode(ctk_object, screen)) { + ctk_config_statusbar_message(ctk_object->ctk_config, + "Switched to mode %dx%d " + "@ %d Hz.", + screen->cur_metamode->edim[W], + screen->cur_metamode->edim[H], + screen->cur_metamode->id); + + nv_info_msg(TAB, "Using > %s", screen->cur_metamode->string); + + clear_apply = 1; + } + } + + /* Post process the metamodes list */ + + postprocess_metamodes(screen, metamode_strs); + + done: + + XFree(metamode_strs); + XFree(cur_metamode_str); + + return clear_apply; + +} /* update_screen_metamodes() */ + + + +/** apply_clicked() ************************************************** + * + * Called when user clicks on the "Apply" button. + * + **/ + +static void apply_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvGpuPtr gpu; + int clear_apply = 1; + + + /* Make sure we can apply */ + if (!validate_apply(ctk_object)) { + return; + } + + /* Make sure the layout is ready to be applied */ + if (!validate_layout(ctk_object)) { + return; + } + + /* Update all GPUs */ + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + nvScreenPtr screen; + + /* Update all X Screens */ + for (screen = gpu->screens; screen; screen = screen->next) { + + if (!screen->handle) continue; + + if (!update_screen_metamodes(ctk_object, screen)) { + clear_apply = FALSE; + } else { + ReturnStatus ret; + ret = NvCtrlSetAttribute(screen->handle, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + screen->displays_mask); + if (ret != NvCtrlSuccess) { + nv_error_msg("Failed to set screen %d's association mask " + "to: 0x%08x", + screen->scrnum, screen->displays_mask); + } else { + /* Make sure other parts of nvidia-settings get updated */ + ctk_event_emit(screen->ctk_event, 0, + NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + screen->displays_mask); + } + } + } + } + + /* Clear the apply button if all went well */ + if (clear_apply) { + gtk_widget_set_sensitive(widget, False); + } + +} /* apply_clicked() */ + + + +/** xconfig_file_clicked() ******************************************* + * + * Called when the user clicks on the "Browse..." button of the + * X Config save dialog. + * + **/ + +static void xconfig_file_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + const gchar *filename = + gtk_entry_get_text(GTK_ENTRY(ctk_object->txt_xconfig_file)); + gint result; + + + /* Ask user for a filename */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_xconfig_file), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + + gtk_file_selection_set_filename + (GTK_FILE_SELECTION(ctk_object->dlg_xconfig_file), filename); + + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_xconfig_file)); + gtk_widget_hide(ctk_object->dlg_xconfig_file); + + switch (result) { + case GTK_RESPONSE_ACCEPT: + case GTK_RESPONSE_OK: + + filename = gtk_file_selection_get_filename + (GTK_FILE_SELECTION(ctk_object->dlg_xconfig_file)); + + gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_xconfig_file), + filename); + break; + default: + return; + } + +} /* xconfig_file_clicked() */ + + + +/** xconfig_preview_clicked() **************************************** + * + * Called when the user clicks on the "Preview" button of the + * X Config save dialog. + * + **/ + +static void xconfig_preview_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gboolean show = !GTK_WIDGET_VISIBLE(ctk_object->box_xconfig_save); + + if (show) { + gtk_widget_show_all(ctk_object->box_xconfig_save); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_xconfig_save), + TRUE); + gtk_widget_set_size_request(ctk_object->txt_xconfig_save, 450, 350); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_xconfig_preview), + "Hide Preview..."); + } else { + gtk_widget_hide(ctk_object->box_xconfig_save); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_xconfig_save), + FALSE); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_xconfig_preview), + "Show Preview..."); + } + +} /* xconfig_preview_clicked() */ + + + +/** makeXConfigModeline() ******************************************** + * + * Returns a copy of an XF86Config-parser modeline structure. + * + */ + +static XConfigModeLinePtr makeXConfigModeline(nvModeLinePtr modeline) +{ + XConfigModeLinePtr xconf_modeline; + + if (!modeline) return NULL; + + xconf_modeline = (XConfigModeLinePtr) malloc(sizeof(XConfigModeLineRec)); + if (!xconf_modeline) return NULL; + + *xconf_modeline = modeline->data; + + if (modeline->xconfig_name) { + xconf_modeline->identifier = strdup(modeline->xconfig_name); + } else if (modeline->data.identifier) { + xconf_modeline->identifier = strdup(modeline->data.identifier); + } + + if (modeline->data.comment) { + xconf_modeline->comment = strdup(modeline->data.comment); + } + + return xconf_modeline; + +} /* makeXConfigModeline() */ + + + +/* + * add_modelines_to_monitor() - Given a list of modes "modes", this + * function adds all the user-specified modelines in use to the + * X config monitor "monitor"'s modeline list. + */ + +static Bool add_modelines_to_monitor(XConfigMonitorPtr monitor, + nvModePtr modes) +{ + XConfigModeLinePtr modeline; + nvModePtr mode; + + /* Add modelines from the list of modes given */ + for (mode = modes; mode; mode = mode->next) { + if (!mode->modeline) continue; + + /* Only add modelines that originated from the X Config + * or that were added through NV-CONTROL. + */ + if (!(mode->modeline->source & MODELINE_SOURCE_USER)) continue; + + /* Don't add the same modeline twice */ + if ((mode->modeline->source & MODELINE_SOURCE_XCONFIG)) { + if (xconfigFindModeLine(mode->modeline->xconfig_name, + monitor->modelines)) continue; + } else { + if (xconfigFindModeLine(mode->modeline->data.identifier, + monitor->modelines)) continue; + } + + /* Dupe the modeline and add it to the monitor section */ + modeline = makeXConfigModeline(mode->modeline); + if (!modeline) continue; + + /* Append to the end of the modeline list */ + monitor->modelines = + (XConfigModeLinePtr)xconfigAddListItem((GenericListPtr)monitor->modelines, + (GenericListPtr)modeline); + } + + return TRUE; + +} /* add_modelines_to_monitor() */ + + + +/* + * add_monitor_to_xconfig() - Adds the given display device's information + * to the X configuration structure. + */ + +static Bool add_monitor_to_xconfig(nvDisplayPtr display, XConfigPtr config, + int monitor_id) +{ + XConfigMonitorPtr monitor; + XConfigOptionPtr opt = NULL; + ReturnStatus ret; + char *range_str = NULL; + char *tmp; + char *v_source = NULL; + char *h_source = NULL; + float min, max; + + monitor = (XConfigMonitorPtr)calloc(1, sizeof(XConfigMonitorRec)); + if (!monitor) goto fail; + + monitor->identifier = (char *)malloc(32); + snprintf(monitor->identifier, 32, "Monitor%d", monitor_id); + monitor->vendor = xconfigStrdup("Unknown"); /* XXX */ + monitor->modelname = xconfigStrdup(display->name); + + /* Get the Horizontal Sync ranges from nv-control */ + + ret = NvCtrlGetStringDisplayAttribute + (display->gpu->handle, + display->device_mask, + NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES, + &range_str); + if (ret != NvCtrlSuccess) { + nv_error_msg("Unable to determine valid horizontal sync ranges " + "for display device '%s' (GPU: %s)!", + display->name, display->gpu->name); + goto fail; + } + + /* Skip tokens */ + tmp = strstr(range_str, "::"); + if (tmp) { + *tmp = '\0'; + tmp += 2; + } + + if (!read_float_range(tmp, &min, &max)) { + nv_error_msg("Unable to determine valid horizontal sync ranges " + "for display device '%s' (GPU: %s)!", + display->name, display->gpu->name); + goto fail; + } + + monitor->n_hsync = 1; + monitor->hsync[0].lo = min; + monitor->hsync[0].hi = max; + + parse_tokens(range_str, apply_monitor_token, (void *)(&h_source)); + free(range_str); + range_str = NULL; + + /* Get the Horizontal Sync ranges from nv-control */ + + ret = NvCtrlGetStringDisplayAttribute + (display->gpu->handle, + display->device_mask, + NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES, + &range_str); + if (ret != NvCtrlSuccess) { + nv_error_msg("Unable to determine valid vertical refresh ranges " + "for display device '%s' (GPU: %s)!", + display->name, display->gpu->name); + goto fail; + } + + /* Skip tokens */ + tmp = strstr(range_str, "::"); + if (tmp) { + *tmp = '\0'; + tmp += 2; + } + + if (!read_float_range(tmp, &min, &max)) { + nv_error_msg("Unable to determine valid vertical refresh ranges " + "for display device '%s' (GPU: %s)!", + display->name, display->gpu->name); + goto fail; + } + + monitor->n_vrefresh = 1; + monitor->vrefresh[0].lo = min; + monitor->vrefresh[0].hi = max; + + parse_tokens(range_str, apply_monitor_token, (void *)(&v_source)); + free(range_str); + range_str = NULL; + + if (h_source && v_source) { + monitor->comment = + g_strdup_printf(" # HorizSync source: %s, " + "VertRefresh source: %s\n", + h_source, v_source); + } + free(h_source); + free(v_source); + + /* Add other options */ + + opt = xconfigAddNewOption(opt, xconfigStrdup("DPMS"), NULL); + monitor->options = opt; + + /* Add modelines used by this display */ + + add_modelines_to_monitor(monitor, display->modes); + + /* Append the monitor to the end of the monitor list */ + + config->monitors = + (XConfigMonitorPtr)xconfigAddListItem((GenericListPtr)config->monitors, + (GenericListPtr)monitor); + + display->conf_monitor = monitor; + return TRUE; + + + fail: + free(range_str); + free(h_source); + free(v_source); + if (monitor) { + xconfigFreeMonitorList(monitor); + } + return FALSE; + +} /* add_monitor_to_xconfig() */ + + + +/* + * add_device_to_xconfig() - Adds the given device (GPU)'s information + * to the X configuration file. If a valid screen order number is given, + * it is also included (This is required for having separate X screens + * driven by a single GPU.) + */ + +static XConfigDevicePtr add_device_to_xconfig(nvGpuPtr gpu, XConfigPtr config, + int device_id, int screen_id, + int print_bus_id) +{ + XConfigDevicePtr device; + + device = (XConfigDevicePtr)calloc(1, sizeof(XConfigDeviceRec)); + if (!device) goto fail; + + + /* Fill out the device information */ + device->identifier = (char *)malloc(32); + snprintf(device->identifier, 32, "Videocard%d", device_id); + + device->driver = xconfigStrdup("nvidia"); + device->vendor = xconfigStrdup("NVIDIA Corporation"); + device->board = xconfigStrdup(gpu->name); + + if (print_bus_id) { + device->busid = (char *)malloc(32); + snprintf(device->busid, 32, "PCI:%d:%d:0", + gpu->pci_bus, gpu->pci_device); + } + + device->chipid = -1; + device->chiprev = -1; + device->irq = -1; + device->screen = screen_id; + + + /* Append to the end of the device list */ + config->devices = + (XConfigDevicePtr)xconfigAddListItem((GenericListPtr)config->devices, + (GenericListPtr)device); + + return device; + + fail: + if (device) { + xconfigFreeDeviceList(device); + } + return NULL; + +} /* add_device_to_xconfig() */ + + + +/* + * add_display_to_screen() - Sets up the display subsection of + * the X config screen structure with information from the given + * screen. + */ + +static Bool add_display_to_screen(nvScreenPtr screen, + XConfigScreenPtr conf_screen) +{ + /* Clear the display list */ + xconfigFreeDisplayList(conf_screen->displays); + conf_screen->displays = NULL; + + + /* Add a single display subsection for the default depth */ + conf_screen->displays = xconfigAddDisplay(NULL, conf_screen->defaultdepth); + if (!conf_screen->displays) goto fail; + + + /* XXX Don't do any further tweaking to the display subsection. + * All mode configuration should be done through the 'MetaModes" + * X Option. The modes generated by xconfigAddDisplay() will + * be used as a fallack. + */ + + return TRUE; + + fail: + xconfigFreeDisplayList(conf_screen->displays); + conf_screen->displays = NULL; + + return FALSE; + +} /* add_display_to_screen() */ + + + +/* + * add_screen_to_xconfig() - Adds the given X Screen's information + * to the X configuration structure. + */ + +static Bool add_screen_to_xconfig(CtkDisplayConfig *ctk_object, + nvScreenPtr screen, XConfigPtr config, + int screen_id) +{ + XConfigScreenPtr conf_screen; + nvDisplayPtr display; + nvDisplayPtr other; + char *metamode_strs; + + conf_screen = (XConfigScreenPtr)calloc(1, sizeof(XConfigScreenRec)); + if (!conf_screen) goto fail; + + + /* Fill out the screen information */ + conf_screen->identifier = (char *)malloc(32); + snprintf(conf_screen->identifier, 32, "Screen%d", screen_id); + + + /* Tie the screen to its device section */ + conf_screen->device_name = + xconfigStrdup(screen->conf_device->identifier); + conf_screen->device = screen->conf_device; + + + /* Find the first display on the screen */ + for (display = screen->gpu->displays; display; display = display->next) { + if (display->screen == screen) { + break; + } + } + if (!display) { + nv_error_msg("Unable to find a display device for screen %d!", + screen->scrnum); + goto fail; + } + + + /* Create the screen's only Monitor section from the first display */ + if (!add_monitor_to_xconfig(display, config, screen_id)) { + nv_error_msg("Failed to add display device '%s' to screen %d!", + display->name, screen->scrnum); + goto fail; + } + + + /* Tie the screen to the monitor section */ + conf_screen->monitor_name = + xconfigStrdup(display->conf_monitor->identifier); + conf_screen->monitor = display->conf_monitor; + + + /* Add the modelines of all other connected displays to the monitor */ + for (other = screen->gpu->displays; other; other = other->next) { + if (other->screen != screen) continue; + if (other == display) continue; + + /* Add modelines used by this display */ + add_modelines_to_monitor(display->conf_monitor, other->modes); + } + + /* Add the TwinView option for multi monitor setups */ + if (screen->num_displays > 1) { + conf_screen->options = + xconfigAddNewOption(conf_screen->options, + xconfigStrdup("TwinView"), + xconfigStrdup("1")); + } + + /* XXX Setup any other twinview options ... */ + + /* Setup the metamode section. + * + * In basic view, always specify the currently selected + * metamode first in the list so the X server starts + * in this mode. + */ + metamode_strs = get_screen_metamode_strs(screen, 1, + !ctk_object->advanced_mode); + + /* If no user specified metamodes were found, add + * whatever the currently selected metamode is + */ + if (!metamode_strs) { + metamode_strs = get_screen_metamode_str(screen, + screen->cur_metamode_idx, 1); + } + + if (metamode_strs) { + conf_screen->options = + xconfigAddNewOption(conf_screen->options, + xconfigStrdup("metamodes"), + metamode_strs); + } + + + /* Setup the display section */ + conf_screen->defaultdepth = screen->depth; + + + /* Setup the display subsection of the screen */ + if (!add_display_to_screen(screen, conf_screen)) { + nv_error_msg("Failed to add Display section for screen %d!", + screen->scrnum); + goto fail; + } + + + /* Append to the end of the screen list */ + config->screens = + (XConfigScreenPtr)xconfigAddListItem((GenericListPtr)config->screens, + (GenericListPtr)conf_screen); + + screen->conf_screen = conf_screen; + return TRUE; + + fail: + if (conf_screen) { + xconfigFreeScreenList(conf_screen); + } + return FALSE; + +} /* add_screen_to_xconfig() */ + + + +/* + * add_screens_to_xconfig() - Adds all the X Screens in the given + * layout to the X configuration structure. + */ + +static Bool add_screens_to_xconfig(CtkDisplayConfig *ctk_object, + nvLayoutPtr layout, XConfigPtr config) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + int device_id, screen_id; + int print_bus_ids; + + + /* Clear the screen list */ + xconfigFreeMonitorList(config->monitors); + config->monitors = NULL; + xconfigFreeDeviceList(config->devices); + config->devices = NULL; + xconfigFreeScreenList(config->screens); + config->screens = NULL; + + /* Don't print the bus ID in the case where we have a single + * GPU driving a single X Screen + */ + if (layout->num_gpus == 1 && + layout->gpus->num_screens == 1) { + print_bus_ids = 0; + } else { + print_bus_ids = 1; + } + + /* Generate the Device sections and Screen sections */ + + device_id = 0; + screen_id = 0; + + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + int device_screen_id = -1; + + for (screen = gpu->screens; screen; screen = screen->next) { + + /* Only print a screen number if more than 1 screen on gpu */ + if (gpu->num_screens > 1) { + device_screen_id++; + } + + /* Each screen needs a unique device section */ + screen->conf_device = add_device_to_xconfig(gpu, config, + device_id, + device_screen_id, + print_bus_ids); + if (!screen->conf_device) { + nv_error_msg("Failed to add Device '%s' to X Config.", + gpu->name); + goto fail; + } + + if (!add_screen_to_xconfig(ctk_object, screen, + config, screen_id)) { + nv_error_msg("Failed to add X Screen %d to X Config.", + screen->scrnum); + goto fail; + } + + device_id++; + screen_id++; + } + } + return TRUE; + + fail: + xconfigFreeMonitorList(config->monitors); + config->monitors = NULL; + xconfigFreeDeviceList(config->devices); + config->devices = NULL; + xconfigFreeScreenList(config->screens); + config->screens = NULL; + return FALSE; + +} /* add_screens_to_xconfig() */ + + + +/* + * add_adjacency_to_xconfig() - Adds the given X screen's positioning + * information to an X config structure. + */ + +static Bool add_adjacency_to_xconfig(nvScreenPtr screen, XConfigPtr config, + int scrnum) +{ + XConfigAdjacencyPtr adj; + XConfigLayoutPtr conf_layout = config->layouts; + + + adj = (XConfigAdjacencyPtr) calloc(1, sizeof(XConfigAdjacencyRec)); + if (!adj) return FALSE; + + adj->scrnum = scrnum; + adj->screen = screen->conf_screen; + adj->screen_name = xconfigStrdup(screen->conf_screen->identifier); + + /* Position the X Screen */ + if (screen->position_type == CONF_ADJ_ABSOLUTE) { + adj->x = screen->dim[X]; + adj->y = screen->dim[Y]; + } else { + adj->where = screen->position_type; + adj->refscreen = + xconfigStrdup(screen->relative_to->conf_screen->identifier); + adj->x = screen->x_offset; + adj->y = screen->y_offset; + } + + /* Append to the end of the screen list */ + conf_layout->adjacencies = + (XConfigAdjacencyPtr)xconfigAddListItem((GenericListPtr)conf_layout->adjacencies, + (GenericListPtr)adj); + + return TRUE; + +} /* add_adjacency_to_xconfig() */ + + + +/* + * add_layout_to_xconfig() - Adds layout (adjacency/X Screen + * positioning) information to the X config structure based + * in the layout given. + */ + +static Bool add_layout_to_xconfig(nvLayoutPtr layout, XConfigPtr config) +{ + XConfigLayoutPtr conf_layout; + nvGpuPtr gpu; + nvScreenPtr screen; + int scrnum; + + + /* Just modify the first layout */ + conf_layout = config->layouts; + if (!conf_layout) { + nv_error_msg("Unable to generate initial layout!"); + goto fail; + } + + + /* Clean up the adjacencies */ + xconfigFreeAdjacencyList(conf_layout->adjacencies); + conf_layout->adjacencies = NULL; + + + /* Assign the adjacencies */ + scrnum = 0; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + if (!add_adjacency_to_xconfig(screen, config, scrnum)) goto fail; + scrnum++; + } + } + + + /* Setup for Xinerama */ + if (!config->flags) { + config->flags = (XConfigFlagsPtr) calloc(1, sizeof(XConfigFlagsRec)); + if (!config->flags) goto fail; + } + config->flags->options = + xconfigAddNewOption(config->flags->options, + xconfigStrdup("Xinerama"), + xconfigStrdup(layout->xinerama_enabled?"1":"0")); + + layout->conf_layout = conf_layout; + return TRUE; + + fail: + return FALSE; + +} /* add_layout_to_xconfig() */ + + + +/* + * get_default_project_root() - scan some common directories for the X + * project root + * + * Users of this information should be careful to account for the + * modular layout. + */ + +char *get_default_project_root(void) +{ + char *paths[] = { "/usr/X11R6", "/usr/X11", NULL }; + struct stat stat_buf; + int i; + + for (i = 0; paths[i]; i++) { + + if (stat(paths[i], &stat_buf) == -1) { + continue; + } + + if (S_ISDIR(stat_buf.st_mode)) { + return paths[i]; + } + } + + /* default to "/usr/X11R6", I guess */ + + return paths[0]; + +} /* get_default_project_root() */ + + + +/* + * generateXConfig() - Generates an X config structure based + * on the layout given. + */ + +static XConfigPtr generateXConfig(CtkDisplayConfig *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + XConfigPtr config = NULL; + GenerateOptions go; + char *server_vendor; + + + /* Query server Xorg/XFree86 */ + server_vendor = NvCtrlGetServerVendor(layout->handle); + if (server_vendor && g_strrstr(server_vendor, "X.Org")) { + go.xserver = X_IS_XORG; + } else { + go.xserver = X_IS_XF86; + } + + + /* XXX Assume we are creating an X config file for the local system */ + go.x_project_root = get_default_project_root(); + go.keyboard = NULL; + go.mouse = NULL; + go.keyboard_driver = NULL; + + + /* Generate the basic layout */ + config = xconfigGenerate(&go); + + + /* Repopulate the X config file with the right information */ + if (!add_screens_to_xconfig(ctk_object, layout, config)) { + nv_error_msg("Failed to add X Screens to X Config."); + goto fail; + } + if (!add_layout_to_xconfig(layout, config)) { + nv_error_msg("Failed to add Server Layout to X Config."); + goto fail; + } + + return config; + + fail: + if (config) { + xconfigFreeConfig(config); + } + return NULL; + +} /* generateXConfig() */ + + + +/* + * tilde_expansion() - do tilde expansion on the given path name; + * based loosely on code snippets found in the comp.unix.programmer + * FAQ. The tilde expansion rule is: if a tilde ('~') is alone or + * followed by a '/', then substitute the current user's home + * directory; if followed by the name of a user, then substitute that + * user's home directory. + * + * Code adapted from nvidia-xconfig + */ + +char *tilde_expansion(char *str) +{ + char *prefix = NULL; + char *replace, *user, *ret; + struct passwd *pw; + int len; + + if ((!str) || (str[0] != '~')) return str; + + if ((str[1] == '/') || (str[1] == '\0')) { + + /* expand to the current user's home directory */ + + prefix = getenv("HOME"); + if (!prefix) { + + /* $HOME isn't set; get the home directory from /etc/passwd */ + + pw = getpwuid(getuid()); + if (pw) prefix = pw->pw_dir; + } + + replace = str + 1; + + } else { + + /* expand to the specified user's home directory */ + + replace = strchr(str, '/'); + if (!replace) replace = str + strlen(str); + + len = replace - str; + user = malloc(len + 1); + strncpy(user, str+1, len-1); + user[len] = '\0'; + pw = getpwnam(user); + if (pw) prefix = pw->pw_dir; + free (user); + } + + if (!prefix) return str; + + ret = malloc(strlen(prefix) + strlen(replace) + 1); + strcpy(ret, prefix); + strcat(ret, replace); + + return ret; + +} /* tilde_expansion() */ + + + +/* + * update_banner() - add our banner at the top of the config, but + * first we need to remove any lines that already include our prefix + * (because presumably they are a banner from an earlier run of + * nvidia-settings) + * + * Code adapted from nvidia-xconfig + */ + +extern const char *pNV_ID; + +static void update_banner(XConfigPtr config) +{ + static const char *banner = + "X configuration file generated by nvidia-settings\n"; + static const char *prefix = + "# nvidia-settings: "; + + char *s = config->comment; + char *line, *eol, *tmp; + + /* remove all lines that begin with the prefix */ + + while (s && (line = strstr(s, prefix))) { + + eol = strchr(line, '\n'); /* find the end of the line */ + + if (eol) { + eol++; + if (*eol == '\0') eol = NULL; + } + + if (line == s) { /* the line with the prefix is at the start */ + if (eol) { /* there is more after the prefix line */ + tmp = g_strdup(eol); + g_free(s); + s = tmp; + } else { /* the prefix line is the only line */ + g_free(s); + s = NULL; + } + } else { /* prefix line is in the middle or end */ + *line = '\0'; + tmp = g_strconcat(s, eol, NULL); + g_free(s); + s = tmp; + } + } + + /* add our prefix lines at the start of the comment */ + config->comment = g_strconcat(prefix, banner, + "# ", pNV_ID, "\n", + (s ? s : ""), + NULL); + if (s) g_free(s); + +} /* update_banner() */ + + + +/** save_xconfig_file() ********************************************** + * + * Saves the X config file text from buf into a file called + * filename. If filename already exists, a backup file named + * 'filename.backup' is created. + * + **/ + +static int save_xconfig_file(gchar *filename, char *buf, mode_t mode) +{ + gchar *backup_filename = NULL; + FILE *fp = NULL; + size_t size; + + int ret = 0; + + + if (!buf || !filename) goto done; + + size = strlen(buf) ; + + /* Backup any existing file */ + if ((access(filename, F_OK) == 0)) { + + backup_filename = g_strdup_printf("%s.backup", filename); + nv_info_msg("", "X configuration file '%s' already exists, " + "backing up file as '%s'", filename, + backup_filename); + + /* Delete any existing backup file */ + if (access(backup_filename, F_OK) == 0) { + + if (unlink(backup_filename) != 0) { + nv_error_msg("Unable to create backup file '%s'.", + backup_filename); + goto done; + } + } + + /* Make the current x config file the backup */ + if (rename(filename, backup_filename)) { + nv_error_msg("Unable to create backup file '%s'.", + backup_filename); + goto done; + } + } + + /* Write out the X Config file */ + fp = fopen(filename, "w"); + if (!fp) { + nv_error_msg("Unable to open file '%s' for writing.", + filename); + goto done; + } + fprintf(fp, "%s", buf); + + ret = 1; + + done: + + if (fp) fclose(fp); + g_free(backup_filename); + return ret; + +} /* save_xconfig_file() */ + + + +/** save_clicked() *************************************************** + * + * Called when the user clicks on the "Save" button. + * + **/ + +static void save_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gint result; + + gchar *filename; + XConfigPtr config = NULL; + + char *tmp_filename; + int tmp_fd; + struct stat st; + void *buf; + GtkTextIter buf_start, buf_end; + + + /* Make sure the layout is ready to be saved */ + if (!validate_layout(ctk_object)) { + return; + } + + + /* Setup the default X config filename */ + if (!ctk_object->layout->filename) { + filename = (gchar *) xconfigOpenConfigFile(NULL, NULL); + if (filename) { + ctk_object->layout->filename = g_strdup(filename); + xconfigCloseConfigFile(); + filename = NULL; + } else { + ctk_object->layout->filename = g_strdup(""); + } + } + gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_xconfig_file), + ctk_object->layout->filename); + + + /* Generate an X Config file from the layout */ + config = generateXConfig(ctk_object); + if (!config) { + nv_error_msg("Failed to generate an X config file!"); + return; + } + + /* Update the X Config banner */ + update_banner(config); + + /* Setup the X config file preview buffer by writing to a temp file */ + tmp_filename = g_strdup_printf("/tmp/.xconfig.tmp.XXXXXX"); + tmp_fd = mkstemp(tmp_filename); + if (!tmp_fd) { + nv_error_msg("Failed to create temp file for displaying X config!"); + g_free(tmp_filename); + return; + } + xconfigWriteConfigFile(tmp_filename, config); + xconfigFreeConfig(config); + + lseek(tmp_fd, 0, SEEK_SET); + fstat(tmp_fd, &st); + buf = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0); + gtk_text_buffer_set_text(GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save), + buf, st.st_size); + munmap(buf, st.st_size); + close(tmp_fd); + remove(tmp_filename); + g_free(tmp_filename); + + + /* Confirm the save */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_xconfig_save), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_hide(ctk_object->box_xconfig_save); + gtk_window_resize(GTK_WINDOW(ctk_object->dlg_xconfig_save), 350, 1); + gtk_window_set_resizable(GTK_WINDOW(ctk_object->dlg_xconfig_save), + FALSE); + gtk_button_set_label(GTK_BUTTON(ctk_object->btn_xconfig_preview), + "Show preview..."); + gtk_widget_show(ctk_object->dlg_xconfig_save); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_xconfig_save)); + gtk_widget_hide(ctk_object->dlg_xconfig_save); + + + /* Handle user's response */ + switch (result) + { + case GTK_RESPONSE_ACCEPT: + + /* Get the filename to write to */ + filename = + (gchar *) gtk_entry_get_text(GTK_ENTRY(ctk_object->txt_xconfig_file)); + + g_free(ctk_object->layout->filename); + ctk_object->layout->filename = tilde_expansion(filename); + if (ctk_object->layout->filename == filename) { + ctk_object->layout->filename = g_strdup(filename); + } + filename = ctk_object->layout->filename; + + + /* Get the buffer to write */ + gtk_text_buffer_get_bounds + (GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save), &buf_start, + &buf_end); + buf = (void *) gtk_text_buffer_get_text + (GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save), &buf_start, + &buf_end, FALSE); + if (!buf) { + nv_error_msg("Failed to read X configuration buffer!"); + break; + } + + /* Save the X config file */ + nv_info_msg("", "Writing X Config file '%s'", filename); + save_xconfig_file(filename, (char *)buf, 0644); + g_free(buf); + break; + + case GTK_RESPONSE_REJECT: + default: + /* do nothing. */ + break; + } + +} /* save_clicked() */ + + + +/** advanced_clicked() *********************************************** + * + * Called when user clicks on the "Advanced..." button. + * + **/ + +static void advanced_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + + + /* Toggle advanced options for the display */ + ctk_object->advanced_mode = !(ctk_object->advanced_mode); + + + /* Show advanced display options */ + if (ctk_object->advanced_mode) { + gtk_button_set_label(GTK_BUTTON(widget), "Basic..."); + ctk_display_layout_set_advanced_mode(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + 1); + + /* Show basic display options */ + } else { + gtk_button_set_label(GTK_BUTTON(widget), "Advanced..."); + ctk_display_layout_set_advanced_mode(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + 0); + } + + + /* Update the GUI to show the right widgets */ + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + +} /* advanced_clicked() */ + + + +/** probe_clicked() ************************************************** + * + * Called when user clicks on the "Probe" button. + * + **/ + +static void probe_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + unsigned int probed_displays; + unsigned int mask; + nvGpuPtr gpu; + nvDisplayPtr display; + nvDisplayPtr selected_display = ctk_display_layout_get_selected_display + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + ReturnStatus ret; + gchar *type; + gchar *str; + + + /* Probe each GPU for display changes */ + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + if (!gpu->handle) continue; + + + /* Do the probe */ + ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PROBE_DISPLAYS, + (int *)&probed_displays); + if (ret != NvCtrlSuccess) { + nv_error_msg("Failed to probe for display devices on GPU-%d '%s'.", + NvCtrlGetTargetId(gpu->handle), gpu->name); + continue; + } + + /* Make sure other parts of nvidia-settings get updated */ + ctk_event_emit(gpu->ctk_event, 0, + NV_CTRL_PROBE_DISPLAYS, probed_displays); + + /* Go through the probed displays */ + for (mask = 1; mask; mask <<= 1) { + + /* Ask users about removing old displays */ + if ((gpu->connected_displays & mask) && + !(probed_displays & mask)) { + + display = get_display_from_gpu(gpu, mask); + if (!display) continue; /* XXX ack. */ + + /* The selected display is being removed */ + if (display == selected_display) { + selected_display = NULL; + } + + /* Setup the remove display dialog */ + type = get_display_type_str(display->device_mask, 0); + str = g_strdup_printf("The display device %s (%s) on GPU-%d " + "(%s) has been\nunplugged. Would you " + "like to remove this display from the " + "layout?", + display->name, type, + NvCtrlGetTargetId(gpu->handle), + gpu->name); + g_free(type); + gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_disable), + str); + g_free(str); + + gtk_button_set_label + (GTK_BUTTON(ctk_object->btn_display_disable_off), + "Remove"); + + gtk_button_set_label + (GTK_BUTTON(ctk_object->btn_display_disable_cancel), + "Ignore"); + + /* Ask the user if they want to remove the display */ + if (do_query_remove_display(ctk_object, display)) { + + /* Remove display from the GPU */ + remove_display_from_gpu(display); + free_display(display); + + /* Let display layout widget know about change */ + ctk_display_layout_update_display_count + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), NULL); + + /* Activate the apply button */ + gtk_widget_set_sensitive(ctk_object->btn_apply, True); + } + + /* Add new displays as 'disabled' */ + } else if (!(gpu->connected_displays & mask) && + (probed_displays & mask)) { + gchar *err_str = NULL; + display = add_display_to_gpu(gpu, mask, &err_str); + if (err_str) { + nv_warning_msg(err_str); + g_free(err_str); + } + add_screenless_modes_to_displays(gpu); + ctk_display_layout_update_display_count + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + selected_display); + } + } + } + + + /* Sync the GUI */ + ctk_display_layout_redraw(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout)); + + setup_display_frame(ctk_object); + + setup_screen_frame(ctk_object); + +} /* probe_clicked() */ + + + +/** reset_clicked() ************************************************** + * + * Called when user clicks on the "Reset" button. + * + **/ + +static void reset_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + nvLayoutPtr layout; + gint result; + gchar *err_str = NULL; + + + /* Show the confirm dialog */ + gtk_window_set_transient_for + (GTK_WINDOW(ctk_object->dlg_reset_confirm), + GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(ctk_object)))); + gtk_widget_grab_focus(ctk_object->btn_reset_cancel); + gtk_widget_show(ctk_object->dlg_reset_confirm); + result = gtk_dialog_run(GTK_DIALOG(ctk_object->dlg_reset_confirm)); + gtk_widget_hide(ctk_object->dlg_reset_confirm); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + /* User wants to reset the configuration */ + break; + + case GTK_RESPONSE_REJECT: + default: + /* User doesn't want to reset the configuration */ + return; + } + + + /* Load the current layout */ + layout = load_server_layout(ctk_object->handle, &err_str); + + + /* Handle errors loading the new layout */ + if (!layout || err_str) { + nv_error_msg(err_str); + g_free(err_str); + return; + } + + + /* Free the existing layout */ + if (ctk_object->layout) { + remove_gpus_from_layout(ctk_object->layout); + free(ctk_object->layout); + } + + + /* Setup the new layout */ + ctk_object->layout = layout; + ctk_display_layout_set_layout((CtkDisplayLayout *)(ctk_object->obj_layout), + ctk_object->layout); + + + /* Make sure X Screens have some kind of position */ + assign_screen_positions(ctk_object); + + + /* Setup the GUI */ + setup_layout_frame(ctk_object); + setup_display_frame(ctk_object); + setup_screen_frame(ctk_object); + + /* Get new position */ + get_cur_screen_pos(ctk_object); + + /* Clear the apply button */ + ctk_object->apply_possible = TRUE; + gtk_widget_set_sensitive(ctk_object->btn_apply, FALSE); + +} /* reset_clicked() */ + + + +/** validation_details_clicked() ************************************* + * + * Callback for when the user clicks on the "Show/Hide Details" + * button in the validation confirmation dialog. + * + **/ + +static void validation_details_clicked(GtkWidget *widget, gpointer user_data) +{ + CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data); + gboolean show = + !(GTK_WIDGET_VISIBLE(ctk_object->box_validation_override_details)); + + if (show) { + gtk_widget_show_all(ctk_object->box_validation_override_details); + gtk_window_set_resizable + (GTK_WINDOW(ctk_object->dlg_validation_override), TRUE); + gtk_widget_set_size_request + (ctk_object->box_validation_override_details, 450, 150); + gtk_button_set_label + (GTK_BUTTON(ctk_object->btn_validation_override_show), + "Hide Details..."); + } else { + gtk_widget_hide(ctk_object->box_validation_override_details); + gtk_window_set_resizable + (GTK_WINDOW(ctk_object->dlg_validation_override), FALSE); + gtk_button_set_label + (GTK_BUTTON(ctk_object->btn_validation_override_show), + "Show Details..."); + } + +} /* validation_details_clicked() */ diff --git a/src/gtk+-2.x/ctkdisplayconfig.h b/src/gtk+-2.x/ctkdisplayconfig.h new file mode 100644 index 0000000..75a96c1 --- /dev/null +++ b/src/gtk+-2.x/ctkdisplayconfig.h @@ -0,0 +1,197 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_DISPLAYCONFIG_H__ +#define __CTK_DISPLAYCONFIG_H__ + +#include "ctkevent.h" +#include "ctkconfig.h" +#include "ctkdisplaylayout.h" + + +G_BEGIN_DECLS + +#define CTK_TYPE_DISPLAY_CONFIG (ctk_display_config_get_type()) + +#define CTK_DISPLAY_CONFIG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_DISPLAY_CONFIG, \ + CtkDisplayConfig)) + +#define CTK_DISPLAY_CONFIG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_DISPLAY_CONFIG, \ + CtkDisplayConfigClass)) + +#define CTK_IS_DISPLAY_CONFIG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_DISPLAY_CONFIG)) + +#define CTK_IS_DISPLAY_CONFIG_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_DISPLAY_CONFIG)) + +#define CTK_DISPLAY_CONFIG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_DISPLAY_CONFIG, \ + CtkDisplayConfigClass)) + + +typedef struct _CtkDisplayConfig +{ + GtkVBox parent; + + NvCtrlAttributeHandle *handle; + CtkConfig *ctk_config; + + + /* Layout */ + nvLayoutPtr layout; + GtkWidget *obj_layout; + + GtkWidget *chk_xinerama_enabled; + + + /* Display - Info */ + GtkWidget *display_frame; + + GtkWidget *txt_display_model; + GtkWidget *txt_display_gpu; + + GtkWidget *btn_display_config; + GtkWidget *txt_display_config; + + /* Display - Settings */ + GtkWidget *box_display_resolution; + GtkWidget *mnu_display_resolution; + nvModeLinePtr *resolution_table; + int resolution_table_len; + + GtkWidget *mnu_display_refresh; + nvModeLinePtr *refresh_table; /* Lookup table for refresh menu */ + int refresh_table_len; + + GtkWidget *box_display_modename; + GtkWidget *txt_display_modename; + + GtkWidget *box_display_position; + GtkWidget *mnu_display_position_type; /* Absolute, Right of... */ + GtkWidget *mnu_display_position_relative; /* List of available devices */ + nvDisplayPtr *display_position_table; /* Lookup table for relative display position */ + int display_position_table_len; + GtkWidget *txt_display_position_offset; /* Absolute: +0+0 */ + + GtkWidget *box_display_panning; + GtkWidget *txt_display_panning; + + + /* X Screen - Info */ + GtkWidget *screen_frame; + + GtkWidget *txt_screen_num; + + /* X Screen - Settings */ + GtkWidget *box_screen_depth; + GtkWidget *mnu_screen_depth; + + GtkWidget *box_screen_position; + GtkWidget *mnu_screen_position_type; /* Absolute, Right of... */ + GtkWidget *mnu_screen_position_relative; /* List of available devices */ + nvScreenPtr *screen_position_table; + int screen_position_table_len; + GtkWidget *txt_screen_position_offset; /* Absolute: +0+0 */ + + GtkWidget *box_screen_metamode; + GtkWidget *btn_screen_metamode; + GtkWidget *btn_screen_metamode_add; + GtkWidget *btn_screen_metamode_delete; + + + /* Dialogs */ + GtkWidget *dlg_display_config; + GtkWidget *rad_display_config_disabled; + GtkWidget *rad_display_config_xscreen; + GtkWidget *rad_display_config_twinview; + GtkWidget *btn_display_config_cancel; + + GtkWidget *dlg_display_disable; + GtkWidget *txt_display_disable; + GtkWidget *btn_display_disable_off; + GtkWidget *btn_display_disable_cancel; + + GtkWidget *dlg_validation_override; + GtkTextBuffer *buf_validation_override; + GtkWidget *btn_validation_override_cancel; + GtkWidget *box_validation_override_details; + GtkWidget *btn_validation_override_show; /* Show details */ + + GtkWidget *dlg_validation_apply; + + GtkWidget *dlg_reset_confirm; + GtkWidget *btn_reset_cancel; + + GtkWidget *dlg_display_confirm; + GtkWidget *txt_display_confirm; + GtkWidget *btn_display_apply_cancel; + guint display_confirm_timer; + int display_confirm_countdown; /* Timeout to reset display config */ + + GtkWidget *dlg_xconfig_save; /* Save X config dialog */ + GtkWidget *scr_xconfig_save; + GtkWidget *txt_xconfig_save; /* Text file... */ + GtkTextBuffer *buf_xconfig_save; /* Text file... */ + GtkWidget *btn_xconfig_preview; /* Show/Hide button */ + GtkWidget *box_xconfig_save; /* Show/Hide this box */ + + GtkWidget *dlg_xconfig_file; /* File save dialog */ + GtkWidget *btn_xconfig_file; + GtkWidget *txt_xconfig_file; + + + /* Buttons */ + GtkWidget *btn_apply; + gboolean apply_possible; /* True if all modifications are applicable */ + int cur_screen_pos[2]; /* Keep track of the selected X Screen's position */ + + GtkWidget *btn_save; + GtkWidget *btn_probe; + + GtkWidget *btn_advanced; + gboolean advanced_mode; /* True if we are in advanced mode */ + + GtkWidget *btn_reset; + +} CtkDisplayConfig; + +typedef struct _CtkDisplayConfigClass +{ + GtkVBoxClass parent_class; +} CtkDisplayConfigClass; + + +GType ctk_display_config_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_display_config_new (NvCtrlAttributeHandle *, + CtkConfig *); + +GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *, + CtkDisplayConfig *); + +G_END_DECLS + +#endif /* __CTK_DISPLAYCONFIG_H__ */ diff --git a/src/gtk+-2.x/ctkdisplaydevice-crt.c b/src/gtk+-2.x/ctkdisplaydevice-crt.c index 06e1a22..cbf3583 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-crt.c +++ b/src/gtk+-2.x/ctkdisplaydevice-crt.c @@ -36,8 +36,16 @@ #include "ctkhelp.h" +static void ctk_display_device_crt_class_init(CtkDisplayDeviceCrtClass *); +static void ctk_display_device_crt_finalize(GObject *); + static void reset_button_clicked(GtkButton *button, gpointer user_data); +static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt + *ctk_display_device_crt); + +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data); GType ctk_display_device_crt_get_type(void) { @@ -48,7 +56,7 @@ GType ctk_display_device_crt_get_type(void) sizeof (CtkDisplayDeviceCrtClass), NULL, /* base_init */ NULL, /* base_finalize */ - NULL, /* class_init, */ + (GClassInitFunc) ctk_display_device_crt_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (CtkDisplayDeviceCrt), @@ -63,6 +71,26 @@ GType ctk_display_device_crt_get_type(void) return ctk_display_device_crt_type; } +static void ctk_display_device_crt_class_init( + CtkDisplayDeviceCrtClass *ctk_display_device_crt_class +) +{ + GObjectClass *gobject_class = (GObjectClass *)ctk_display_device_crt_class; + gobject_class->finalize = ctk_display_device_crt_finalize; +} + +static void ctk_display_device_crt_finalize( + GObject *object +) +{ + CtkDisplayDeviceCrt *ctk_display_device_crt = CTK_DISPLAY_DEVICE_CRT(object); + g_free(ctk_display_device_crt->name); +} + +/* + * ctk_display_device_crt_new() - constructor for the CRT display + * device page. + */ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, CtkConfig *ctk_config, @@ -74,19 +102,16 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, CtkDisplayDeviceCrt *ctk_display_device_crt; GtkWidget *banner; GtkWidget *hbox; - GtkWidget *label; GtkWidget *alignment; - GtkWidget *edid; - - char *s; object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_CRT, NULL); ctk_display_device_crt = CTK_DISPLAY_DEVICE_CRT(object); ctk_display_device_crt->handle = handle; ctk_display_device_crt->ctk_config = ctk_config; + ctk_display_device_crt->ctk_event = ctk_event; ctk_display_device_crt->display_device_mask = display_device_mask; - ctk_display_device_crt->name = name; + ctk_display_device_crt->name = g_strdup(name); gtk_box_set_spacing(GTK_BOX(object), 10); @@ -101,13 +126,8 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, * sensitivity), though we pack it at the bottom of the page */ - label = gtk_label_new("Reset Hardware Defaults"); - hbox = gtk_hbox_new(FALSE, 0); - ctk_display_device_crt->reset_button = gtk_button_new(); - - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); - gtk_container_add(GTK_CONTAINER(ctk_display_device_crt->reset_button), - hbox); + ctk_display_device_crt->reset_button = + gtk_button_new_with_label("Reset Hardware Defaults"); alignment = gtk_alignment_new(1, 1, 0, 0); gtk_container_add(GTK_CONTAINER(alignment), @@ -132,33 +152,29 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, gtk_box_pack_start(GTK_BOX(object), ctk_display_device_crt->image_sliders, FALSE, FALSE, 0); - } else { - s = g_strconcat("There are no configurable options available for ", - ctk_display_device_crt->name, ".", NULL); - - label = gtk_label_new(s); - - g_free(s); - - gtk_box_pack_start(GTK_BOX(object), label, FALSE, FALSE, 0); } /* pack the EDID button */ - edid = ctk_edid_new(handle, ctk_config, ctk_event, - ctk_display_device_crt->reset_button, - display_device_mask, name); - if (edid) { - gtk_box_pack_start(GTK_BOX(object), edid, FALSE, FALSE, 0); - ctk_display_device_crt->edid_available = TRUE; - } else { - ctk_display_device_crt->edid_available = FALSE; - } + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); + ctk_display_device_crt->edid_box = hbox; /* show the page */ gtk_widget_show_all(GTK_WIDGET(object)); + /* Update the GUI */ + + ctk_display_device_crt_setup(ctk_display_device_crt); + + /* handle enable/disable events on the display device */ + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_ENABLED_DISPLAYS), + G_CALLBACK(enabled_displays_received), + (gpointer) ctk_display_device_crt); + return GTK_WIDGET(object); } @@ -170,7 +186,6 @@ GtkTextBuffer *ctk_display_device_crt_create_help(GtkTextTagTable *table, { GtkTextIter i; GtkTextBuffer *b; - gboolean ret; b = gtk_text_buffer_new(table); @@ -178,22 +193,13 @@ GtkTextBuffer *ctk_display_device_crt_create_help(GtkTextTagTable *table, ctk_help_title(b, &i, "%s Help", ctk_display_device_crt->name); - if (ctk_display_device_crt->image_sliders) { - ret = add_image_sliders_help - (CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders), b, &i); - } else { - ret = FALSE; - } + add_image_sliders_help + (CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders), b, &i); - if (ctk_display_device_crt->edid_available) { + if (ctk_display_device_crt->edid) { add_acquire_edid_help(b, &i); } - if (!ret) { - ctk_help_para(b, &i, "There are no configurable options available " - "for %s.", ctk_display_device_crt->name); - } - ctk_help_finish(b); return b; @@ -210,13 +216,94 @@ static void reset_button_clicked(GtkButton *button, gpointer user_data) CtkDisplayDeviceCrt *ctk_display_device_crt = CTK_DISPLAY_DEVICE_CRT(user_data); - if (ctk_display_device_crt->image_sliders) { - ctk_image_sliders_reset - (CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders)); - } + ctk_image_sliders_reset + (CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders)); + + gtk_widget_set_sensitive(ctk_display_device_crt->reset_button, FALSE); ctk_config_statusbar_message(ctk_display_device_crt->ctk_config, "Reset hardware defaults for %s.", ctk_display_device_crt->name); } /* reset_button_clicked() */ + + + +/* + * Updates the display device page to reflect the current + * configuration of the display device. + */ +static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt + *ctk_display_device_crt) +{ + ReturnStatus ret; + unsigned int enabled_displays; + + + /* Is display enabled? */ + + ret = NvCtrlGetAttribute(ctk_display_device_crt->handle, + NV_CTRL_ENABLED_DISPLAYS, + (int *)&enabled_displays); + + ctk_display_device_crt->display_enabled = + (ret == NvCtrlSuccess && + (enabled_displays & (ctk_display_device_crt->display_device_mask))); + + + /* Update the image sliders */ + + ctk_image_sliders_setup + (CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders)); + + + /* update acquire EDID button */ + + if (ctk_display_device_crt->edid) { + GList *list; + + list = gtk_container_get_children + (GTK_CONTAINER(ctk_display_device_crt->edid_box)); + if (list) { + gtk_container_remove + (GTK_CONTAINER(ctk_display_device_crt->edid_box), + (GtkWidget *)(list->data)); + g_list_free(list); + } + } + + ctk_display_device_crt->edid = + ctk_edid_new(ctk_display_device_crt->handle, + ctk_display_device_crt->ctk_config, + ctk_display_device_crt->ctk_event, + ctk_display_device_crt->reset_button, + ctk_display_device_crt->display_device_mask, + ctk_display_device_crt->name); + + if (ctk_display_device_crt->edid) { + gtk_box_pack_start(GTK_BOX(ctk_display_device_crt->edid_box), + ctk_display_device_crt->edid, TRUE, TRUE, 0); + } + + + /* update the reset button */ + + gtk_widget_set_sensitive(ctk_display_device_crt->reset_button, FALSE); + +} /* ctk_display_device_crt_setup() */ + + + +/* + * When the list of enabled displays on the GPU changes, + * this page should disable/enable access based on whether + * or not the display device is enabled. + */ +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + CtkDisplayDeviceCrt *ctk_object = CTK_DISPLAY_DEVICE_CRT(user_data); + + ctk_display_device_crt_setup(ctk_object); + +} /* enabled_displays_received() */ diff --git a/src/gtk+-2.x/ctkdisplaydevice-crt.h b/src/gtk+-2.x/ctkdisplaydevice-crt.h index f31632a..56180d3 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-crt.h +++ b/src/gtk+-2.x/ctkdisplaydevice-crt.h @@ -60,12 +60,15 @@ struct _CtkDisplayDeviceCrt NvCtrlAttributeHandle *handle; CtkConfig *ctk_config; + CtkEvent *ctk_event; GtkWidget *image_sliders; GtkWidget *reset_button; + + GtkWidget *edid_box; + GtkWidget *edid; unsigned int display_device_mask; - unsigned int active_attributes; - gboolean edid_available; + gboolean display_enabled; char *name; }; diff --git a/src/gtk+-2.x/ctkdisplaydevice-dfp.c b/src/gtk+-2.x/ctkdisplaydevice-dfp.c index f5fdcf6..ead85c3 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-dfp.c +++ b/src/gtk+-2.x/ctkdisplaydevice-dfp.c @@ -37,6 +37,9 @@ #include "ctkutils.h" +static void ctk_display_device_dfp_class_init(CtkDisplayDeviceDfpClass *); +static void ctk_display_device_dfp_finalize(GObject *); + static GtkWidget *make_scaling_radio_button(CtkDisplayDeviceDfp *ctk_display_device_dfp, GtkWidget *vbox, @@ -69,12 +72,23 @@ dfp_dithering_update_radio_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp, static void dfp_update_received(GtkObject *object, gpointer arg1, gpointer user_data); +static void dfp_info_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp); + +static void dfp_scaling_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp); + +static void dfp_dithering_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp); + +static void ctk_display_device_dfp_setup(CtkDisplayDeviceDfp + *ctk_display_device_dfp); + +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data); + #define FRAME_PADDING 5 #define __SCALING (1<<0) #define __DITHERING (1<<1) -#define __INFO (1<<2) static const char *__scaling_help = @@ -103,8 +117,8 @@ GType ctk_display_device_dfp_get_type(void) sizeof (CtkDisplayDeviceDfpClass), NULL, /* base_init */ NULL, /* base_finalize */ - NULL, /* class_init, */ - NULL, /* class_finalize */ + (GClassInitFunc) ctk_display_device_dfp_class_init, + NULL, /* class_finalize, */ NULL, /* class_data */ sizeof (CtkDisplayDeviceDfp), 0, /* n_preallocs */ @@ -118,11 +132,26 @@ GType ctk_display_device_dfp_get_type(void) return ctk_display_device_dfp_type; } +static void ctk_display_device_dfp_class_init( + CtkDisplayDeviceDfpClass *ctk_display_device_dfp_class +) +{ + GObjectClass *gobject_class = (GObjectClass *)ctk_display_device_dfp_class; + gobject_class->finalize = ctk_display_device_dfp_finalize; +} + +static void ctk_display_device_dfp_finalize( + GObject *object +) +{ + CtkDisplayDeviceDfp *ctk_display_device_dfp = CTK_DISPLAY_DEVICE_DFP(object); + g_free(ctk_display_device_dfp->name); +} /* * ctk_display_device_dfp_new() - constructor for the DFP display - * device page + * device page. */ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, @@ -136,7 +165,6 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, GtkWidget *banner; GtkWidget *frame; GtkWidget *hbox, *vbox, *tmpbox; - GtkWidget *label; GtkWidget *eventbox; GtkWidget *radio0; @@ -144,13 +172,8 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, GtkWidget *radio2; GtkWidget *radio3; GtkWidget *alignment; - GtkWidget *edid; GtkWidget *table; - - ReturnStatus ret; - - gint val, i; object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_DFP, NULL); @@ -158,7 +181,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, ctk_display_device_dfp->handle = handle; ctk_display_device_dfp->ctk_config = ctk_config; ctk_display_device_dfp->display_device_mask = display_device_mask; - ctk_display_device_dfp->name = name; + ctk_display_device_dfp->name = g_strdup(name); gtk_box_set_spacing(GTK_BOX(object), 10); @@ -173,13 +196,8 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, * sensitivity), though we pack it at the bottom of the page */ - label = gtk_label_new("Reset Hardware Defaults"); - hbox = gtk_hbox_new(FALSE, 0); - ctk_display_device_dfp->reset_button = gtk_button_new(); - - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); - gtk_container_add(GTK_CONTAINER(ctk_display_device_dfp->reset_button), - hbox); + ctk_display_device_dfp->reset_button = + gtk_button_new_with_label("Reset Hardware Defaults"); alignment = gtk_alignment_new(1, 1, 0, 0); gtk_container_add(GTK_CONTAINER(alignment), @@ -200,176 +218,116 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, FRAME_PADDING); /* DFP info */ - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_CHIP_LOCATION, &val); - if (ret == NvCtrlSuccess) { - char *chip_location, *link, *signal; - gint tmp; - - /* NV_CTRL_FLATPANEL_CHIP_LOCATION */ - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_CHIP_LOCATION, &tmp); - chip_location = NULL; - if (ret == NvCtrlSuccess) { - if (tmp == NV_CTRL_FLATPANEL_CHIP_LOCATION_INTERNAL) chip_location = "Internal"; - if (tmp == NV_CTRL_FLATPANEL_CHIP_LOCATION_EXTERNAL) chip_location = "External"; - } - - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_LINK, &tmp); - link = NULL; - if (ret == NvCtrlSuccess) { - if (tmp == NV_CTRL_FLATPANEL_LINK_SINGLE) link = "Single"; - if (tmp == NV_CTRL_FLATPANEL_LINK_DUAL) link = "Dual"; - } - - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_SIGNAL, &tmp); - signal = NULL; - if (ret == NvCtrlSuccess) { - if (tmp == NV_CTRL_FLATPANEL_SIGNAL_LVDS) signal = "LVDS"; - if (tmp == NV_CTRL_FLATPANEL_SIGNAL_TMDS) signal = "TMDS"; - } - - frame = gtk_frame_new("Flat Panel Information"); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - table = gtk_table_new(3, 2, FALSE); - - /* - * insert a vbox between the frame and the table, so that the - * table doesn't expand to fill all of the space within the - * frame - */ - - tmpbox = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(tmpbox), table, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(frame), tmpbox); - - gtk_table_set_row_spacings(GTK_TABLE(table), 3); - gtk_table_set_col_spacings(GTK_TABLE(table), 15); - - gtk_container_set_border_width(GTK_CONTAINER(table), 5); + frame = gtk_frame_new("Flat Panel Information"); + gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - add_table_row(table, 0, 0, "Chip location:", chip_location); - add_table_row(table, 1, 0, "DVI connection link:", link); - add_table_row(table, 2, 0, "Signal:", signal); - - ctk_display_device_dfp->active_attributes |= __INFO; - } - else - ctk_display_device_dfp->active_attributes &= ~__INFO; + table = gtk_table_new(3, 2, FALSE); + + /* + * insert a vbox between the frame and the table, so that the + * table doesn't expand to fill all of the space within the + * frame + */ + + tmpbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(tmpbox), table, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(frame), tmpbox); + + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + ctk_display_device_dfp->txt_chip_location = + add_table_row(table, 0, + 0, 0.5, "Chip location:", + 0, 0.5, ""); + + ctk_display_device_dfp->txt_link = + add_table_row(table, 1, + 0, 0.5, "DVI connection link:", + 0, 0.5, ""); + + ctk_display_device_dfp->txt_signal = + add_table_row(table, 2, + 0, 0.5, "Signal:", + 0, 0.5, ""); /* FlatPanel Scaling */ - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_SCALING, &val); - - if (ret == NvCtrlSuccess) { - frame = gtk_frame_new("FlatPanel Scaling"); - eventbox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(eventbox), frame); - gtk_box_pack_start(GTK_BOX(hbox), eventbox, FALSE, FALSE, 0); + frame = gtk_frame_new("FlatPanel Scaling"); + eventbox = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(eventbox), frame); + gtk_box_pack_start(GTK_BOX(hbox), eventbox, FALSE, FALSE, 0); + ctk_display_device_dfp->scaling_frame = frame; - ctk_config_set_tooltip(ctk_config, eventbox, __scaling_help); - - vbox = gtk_vbox_new(FALSE, FRAME_PADDING); - gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); - gtk_container_add(GTK_CONTAINER(frame), vbox); - - - radio0 = make_scaling_radio_button - (ctk_display_device_dfp, vbox, NULL, "Default", - NV_CTRL_FLATPANEL_SCALING_DEFAULT); - - radio1 = make_scaling_radio_button - (ctk_display_device_dfp, vbox, radio0, "Scaled", - NV_CTRL_FLATPANEL_SCALING_SCALED); - - radio2 = make_scaling_radio_button - (ctk_display_device_dfp, vbox, radio1, "Centered", - NV_CTRL_FLATPANEL_SCALING_CENTERED); - - radio3 = make_scaling_radio_button - (ctk_display_device_dfp, vbox, radio2, "Fixed Aspect Ratio Scaled", - NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED); - - /* - * XXX TODO: determine when we should advertise Monitor - * Scaling (aka "Native" scaling) - */ - - ctk_display_device_dfp->scaling_buttons - [NV_CTRL_FLATPANEL_SCALING_NATIVE] = NULL; - - - dfp_scaling_update_radio_buttons(ctk_display_device_dfp, val); - - g_signal_connect(G_OBJECT(ctk_event), - CTK_EVENT_NAME(NV_CTRL_FLATPANEL_SCALING), - G_CALLBACK(dfp_update_received), - (gpointer) ctk_display_device_dfp); - - ctk_display_device_dfp->active_attributes |= __SCALING; - - } else { - - for (i = 0; i < NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED+1; i++) { - ctk_display_device_dfp->scaling_buttons[i] = NULL; - } - - ctk_display_device_dfp->active_attributes &= ~__SCALING; - } + ctk_config_set_tooltip(ctk_config, eventbox, __scaling_help); + + vbox = gtk_vbox_new(FALSE, FRAME_PADDING); + gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + radio0 = make_scaling_radio_button + (ctk_display_device_dfp, vbox, NULL, "Default", + NV_CTRL_FLATPANEL_SCALING_DEFAULT); + + radio1 = make_scaling_radio_button + (ctk_display_device_dfp, vbox, radio0, "Scaled", + NV_CTRL_FLATPANEL_SCALING_SCALED); + + radio2 = make_scaling_radio_button + (ctk_display_device_dfp, vbox, radio1, "Centered", + NV_CTRL_FLATPANEL_SCALING_CENTERED); + + radio3 = make_scaling_radio_button + (ctk_display_device_dfp, vbox, radio2, "Fixed Aspect Ratio Scaled", + NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED); + + /* + * XXX TODO: determine when we should advertise Monitor + * Scaling (aka "Native" scaling) + */ + + ctk_display_device_dfp->scaling_buttons + [NV_CTRL_FLATPANEL_SCALING_NATIVE] = NULL; + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_FLATPANEL_SCALING), + G_CALLBACK(dfp_update_received), + (gpointer) ctk_display_device_dfp); /* FlatPanel Dithering */ - ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_FLATPANEL_DITHERING, &val); - - if (ret == NvCtrlSuccess) { - frame = gtk_frame_new("FlatPanel Dithering"); - eventbox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(eventbox), frame); - gtk_box_pack_start(GTK_BOX(hbox), eventbox, TRUE, TRUE, 0); + frame = gtk_frame_new("FlatPanel Dithering"); + eventbox = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(eventbox), frame); + gtk_box_pack_start(GTK_BOX(hbox), eventbox, TRUE, TRUE, 0); + ctk_display_device_dfp->dithering_frame = frame; - ctk_config_set_tooltip(ctk_config, eventbox, __dithering_help); - - vbox = gtk_vbox_new(FALSE, FRAME_PADDING); - gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); - gtk_container_add(GTK_CONTAINER(frame), vbox); + ctk_config_set_tooltip(ctk_config, eventbox, __dithering_help); + vbox = gtk_vbox_new(FALSE, FRAME_PADDING); + gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(frame), vbox); - radio0 = make_dithering_radio_button - (ctk_display_device_dfp, vbox, NULL, "Default", - NV_CTRL_FLATPANEL_DITHERING_DEFAULT); - - radio1 = make_dithering_radio_button - (ctk_display_device_dfp, vbox, radio0, "Enabled", - NV_CTRL_FLATPANEL_DITHERING_ENABLED); - - radio2 = make_dithering_radio_button - (ctk_display_device_dfp, vbox, radio1, "Disabled", - NV_CTRL_FLATPANEL_DITHERING_DISABLED); - - dfp_dithering_update_radio_buttons(ctk_display_device_dfp, val); - - g_signal_connect(G_OBJECT(ctk_event), - CTK_EVENT_NAME(NV_CTRL_FLATPANEL_DITHERING), - G_CALLBACK(dfp_update_received), - (gpointer) ctk_display_device_dfp); - - ctk_display_device_dfp->active_attributes |= __DITHERING; - - } else { - - for (i = 0; i < NV_CTRL_FLATPANEL_DITHERING_DISABLED+1; i++) { - ctk_display_device_dfp->dithering_buttons[i] = NULL; - } - - ctk_display_device_dfp->active_attributes &= ~__DITHERING; - } + radio0 = make_dithering_radio_button + (ctk_display_device_dfp, vbox, NULL, "Default", + NV_CTRL_FLATPANEL_DITHERING_DEFAULT); + + radio1 = make_dithering_radio_button + (ctk_display_device_dfp, vbox, radio0, "Enabled", + NV_CTRL_FLATPANEL_DITHERING_ENABLED); + + radio2 = make_dithering_radio_button + (ctk_display_device_dfp, vbox, radio1, "Disabled", + NV_CTRL_FLATPANEL_DITHERING_DISABLED); + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_FLATPANEL_DITHERING), + G_CALLBACK(dfp_update_received), + (gpointer) ctk_display_device_dfp); /* pack the image sliders */ @@ -385,20 +343,25 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, /* pack the EDID button */ - edid = ctk_edid_new(handle, ctk_config, ctk_event, - ctk_display_device_dfp->reset_button, - display_device_mask, name); - if (edid) { - gtk_box_pack_start(GTK_BOX(object), edid, FALSE, FALSE, 0); - ctk_display_device_dfp->edid_available = TRUE; - } else { - ctk_display_device_dfp->edid_available = FALSE; - } + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); + ctk_display_device_dfp->edid_box = hbox; /* show the page */ gtk_widget_show_all(GTK_WIDGET(object)); + /* Update the GUI */ + + ctk_display_device_dfp_setup(ctk_display_device_dfp); + + /* handle enable/disable events on the display device */ + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_ENABLED_DISPLAYS), + G_CALLBACK(enabled_displays_received), + (gpointer) ctk_display_device_dfp); + return GTK_WIDGET(object); } /* ctk_display_device_dfp_new() */ @@ -613,10 +576,8 @@ static void reset_button_clicked(GtkButton *button, gpointer user_data) gint value; - if (ctk_display_device_dfp->image_sliders) { - ctk_image_sliders_reset - (CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders)); - } + ctk_image_sliders_reset + (CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders)); /* * if scaling is active, send the default scaling value to the @@ -650,6 +611,10 @@ static void reset_button_clicked(GtkButton *button, gpointer user_data) dfp_dithering_update_radio_buttons(ctk_display_device_dfp, value); } + /* Update the reset button */ + + gtk_widget_set_sensitive(ctk_display_device_dfp->reset_button, FALSE); + /* status bar message */ ctk_config_statusbar_message(ctk_display_device_dfp->ctk_config, @@ -758,7 +723,7 @@ dfp_dithering_update_radio_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp, /* - * dfp_dithering_update_received() - callback function for changed DFP + * dfp_update_received() - callback function for changed DFP * settings; this is called when we receive an event indicating that * another NV-CONTROL client changed any of the settings that we care * about. @@ -794,7 +759,7 @@ static void dfp_update_received(GtkObject *object, gpointer arg1, break; } -} /* dfp_dithering_update_received() */ +} /* dfp_update_received() */ @@ -809,7 +774,6 @@ GtkTextBuffer *ctk_display_device_dfp_create_help(GtkTextTagTable *table, { GtkTextIter i; GtkTextBuffer *b; - gboolean ret = FALSE; b = gtk_text_buffer_new(table); @@ -817,82 +781,275 @@ GtkTextBuffer *ctk_display_device_dfp_create_help(GtkTextTagTable *table, ctk_help_title(b, &i, "%s Help", ctk_display_device_dfp->name); - if (ctk_display_device_dfp->active_attributes & __INFO) { - ctk_help_heading(b, &i, "FlatPanel Information"); - ctk_help_para(b, &i, __info_help); + ctk_help_heading(b, &i, "FlatPanel Information"); + ctk_help_para(b, &i, __info_help); - ctk_help_term(b, &i, "Chip Location"); - ctk_help_para(b, &i, "Report whether the flatpanel is driven by " - "the on-chip controller (internal), or a " - " separate controller chip elsewhere on the " - "graphics board (external)"); + ctk_help_term(b, &i, "Chip Location"); + ctk_help_para(b, &i, "Report whether the flatpanel is driven by " + "the on-chip controller (internal), or a " + " separate controller chip elsewhere on the " + "graphics board (external)"); - ctk_help_term(b, &i, "Link"); - ctk_help_para(b, &i, "Report whether the specified display device " - "is driven by a single link or dual link DVI " - "connection."); - - ctk_help_term(b, &i, "Signal"); - ctk_help_para(b, &i, "Report whether the flatpanel is driven by " - "an LVDS or TMDS signal"); - - ret = TRUE; - } + ctk_help_term(b, &i, "Link"); + ctk_help_para(b, &i, "Report whether the specified display device " + "is driven by a single link or dual link DVI " + "connection."); - if (ctk_display_device_dfp->active_attributes & __SCALING) { - ctk_help_heading(b, &i, "FlatPanel Scaling"); - ctk_help_para(b, &i, __scaling_help); - - ctk_help_term(b, &i, "Default"); - ctk_help_para(b, &i, "The driver will choose what scaling state is " - "best."); - - ctk_help_term(b, &i, "Scaled"); - ctk_help_para(b, &i, "The image will be expanded to fit the entire " - "FlatPanel."); - - ctk_help_term(b, &i, "Centered"); - ctk_help_para(b, &i, "The image will only occupy the number of pixels " - "needed and be centered on the FlatPanel."); - - ctk_help_term(b, &i, "Fixed Aspect Ratio Scaled"); - ctk_help_para(b, &i, "The image will be expanded (like when Scaled), " - "but the image will retain the original aspect ratio."); - ret = TRUE; - } + ctk_help_term(b, &i, "Signal"); + ctk_help_para(b, &i, "Report whether the flatpanel is driven by " + "an LVDS or TMDS signal"); - if (ctk_display_device_dfp->active_attributes & __DITHERING) { - ctk_help_heading(b, &i, "FlatPanel Dithering"); - ctk_help_para(b, &i, __dithering_help); - - ctk_help_term(b, &i, "Default"); - ctk_help_para(b, &i, "The driver will choose when to dither."); - - ctk_help_term(b, &i, "Enabled"); - ctk_help_para(b, &i, "Force dithering on."); - - ctk_help_term(b, &i, "Disabled"); - ctk_help_para(b, &i, "Force dithering off."); - - ret = TRUE; - } + ctk_help_heading(b, &i, "FlatPanel Scaling"); + ctk_help_para(b, &i, __scaling_help); + + ctk_help_term(b, &i, "Default"); + ctk_help_para(b, &i, "The driver will choose what scaling state is " + "best."); + + ctk_help_term(b, &i, "Scaled"); + ctk_help_para(b, &i, "The image will be expanded to fit the entire " + "FlatPanel."); + + ctk_help_term(b, &i, "Centered"); + ctk_help_para(b, &i, "The image will only occupy the number of pixels " + "needed and be centered on the FlatPanel."); + + ctk_help_term(b, &i, "Fixed Aspect Ratio Scaled"); + ctk_help_para(b, &i, "The image will be expanded (like when Scaled), " + "but the image will retain the original aspect ratio."); + + ctk_help_heading(b, &i, "FlatPanel Dithering"); + ctk_help_para(b, &i, __dithering_help); + + ctk_help_term(b, &i, "Default"); + ctk_help_para(b, &i, "The driver will choose when to dither."); + + ctk_help_term(b, &i, "Enabled"); + ctk_help_para(b, &i, "Force dithering on."); + + ctk_help_term(b, &i, "Disabled"); + ctk_help_para(b, &i, "Force dithering off."); - if (ctk_display_device_dfp->image_sliders) { - ret |= add_image_sliders_help - (CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders), b, &i); - } + add_image_sliders_help + (CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders), b, &i); - if (ctk_display_device_dfp->edid_available) { + if (ctk_display_device_dfp->edid) { add_acquire_edid_help(b, &i); } - if (!ret) { - ctk_help_para(b, &i, "There are no configurable options available " - "for %s.", ctk_display_device_dfp->name); - } - ctk_help_finish(b); return b; } /* ctk_display_device_dfp_create_help() */ + + + +/* + * dfp_info_setup() - + * + * + */ +static void dfp_info_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp) +{ + ReturnStatus ret; + gint val; + char *chip_location, *link, *signal; + + chip_location = link = signal = "Unknown"; + + /* Chip location */ + + ret = + NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle, + ctk_display_device_dfp->display_device_mask, + NV_CTRL_FLATPANEL_CHIP_LOCATION, &val); + if (ret == NvCtrlSuccess) { + if (val == NV_CTRL_FLATPANEL_CHIP_LOCATION_INTERNAL) + chip_location = "Internal"; + if (val == NV_CTRL_FLATPANEL_CHIP_LOCATION_EXTERNAL) + chip_location = "External"; + } + gtk_label_set_text + (GTK_LABEL(ctk_display_device_dfp->txt_chip_location), chip_location); + + /* Link */ + + ret = + NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle, + ctk_display_device_dfp->display_device_mask, + NV_CTRL_FLATPANEL_LINK, &val); + if (ret == NvCtrlSuccess) { + if (val == NV_CTRL_FLATPANEL_LINK_SINGLE) link = "Single"; + if (val == NV_CTRL_FLATPANEL_LINK_DUAL) link = "Dual"; + } + gtk_label_set_text + (GTK_LABEL(ctk_display_device_dfp->txt_link), link); + + /* Signal */ + + ret = + NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle, + ctk_display_device_dfp->display_device_mask, + NV_CTRL_FLATPANEL_SIGNAL, &val); + if (ret == NvCtrlSuccess) { + if (val == NV_CTRL_FLATPANEL_SIGNAL_LVDS) signal = "LVDS"; + if (val == NV_CTRL_FLATPANEL_SIGNAL_TMDS) signal = "TMDS"; + } + gtk_label_set_text + (GTK_LABEL(ctk_display_device_dfp->txt_signal), signal); + +} /* dfp_info_setup() */ + + + +/* + * dfp_scaling_setup() - Update GUI to reflect X server settings of + * DFP Scaling. + */ +static void dfp_scaling_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp) +{ + ReturnStatus ret; + int val; + + ret = + NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle, + ctk_display_device_dfp->display_device_mask, + NV_CTRL_FLATPANEL_SCALING, &val); + if (ret != NvCtrlSuccess) { + gtk_widget_set_sensitive(ctk_display_device_dfp->scaling_frame, FALSE); + gtk_widget_hide(ctk_display_device_dfp->scaling_frame); + ctk_display_device_dfp->active_attributes &= ~__SCALING; + return; + } + + gtk_widget_show(ctk_display_device_dfp->scaling_frame); + ctk_display_device_dfp->active_attributes |= __SCALING; + + gtk_widget_set_sensitive(ctk_display_device_dfp->scaling_frame, TRUE); + + dfp_scaling_update_radio_buttons(ctk_display_device_dfp, val); + +} /* dfp_scaling_setup() */ + + + +/* + * dfp_dithering_setup() - Update GUI to reflect X server settings + * of DFP Dithering. + */ +static void dfp_dithering_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp) +{ + ReturnStatus ret; + int val; + + ret = + NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle, + ctk_display_device_dfp->display_device_mask, + NV_CTRL_FLATPANEL_DITHERING, &val); + if (ret != NvCtrlSuccess) { + gtk_widget_set_sensitive(ctk_display_device_dfp->dithering_frame, + FALSE); + gtk_widget_hide(ctk_display_device_dfp->dithering_frame); + ctk_display_device_dfp->active_attributes &= ~__DITHERING; + return; + } + + gtk_widget_show(ctk_display_device_dfp->dithering_frame); + ctk_display_device_dfp->active_attributes |= __DITHERING; + + gtk_widget_set_sensitive(ctk_display_device_dfp->dithering_frame, TRUE); + + dfp_dithering_update_radio_buttons(ctk_display_device_dfp, val); + +} /* dfp_dithering_setup() */ + + + +/* + * Updates the display device page to reflect the current + * configuration of the display device. + */ +static void ctk_display_device_dfp_setup(CtkDisplayDeviceDfp + *ctk_display_device_dfp) +{ + ReturnStatus ret; + unsigned int enabled_displays; + + + /* Is display enabled? */ + + ret = NvCtrlGetAttribute(ctk_display_device_dfp->handle, + NV_CTRL_ENABLED_DISPLAYS, + (int *)&enabled_displays); + + ctk_display_device_dfp->display_enabled = + (ret == NvCtrlSuccess && + (enabled_displays & (ctk_display_device_dfp->display_device_mask))); + + + /* Update DFP-specific settings */ + + dfp_info_setup(ctk_display_device_dfp); + + dfp_scaling_setup(ctk_display_device_dfp); + + dfp_dithering_setup(ctk_display_device_dfp); + + + /* Update the image sliders */ + + ctk_image_sliders_setup + (CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders)); + + + /* update acquire EDID button */ + + if (ctk_display_device_dfp->edid) { + GList *list; + + list = gtk_container_get_children + (GTK_CONTAINER(ctk_display_device_dfp->edid_box)); + if (list) { + gtk_container_remove + (GTK_CONTAINER(ctk_display_device_dfp->edid_box), + (GtkWidget *)(list->data)); + g_list_free(list); + } + } + + ctk_display_device_dfp->edid = + ctk_edid_new(ctk_display_device_dfp->handle, + ctk_display_device_dfp->ctk_config, + ctk_display_device_dfp->ctk_event, + ctk_display_device_dfp->reset_button, + ctk_display_device_dfp->display_device_mask, + ctk_display_device_dfp->name); + + if (ctk_display_device_dfp->edid) { + gtk_box_pack_start(GTK_BOX(ctk_display_device_dfp->edid_box), + ctk_display_device_dfp->edid, TRUE, TRUE, 0); + } + + + /* update the reset button */ + + gtk_widget_set_sensitive(ctk_display_device_dfp->reset_button, FALSE); + +} /* ctk_display_device_dfp_setup() */ + + + +/* + * When the list of enabled displays on the GPU changes, + * this page should disable/enable access based on whether + * or not the display device is enabled. + */ +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + CtkDisplayDeviceDfp *ctk_object = CTK_DISPLAY_DEVICE_DFP(user_data); + + ctk_display_device_dfp_setup(ctk_object); + +} /* enabled_displays_received() */ diff --git a/src/gtk+-2.x/ctkdisplaydevice-dfp.h b/src/gtk+-2.x/ctkdisplaydevice-dfp.h index b8c432a..ae1c578 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-dfp.h +++ b/src/gtk+-2.x/ctkdisplaydevice-dfp.h @@ -60,15 +60,25 @@ struct _CtkDisplayDeviceDfp NvCtrlAttributeHandle *handle; CtkConfig *ctk_config; + CtkEvent *ctk_event; GtkWidget *image_sliders; GtkWidget *reset_button; + GtkWidget *edid_box; + GtkWidget *edid; + GtkWidget *txt_chip_location; + GtkWidget *txt_link; + GtkWidget *txt_signal; + + GtkWidget *scaling_frame; GtkWidget *scaling_buttons[NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED+1]; + + GtkWidget *dithering_frame; GtkWidget *dithering_buttons[NV_CTRL_FLATPANEL_DITHERING_DISABLED+1]; unsigned int display_device_mask; + gboolean display_enabled; unsigned int active_attributes; - gboolean edid_available; char *name; }; diff --git a/src/gtk+-2.x/ctkdisplaydevice-tv.c b/src/gtk+-2.x/ctkdisplaydevice-tv.c index e0b13f6..13c1110 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-tv.c +++ b/src/gtk+-2.x/ctkdisplaydevice-tv.c @@ -24,15 +24,6 @@ /* * The TV DisplayDevice widget provides a way to adjust TV settings. - * - * TODO: - * - * - make the reset button sensitive only when there is a value to - * change - * - * - tooltips - * - * - online help */ #include <gtk/gtk.h> @@ -73,30 +64,25 @@ static const char* __tv_saturation_help = "The TV Brightness slider adjusts " /* local prototypes */ -static void add_adjustment(CtkDisplayDeviceTv *ctk_display_device_tv, - int attribute, unsigned int attribute_bitmask, - char *name, const char *help, - GtkObject **adjustment); +static void ctk_display_device_tv_class_init(CtkDisplayDeviceTvClass *); +static void ctk_display_device_tv_finalize(GObject *); + +static GtkWidget * add_scale(CtkDisplayDeviceTv *ctk_display_device_tv, + int attribute, char *name, const char *help); static void adjustment_value_changed(GtkAdjustment *adjustment, gpointer user_data); static void reset_defaults(GtkButton *button, gpointer user_data); -static void value_changed(GtkObject *object, gpointer arg1, - gpointer user_data); +static void value_received(GtkObject *object, gpointer arg1, + gpointer user_data); -/* - * constants indicating which attributes are available (so that we - * know which attributes to document) in the online Help - */ +static void ctk_display_device_tv_setup(CtkDisplayDeviceTv + *ctk_display_device_tv); -#define __OVERSCAN (1 << 0) -#define __FLICKER_FILTER (1 << 1) -#define __BRIGHTNESS (1 << 2) -#define __HUE (1 << 3) -#define __CONTRAST (1 << 4) -#define __SATURATION (1 << 5) +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data); GType ctk_display_device_tv_get_type(void) @@ -108,7 +94,7 @@ GType ctk_display_device_tv_get_type(void) sizeof (CtkDisplayDeviceTvClass), NULL, /* base_init */ NULL, /* base_finalize */ - NULL, /* class_init, */ + (GClassInitFunc) ctk_display_device_tv_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (CtkDisplayDeviceTv), @@ -123,11 +109,26 @@ GType ctk_display_device_tv_get_type(void) return ctk_display_device_tv_type; } +static void ctk_display_device_tv_class_init( + CtkDisplayDeviceTvClass *ctk_display_device_tv_class +) +{ + GObjectClass *gobject_class = (GObjectClass *)ctk_display_device_tv_class; + gobject_class->finalize = ctk_display_device_tv_finalize; +} + +static void ctk_display_device_tv_finalize( + GObject *object +) +{ + CtkDisplayDeviceTv *ctk_display_device_tv = CTK_DISPLAY_DEVICE_TV(object); + g_free(ctk_display_device_tv->name); +} /* - * ctk_display_device_tv_new() - constructor for the CtkDisplayDeviceTv - * widget + * ctk_display_device_tv_new() - constructor for the TV display + * device page. */ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, @@ -143,19 +144,16 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, GtkWidget *hbox; GtkWidget *label; GtkWidget *alignment; - GtkWidget *edid; - - char *str; - ReturnStatus ret; + object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_TV, NULL); ctk_display_device_tv = CTK_DISPLAY_DEVICE_TV(object); ctk_display_device_tv->handle = handle; ctk_display_device_tv->ctk_config = ctk_config; + ctk_display_device_tv->ctk_event = ctk_event; ctk_display_device_tv->display_device_mask = display_device_mask; - ctk_display_device_tv->name = name; - ctk_display_device_tv->active_attributes = 0; + ctk_display_device_tv->name = g_strdup(name); gtk_box_set_spacing(GTK_BOX(object), 10); @@ -164,98 +162,100 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, banner = ctk_banner_image_new(&tv_banner_image); gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); + /* Information */ - /* NV_CTRL_STRING_TV_ENCODER_NAME */ + frame = gtk_frame_new(NULL); + gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0); + ctk_display_device_tv->info_frame = frame; - ret = NvCtrlGetStringDisplayAttribute(handle, display_device_mask, - NV_CTRL_STRING_TV_ENCODER_NAME, - &str); - if (ret == NvCtrlSuccess) { - frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0); - - hbox = gtk_hbox_new(FALSE, FRAME_PADDING); - gtk_container_set_border_width(GTK_CONTAINER(hbox), FRAME_PADDING); - gtk_container_add(GTK_CONTAINER(frame), hbox); - - label = gtk_label_new("TV Encoder: "); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - label = gtk_label_new(str); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - } + hbox = gtk_hbox_new(FALSE, FRAME_PADDING); + gtk_container_set_border_width(GTK_CONTAINER(hbox), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(frame), hbox); + + label = gtk_label_new("TV Encoder: "); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + label = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + ctk_display_device_tv->txt_encoder_name = label; + + /* NV_CTRL_TV_OVERSCAN */ - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_OVERSCAN, - __OVERSCAN, "TV OverScan", __tv_overscan_help, - &ctk_display_device_tv->overscan); + ctk_display_device_tv->overscan = + add_scale(ctk_display_device_tv, NV_CTRL_TV_OVERSCAN, + "TV OverScan", __tv_overscan_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_OVERSCAN), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); /* NV_CTRL_TV_FLICKER_FILTER */ - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_FLICKER_FILTER, - __FLICKER_FILTER, "TV Flicker Filter", - __tv_flicker_filter_help, - &ctk_display_device_tv->flicker_filter); + ctk_display_device_tv->flicker_filter = + add_scale(ctk_display_device_tv, NV_CTRL_TV_FLICKER_FILTER, + "TV Flicker Filter", __tv_flicker_filter_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_FLICKER_FILTER), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); /* NV_CTRL_TV_BRIGHTNESS */ - - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_BRIGHTNESS, - __BRIGHTNESS, "TV Brightness", __tv_brightness_help, - &ctk_display_device_tv->brightness); + + ctk_display_device_tv->brightness = + add_scale(ctk_display_device_tv, NV_CTRL_TV_BRIGHTNESS, + "TV Brightness", __tv_brightness_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_BRIGHTNESS), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); /* NV_CTRL_TV_HUE */ - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_HUE, - __HUE, "TV Hue", __tv_hue_help, - &ctk_display_device_tv->hue); + ctk_display_device_tv->hue = + add_scale(ctk_display_device_tv, NV_CTRL_TV_HUE, + "TV Hue", __tv_hue_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_HUE), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); /* NV_CTRL_TV_CONTRAST */ - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_CONTRAST, - __CONTRAST, "TV Contrast", __tv_contrast_help, - &ctk_display_device_tv->contrast); + ctk_display_device_tv->contrast = + add_scale(ctk_display_device_tv, NV_CTRL_TV_CONTRAST, + "TV Contrast", __tv_contrast_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_CONTRAST), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); /* NV_CTRL_TV_SATURATION */ - add_adjustment(ctk_display_device_tv, NV_CTRL_TV_SATURATION, - __SATURATION, "TV Saturation", __tv_saturation_help, - &ctk_display_device_tv->saturation); + ctk_display_device_tv->saturation = + add_scale(ctk_display_device_tv, NV_CTRL_TV_SATURATION, + "TV Saturation", __tv_saturation_help); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_SATURATION), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); - /* pack the image sliders */ + /* Create the reset button here so it can be used by the image sliders */ + + ctk_display_device_tv->reset_button = + gtk_button_new_with_label("Reset TV Hardware Defaults"); + + /* create and pack the image sliders */ ctk_display_device_tv->image_sliders = - ctk_image_sliders_new(handle, ctk_config, ctk_event, NULL, + ctk_image_sliders_new(handle, ctk_config, ctk_event, + ctk_display_device_tv->reset_button, display_device_mask, name); if (ctk_display_device_tv->image_sliders) { gtk_box_pack_start(GTK_BOX(object), @@ -264,10 +264,7 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, } /* reset button */ - - ctk_display_device_tv->reset_button = - gtk_button_new_with_label("Reset TV Hardware Defaults"); - + g_signal_connect(G_OBJECT(ctk_display_device_tv->reset_button), "clicked", G_CALLBACK(reset_defaults), (gpointer) ctk_display_device_tv); @@ -275,33 +272,38 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, alignment = gtk_alignment_new(1, 1, 0, 0); gtk_container_add(GTK_CONTAINER(alignment), ctk_display_device_tv->reset_button); - gtk_box_pack_start(GTK_BOX(object), alignment, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(object), alignment, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(ctk_event), CTK_EVENT_NAME(NV_CTRL_TV_RESET_SETTINGS), - G_CALLBACK(value_changed), + G_CALLBACK(value_received), (gpointer) ctk_display_device_tv); ctk_config_set_tooltip(ctk_config, ctk_display_device_tv->reset_button, "The Reset TV Hardware Defaults button restores " "the TV settings to their default values."); - /* pack the EDID button */ + /* EDID button box */ + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); + ctk_display_device_tv->edid_box = hbox; - edid = ctk_edid_new(handle, ctk_config, ctk_event, - ctk_display_device_tv->reset_button, - display_device_mask, name); - if (edid) { - gtk_box_pack_start(GTK_BOX(object), edid, FALSE, FALSE, 0); - ctk_display_device_tv->edid_available = TRUE; - } else { - ctk_display_device_tv->edid_available = FALSE; - } - /* finally, display the widget */ gtk_widget_show_all(GTK_WIDGET(object)); + /* update the GUI */ + + ctk_display_device_tv_setup(ctk_display_device_tv); + + /* handle enable/disable events on the display device */ + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_ENABLED_DISPLAYS), + G_CALLBACK(enabled_displays_received), + (gpointer) ctk_display_device_tv); + return GTK_WIDGET(object); } /* ctk_display_device_tv_new() */ @@ -309,68 +311,62 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, /* - * add_adjustment() - if the specified attribute exists and we can - * query its valid values, create a new adjustment widget and pack it + * Returns whether or not the scale is active + */ + +static gint get_scale_active(CtkScale *scale) +{ + GtkAdjustment *adj = scale->gtk_adjustment; + + return + GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adj), "attribute active")); + +} /* get_scale_active() */ + + + +/* + * add_scale() - if the specified attribute exists and we can + * query its valid values, create a new scale widget and pack it * in the ctk_display_device_tv */ -static void add_adjustment(CtkDisplayDeviceTv *ctk_display_device_tv, - int attribute, unsigned int attribute_bitmask, - char *name, const char *help, - GtkObject **adjustment) +static GtkWidget * add_scale(CtkDisplayDeviceTv *ctk_display_device_tv, + int attribute, char *name, const char *help) { - ReturnStatus ret0, ret1; - NVCTRLAttributeValidValuesRec valid; GtkObject *adj; - NvCtrlAttributeHandle *handle = ctk_display_device_tv->handle; - unsigned int mask = ctk_display_device_tv->display_device_mask; - int val; GtkWidget *scale; - - ret0 = NvCtrlGetValidDisplayAttributeValues(handle, mask, - attribute, &valid); - - ret1 = NvCtrlGetDisplayAttribute(handle, mask, attribute, &val); - - if ((ret0 == NvCtrlSuccess) && (ret1 == NvCtrlSuccess) && - (valid.type == ATTRIBUTE_TYPE_RANGE)) { - - adj = gtk_adjustment_new(val, valid.u.range.min, - valid.u.range.max, 1, 1, 0); - - gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), val); + + + adj = gtk_adjustment_new(0, 0, 10, 1, 1, 0); - g_object_set_data(G_OBJECT(adj), "attribute", - GINT_TO_POINTER(attribute)); + g_object_set_data(G_OBJECT(adj), "attribute", + GINT_TO_POINTER(attribute)); - g_object_set_data(G_OBJECT(adj), "attribute name", name); + g_object_set_data(G_OBJECT(adj), "attribute name", name); - g_signal_connect(G_OBJECT(adj), "value_changed", - G_CALLBACK(adjustment_value_changed), - (gpointer) ctk_display_device_tv); - - scale = ctk_scale_new(GTK_ADJUSTMENT(adj), name, - ctk_display_device_tv->ctk_config, - G_TYPE_INT); - - if (help) { - ctk_config_set_tooltip(ctk_display_device_tv->ctk_config, - CTK_SCALE_TOOLTIP_WIDGET(scale), help); - } + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(0)); - gtk_box_pack_start(GTK_BOX(ctk_display_device_tv), scale, - FALSE, FALSE, 0); - - *adjustment = adj; - - ctk_display_device_tv->active_attributes |= attribute_bitmask; + g_signal_connect(G_OBJECT(adj), "value_changed", + G_CALLBACK(adjustment_value_changed), + (gpointer) ctk_display_device_tv); - } else { - *adjustment = NULL; + scale = ctk_scale_new(GTK_ADJUSTMENT(adj), name, + ctk_display_device_tv->ctk_config, + G_TYPE_INT); - ctk_display_device_tv->active_attributes &= ~attribute_bitmask; + if (help) { + ctk_config_set_tooltip(ctk_display_device_tv->ctk_config, + CTK_SCALE_TOOLTIP_WIDGET(scale), help); } -} /* add_adjustment() */ + + gtk_box_pack_start(GTK_BOX(ctk_display_device_tv), scale, + FALSE, FALSE, 0); + + return scale; + +} /* add_scale() */ @@ -388,6 +384,8 @@ static void post_adjustment_value_changed(GtkAdjustment *adjustment, { char *name = g_object_get_data(G_OBJECT(adjustment), "attribute name"); + gtk_widget_set_sensitive(ctk_display_device_tv->reset_button, TRUE); + ctk_config_statusbar_message(ctk_display_device_tv->ctk_config, "%s set to %d.", name, value); @@ -433,17 +431,20 @@ static void adjustment_value_changed(GtkAdjustment *adjustment, */ static void reset_slider(CtkDisplayDeviceTv *ctk_display_device_tv, - GtkObject *adj) + GtkWidget *scale) { + GtkAdjustment *adj; gint attribute; - gpointer user_data; ReturnStatus ret; gint val; + adj = CTK_SCALE(scale)->gtk_adjustment; + if (!adj) return; - user_data = g_object_get_data(G_OBJECT(adj), "attribute"); - attribute = GPOINTER_TO_INT(user_data); + if (!get_scale_active(CTK_SCALE(scale))) return; + + attribute = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adj), "attribute")); ret = NvCtrlGetDisplayAttribute(ctk_display_device_tv->handle, ctk_display_device_tv->display_device_mask, @@ -478,7 +479,9 @@ static void reset_sliders(CtkDisplayDeviceTv *ctk_display_device_tv) reset_slider(ctk_display_device_tv, ctk_display_device_tv->hue); reset_slider(ctk_display_device_tv, ctk_display_device_tv->contrast); reset_slider(ctk_display_device_tv, ctk_display_device_tv->saturation); - + + gtk_widget_set_sensitive(ctk_display_device_tv->reset_button, FALSE); + ctk_config_statusbar_message(ctk_display_device_tv->ctk_config, "Reset TV Hardware defaults for %s.", ctk_display_device_tv->name); @@ -496,10 +499,23 @@ static void reset_defaults(GtkButton *button, gpointer user_data) { CtkDisplayDeviceTv *ctk_display_device_tv = CTK_DISPLAY_DEVICE_TV(user_data); - - NvCtrlSetDisplayAttribute(ctk_display_device_tv->handle, - ctk_display_device_tv->display_device_mask, - NV_CTRL_TV_RESET_SETTINGS, 1); + gint active = 0; + + /* Make sure something is active */ + + active = + (get_scale_active(CTK_SCALE(ctk_display_device_tv->overscan)) || + get_scale_active(CTK_SCALE(ctk_display_device_tv->flicker_filter)) || + get_scale_active(CTK_SCALE(ctk_display_device_tv->brightness)) || + get_scale_active(CTK_SCALE(ctk_display_device_tv->hue)) || + get_scale_active(CTK_SCALE(ctk_display_device_tv->contrast)) || + get_scale_active(CTK_SCALE(ctk_display_device_tv->saturation))); + + if (active) { + NvCtrlSetDisplayAttribute(ctk_display_device_tv->handle, + ctk_display_device_tv->display_device_mask, + NV_CTRL_TV_RESET_SETTINGS, 1); + } if (ctk_display_device_tv->image_sliders) { ctk_image_sliders_reset @@ -507,46 +523,48 @@ static void reset_defaults(GtkButton *button, gpointer user_data) } reset_sliders(ctk_display_device_tv); - + } /* reset_defaults() */ /* - * value_changed() - callback function for changed TV settings; this + * value_received() - callback function for changed TV settings; this * is called when we receive an event indicating that another * NV-CONTROL client changed any of the settings that we care about. */ -static void value_changed(GtkObject *object, gpointer arg1, gpointer user_data) +static void value_received(GtkObject *object, gpointer arg1, + gpointer user_data) { CtkEventStruct *event_struct; CtkDisplayDeviceTv *ctk_display_device_tv = CTK_DISPLAY_DEVICE_TV(user_data); - GtkObject *adj; + GtkAdjustment *adj; + GtkWidget *scale; gint val; event_struct = (CtkEventStruct *) arg1; switch (event_struct->attribute) { case NV_CTRL_TV_OVERSCAN: - adj = ctk_display_device_tv->overscan; + scale = ctk_display_device_tv->overscan; break; case NV_CTRL_TV_FLICKER_FILTER: - adj = ctk_display_device_tv->flicker_filter; + scale = ctk_display_device_tv->flicker_filter; break; case NV_CTRL_TV_BRIGHTNESS: - adj = ctk_display_device_tv->brightness; + scale = ctk_display_device_tv->brightness; break; case NV_CTRL_TV_HUE: - adj = ctk_display_device_tv->hue; + scale = ctk_display_device_tv->hue; break; case NV_CTRL_TV_CONTRAST: - adj = ctk_display_device_tv->contrast; + scale = ctk_display_device_tv->contrast; break; case NV_CTRL_TV_SATURATION: - adj = ctk_display_device_tv->saturation; + scale = ctk_display_device_tv->saturation; break; case NV_CTRL_TV_RESET_SETTINGS: reset_sliders(ctk_display_device_tv); @@ -555,6 +573,7 @@ static void value_changed(GtkObject *object, gpointer arg1, gpointer user_data) return; } + adj = CTK_SCALE(scale)->gtk_adjustment; val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj)); if (val != event_struct->value) { @@ -572,7 +591,7 @@ static void value_changed(GtkObject *object, gpointer arg1, gpointer user_data) g_signal_handlers_unblock_by_func(adj, adjustment_value_changed, ctk_display_device_tv); } -} /* value_changed() */ +} /* value_received() */ @@ -587,7 +606,6 @@ GtkTextBuffer *ctk_display_device_tv_create_help(GtkTextTagTable *table, { GtkTextIter i; GtkTextBuffer *b; - gboolean ret = FALSE; b = gtk_text_buffer_new(table); @@ -595,58 +613,221 @@ GtkTextBuffer *ctk_display_device_tv_create_help(GtkTextTagTable *table, ctk_help_title(b, &i, "%s Help", ctk_display_device_tv->name); - if (ctk_display_device_tv->active_attributes & __OVERSCAN) { - ctk_help_heading(b, &i, "TV Overscan"); - ctk_help_para(b, &i, __tv_overscan_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Overscan"); + ctk_help_para(b, &i, __tv_overscan_help); - if (ctk_display_device_tv->active_attributes & __FLICKER_FILTER) { - ctk_help_heading(b, &i, "TV Flicker Filter"); - ctk_help_para(b, &i, __tv_flicker_filter_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Flicker Filter"); + ctk_help_para(b, &i, __tv_flicker_filter_help); - if (ctk_display_device_tv->active_attributes & __BRIGHTNESS) { - ctk_help_heading(b, &i, "TV Brightness"); - ctk_help_para(b, &i, __tv_brightness_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Brightness"); + ctk_help_para(b, &i, __tv_brightness_help); - if (ctk_display_device_tv->active_attributes & __HUE) { - ctk_help_heading(b, &i, "TV Hue"); - ctk_help_para(b, &i, __tv_hue_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Hue"); + ctk_help_para(b, &i, __tv_hue_help); - if (ctk_display_device_tv->active_attributes & __CONTRAST) { - ctk_help_heading(b, &i, "TV Contrast"); - ctk_help_para(b, &i, __tv_contrast_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Contrast"); + ctk_help_para(b, &i, __tv_contrast_help); - if (ctk_display_device_tv->active_attributes & __SATURATION) { - ctk_help_heading(b, &i, "TV Saturation"); - ctk_help_para(b, &i, __tv_saturation_help); - ret = TRUE; - } + ctk_help_heading(b, &i, "TV Saturation"); + ctk_help_para(b, &i, __tv_saturation_help); - if (ctk_display_device_tv->image_sliders) { - ret |= add_image_sliders_help - (CTK_IMAGE_SLIDERS(ctk_display_device_tv->image_sliders), b, &i); - } + add_image_sliders_help + (CTK_IMAGE_SLIDERS(ctk_display_device_tv->image_sliders), b, &i); - if (ctk_display_device_tv->edid_available) { + if (ctk_display_device_tv->edid) { add_acquire_edid_help(b, &i); } - if (!ret) { - ctk_help_para(b, &i, "There are no configurable options available " - "for %s.", ctk_display_device_tv->name); - } - ctk_help_finish(b); return b; } /* ctk_display_device_tv_create_help() */ + + + +/* Update GUI state of the scale to reflect current settings + * on the X Driver. + */ + +static void setup_scale(CtkDisplayDeviceTv *ctk_display_device_tv, + int attribute, GtkWidget *scale) +{ + ReturnStatus ret0, ret1; + NVCTRLAttributeValidValuesRec valid; + NvCtrlAttributeHandle *handle = ctk_display_device_tv->handle; + unsigned int mask = ctk_display_device_tv->display_device_mask; + int val; + GtkAdjustment *adj = CTK_SCALE(scale)->gtk_adjustment; + + + /* Read settings from X server */ + ret0 = NvCtrlGetValidDisplayAttributeValues(handle, mask, + attribute, &valid); + + ret1 = NvCtrlGetDisplayAttribute(handle, mask, attribute, &val); + + if ((ret0 == NvCtrlSuccess) && (ret1 == NvCtrlSuccess) && + (valid.type == ATTRIBUTE_TYPE_RANGE)) { + + g_signal_handlers_block_by_func(adj, adjustment_value_changed, + ctk_display_device_tv); + + adj->lower = valid.u.range.min; + adj->upper = valid.u.range.max; + gtk_adjustment_changed(GTK_ADJUSTMENT(adj)); + + gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), val); + + g_signal_handlers_unblock_by_func(adj, adjustment_value_changed, + ctk_display_device_tv); + + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(1)); + + gtk_widget_set_sensitive(scale, TRUE); + gtk_widget_show(scale); + } else { + + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(0)); + + gtk_widget_set_sensitive(scale, FALSE); + gtk_widget_hide(scale); + } + + +} /* setup_scale() */ + + + +/* + * Updates the display device TV page to reflect the current + * configuration of the display device. + */ +static void ctk_display_device_tv_setup(CtkDisplayDeviceTv + *ctk_display_device_tv) +{ + ReturnStatus ret; + char *str; + unsigned int enabled_displays; + + + /* Is display enabled? */ + + ret = NvCtrlGetAttribute(ctk_display_device_tv->handle, + NV_CTRL_ENABLED_DISPLAYS, + (int *)&enabled_displays); + + ctk_display_device_tv->display_enabled = + (ret == NvCtrlSuccess && + (enabled_displays & (ctk_display_device_tv->display_device_mask))); + + + /* Information Frame */ + + /* NV_CTRL_STRING_TV_ENCODER_NAME */ + + ret = NvCtrlGetStringDisplayAttribute + (ctk_display_device_tv->handle, + ctk_display_device_tv->display_device_mask, + NV_CTRL_STRING_TV_ENCODER_NAME, + &str); + if (ret == NvCtrlSuccess) { + gtk_label_set_text(GTK_LABEL(ctk_display_device_tv->txt_encoder_name), + str); + gtk_widget_show(ctk_display_device_tv->info_frame); + XFree(str); + } else { + gtk_widget_hide(ctk_display_device_tv->info_frame); + } + + + /* Update sliders */ + + /* NV_CTRL_TV_OVERSCAN */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_OVERSCAN, + ctk_display_device_tv->overscan); + + /* NV_CTRL_TV_FLICKER_FILTER */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_FLICKER_FILTER, + ctk_display_device_tv->flicker_filter); + + /* NV_CTRL_TV_BRIGHTNESS */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_BRIGHTNESS, + ctk_display_device_tv->brightness); + + /* NV_CTRL_TV_HUE */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_HUE, + ctk_display_device_tv->hue); + + /* NV_CTRL_TV_CONTRAST */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_CONTRAST, + ctk_display_device_tv->contrast); + + /* NV_CTRL_TV_SATURATION */ + + setup_scale(ctk_display_device_tv, NV_CTRL_TV_SATURATION, + ctk_display_device_tv->saturation); + + /* Update the image sliders */ + + ctk_image_sliders_setup + (CTK_IMAGE_SLIDERS(ctk_display_device_tv->image_sliders)); + + + /* update acquire EDID button */ + + if (ctk_display_device_tv->edid) { + GList *list; + + list = gtk_container_get_children + (GTK_CONTAINER(ctk_display_device_tv->edid_box)); + if (list) { + gtk_container_remove + (GTK_CONTAINER(ctk_display_device_tv->edid_box), + (GtkWidget *)(list->data)); + g_list_free(list); + } + } + + ctk_display_device_tv->edid = + ctk_edid_new(ctk_display_device_tv->handle, + ctk_display_device_tv->ctk_config, + ctk_display_device_tv->ctk_event, + ctk_display_device_tv->reset_button, + ctk_display_device_tv->display_device_mask, + ctk_display_device_tv->name); + + if (ctk_display_device_tv->edid) { + gtk_box_pack_start(GTK_BOX(ctk_display_device_tv->edid_box), + ctk_display_device_tv->edid, TRUE, TRUE, 0); + } + + + /* update the reset button */ + + gtk_widget_set_sensitive(ctk_display_device_tv->reset_button, FALSE); + +} /* ctk_display_device_tv_setup() */ + + + +/* + * When the list of enabled displays on the GPU changes, + * this page should disable/enable access based on whether + * or not the display device is enabled. + */ +static void enabled_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + CtkDisplayDeviceTv *ctk_object = CTK_DISPLAY_DEVICE_TV(user_data); + + ctk_display_device_tv_setup(ctk_object); + +} /* enabled_displays_received() */ diff --git a/src/gtk+-2.x/ctkdisplaydevice-tv.h b/src/gtk+-2.x/ctkdisplaydevice-tv.h index dbeafe2..d4597a8 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-tv.h +++ b/src/gtk+-2.x/ctkdisplaydevice-tv.h @@ -57,25 +57,30 @@ typedef struct _CtkDisplayDeviceTvClass CtkDisplayDeviceTvClass; struct _CtkDisplayDeviceTv { GtkVBox parent; + CtkConfig *ctk_config; + CtkEvent *ctk_event; NvCtrlAttributeHandle *handle; - CtkConfig *ctk_config; - GtkWidget *image_sliders; - GtkWidget *reset_button; + unsigned int display_device_mask; + gboolean display_enabled; + char *name; - GtkObject *overscan; - GtkObject *flicker_filter; - - GtkObject *brightness; - GtkObject *hue; - GtkObject *contrast; - GtkObject *saturation; + GtkWidget *info_frame; + GtkWidget *txt_encoder_name; + + GtkWidget *overscan; + GtkWidget *flicker_filter; - unsigned int display_device_mask; - unsigned int active_attributes; - gboolean edid_available; + GtkWidget *brightness; + GtkWidget *hue; + GtkWidget *contrast; + GtkWidget *saturation; + + GtkWidget *image_sliders; - char *name; + GtkWidget *edid_box; + GtkWidget *edid; + GtkWidget *reset_button; }; struct _CtkDisplayDeviceTvClass diff --git a/src/gtk+-2.x/ctkdisplaydevice.c b/src/gtk+-2.x/ctkdisplaydevice.c deleted file mode 100644 index a379f51..0000000 --- a/src/gtk+-2.x/ctkdisplaydevice.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix - * and Linux systems. - * - * Copyright (C) 2004 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of Version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 - * of the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307, USA - * - */ - -#include <gtk/gtk.h> -#include <NvCtrlAttributes.h> - -#include "display_device_banner.h" -#include "crt.h" -#include "dfp.h" -#include "tv.h" -#include "ctkimage.h" - -#include "ctkdisplaydevice.h" - -#include "ctkconfig.h" -#include "ctkhelp.h" - - -GType ctk_display_device_get_type(void) -{ - static GType ctk_display_device_type = 0; - - if (!ctk_display_device_type) { - static const GTypeInfo ctk_display_device_info = { - sizeof (CtkDisplayDeviceClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - NULL, /* class_init, */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (CtkDisplayDevice), - 0, /* n_preallocs */ - NULL, /* instance_init */ - }; - - ctk_display_device_type = g_type_register_static (GTK_TYPE_VBOX, - "CtkDisplayDevice", &ctk_display_device_info, 0); - } - - return ctk_display_device_type; -} - - -GtkWidget* ctk_display_device_new(NvCtrlAttributeHandle *handle, - CtkConfig *ctk_config, CtkEvent *ctk_event) -{ - GObject *object; - CtkDisplayDevice *ctk_display_device; - GtkWidget *image; - GtkWidget *banner; - GtkWidget *frame; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *label; - GtkWidget *alignment; - ReturnStatus ret; - - guint8 *image_buffer = NULL; - const nv_image_t *img; - int enabled, i, mask, n; - char *name; - - object = g_object_new(CTK_TYPE_DISPLAY_DEVICE, NULL); - - ctk_display_device = CTK_DISPLAY_DEVICE(object); - ctk_display_device->handle = handle; - ctk_display_device->ctk_config = ctk_config; - ctk_display_device->num_display_devices = 0; - - gtk_box_set_spacing(GTK_BOX(object), 10); - - /* banner */ - - banner = ctk_banner_image_new(&display_device_banner_image); - gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); - - /* - * In the future: this page will be where things like TwinView - * will be configured. In the meantime, just put place holders - * for each display device present on this X screen. - */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_ENABLED_DISPLAYS, &enabled); - if (ret != NvCtrlSuccess) { - return NULL; - } - - ctk_display_device->enabled_display_devices = enabled; - - /* create an alignment to center the placeholder */ - - alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0); - gtk_box_pack_start(GTK_BOX(object), alignment, TRUE, FALSE, 0); - - /* create a frame to hold the whole placeholder */ - - frame = gtk_frame_new(NULL); - gtk_container_add(GTK_CONTAINER(alignment), frame); - - /* create an hbox to hold each display device */ - - hbox = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(frame), hbox); - - /* create a vbox with image and label for each display device */ - - for (n = 0, i = 0; i < 24; i++) { - - mask = 1 << i; - if (!(enabled & mask)) continue; - - /* get the name of the display device */ - - ret = - NvCtrlGetStringDisplayAttribute(handle, mask, - NV_CTRL_STRING_DISPLAY_DEVICE_NAME, - &name); - - if ((ret != NvCtrlSuccess) || (!name)) { - name = g_strdup("Unknown"); - } - - /* get the correct image for each display device type */ - - if (mask & CTK_DISPLAY_DEVICE_CRT_MASK) { - img = &crt_image; - } else if (mask & CTK_DISPLAY_DEVICE_TV_MASK) { - img = &tv_image; - } else if (mask & CTK_DISPLAY_DEVICE_DFP_MASK) { - img = &dfp_image; - } else { - continue; - } - - vbox = gtk_vbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 5); - - frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5); - - image_buffer = decompress_image_data(img); - - image = gtk_image_new_from_pixbuf - (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - TRUE, 8, img->width, img->height, - img->width * img->bytes_per_pixel, - free_decompressed_image, NULL)); - - gtk_container_add(GTK_CONTAINER(frame), image); - - label = gtk_label_new(name); - - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - /* save the display device name */ - - ctk_display_device->display_device_names[n] = name; - - /* increment the display device count */ - - n++; - } - - ctk_display_device->num_display_devices = n; - - /* show the page */ - - gtk_widget_show_all(GTK_WIDGET(object)); - - return GTK_WIDGET(object); - -} /* ctk_display_device_new() */ - - - -/* - * ctk_display_device_create_help() - construct help page - */ - -GtkTextBuffer *ctk_display_device_create_help(GtkTextTagTable *table, - CtkDisplayDevice - *ctk_display_device) -{ - GtkTextIter i; - GtkTextBuffer *b; - char *title, *page, *s, *tmp, *name; - int n, num; - - num = ctk_display_device->num_display_devices; - - if (num == 1) { - title = "Display Device Help"; - page = "page"; - } else { - title = "Display Devices Help"; - page = "pages"; - } - - /* ugliness to build list of display device names */ - - s = NULL; - for (n = 0; n < num; n++) { - - name = ctk_display_device->display_device_names[n]; - - if (s) { - tmp = s; - s = g_strconcat(s, " ", NULL); - g_free(tmp); - } else { - s = g_strdup(" "); - } - - tmp = s; - - if (n == (num - 1)) { - s = g_strconcat(s, name, NULL); - } else if (n == (num - 2)) { - s = g_strconcat(s, name, " and", NULL); - } else { - s = g_strconcat(s, name, ",", NULL); - } - - g_free(tmp); - } - - - b = gtk_text_buffer_new(table); - - gtk_text_buffer_get_iter_at_offset(b, &i, 0); - - ctk_help_title(b, &i, title); - - ctk_help_para(b, &i, "The %s page is a place holder until support " - "for configuring TwinView is added.", title); - - ctk_help_para(b, &i, "Please see the %s for%s for per-display device " - "configuration.", page, s); - - ctk_help_finish(b); - - return b; - -} /* ctk_display_device_create_help() */ diff --git a/src/gtk+-2.x/ctkdisplaydevice.h b/src/gtk+-2.x/ctkdisplaydevice.h deleted file mode 100644 index 2036eb5..0000000 --- a/src/gtk+-2.x/ctkdisplaydevice.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix - * and Linux systems. - * - * Copyright (C) 2004 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of Version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 - * of the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307, USA - * - */ - -#ifndef __CTK_DISPLAYDEVICE_H__ -#define __CTK_DISPLAYDEVICE_H__ - -#include "ctkevent.h" -#include "ctkconfig.h" - -G_BEGIN_DECLS - -#define CTK_TYPE_DISPLAY_DEVICE (ctk_display_device_get_type()) - -#define CTK_DISPLAY_DEVICE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_DISPLAY_DEVICE, \ - CtkDisplayDevice)) - -#define CTK_DISPLAY_DEVICE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_DISPLAY_DEVICE, \ - CtkDisplayDeviceClass)) - -#define CTK_IS_DISPLAY_DEVICE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_DISPLAY_DEVICE)) - -#define CTK_IS_DISPLAY_DEVICE_CLASS(class) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_DISPLAY_DEVICE)) - -#define CTK_DISPLAY_DEVICE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_DISPLAY_DEVICE, \ - CtkDisplayDeviceClass)) - - -#define CTK_DISPLAY_DEVICE_CRT_MASK 0x000000FF -#define CTK_DISPLAY_DEVICE_TV_MASK 0x0000FF00 -#define CTK_DISPLAY_DEVICE_DFP_MASK 0x00FF0000 - - -typedef struct _CtkDisplayDevice CtkDisplayDevice; -typedef struct _CtkDisplayDeviceClass CtkDisplayDeviceClass; - -struct _CtkDisplayDevice -{ - GtkVBox parent; - - NvCtrlAttributeHandle *handle; - CtkConfig *ctk_config; - - unsigned int enabled_display_devices; - - int num_display_devices; - char *display_device_names[24]; - -}; - -struct _CtkDisplayDeviceClass -{ - GtkVBoxClass parent_class; -}; - -GType ctk_display_device_get_type (void) G_GNUC_CONST; -GtkWidget* ctk_display_device_new (NvCtrlAttributeHandle *, - CtkConfig *, CtkEvent *); - -GtkTextBuffer *ctk_display_device_create_help(GtkTextTagTable *, - CtkDisplayDevice *); - -G_END_DECLS - -#endif /* __CTK_DISPLAYDEVICE_H__ */ diff --git a/src/gtk+-2.x/ctkdisplaylayout.c b/src/gtk+-2.x/ctkdisplaylayout.c new file mode 100644 index 0000000..2b851e1 --- /dev/null +++ b/src/gtk+-2.x/ctkdisplaylayout.c @@ -0,0 +1,3690 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <stdlib.h> /* malloc */ +#include <string.h> /* strlen */ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> + +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "ctkevent.h" +#include "ctkhelp.h" +#include "ctkdisplaylayout.h" + + + + +/* GUI look and feel */ + +#define DEFAULT_SNAP_STRENGTH 100 + +#define MAX_LAYOUT_WIDTH 0x00007FFF /* 16 bit signed int (32767) */ +#define MAX_LAYOUT_HEIGHT 0x00007FFF + +#define LAYOUT_IMG_OFFSET 2 /* Border + White trimming */ +#define LAYOUT_IMG_BORDER_PADDING 8 + +#define LAYOUT_IMG_FG_COLOR "black" +#define LAYOUT_IMG_BG_COLOR "#AAAAAA" +#define LAYOUT_IMG_SELECT_COLOR "#FF8888" + + +/* Device (GPU) Coloring */ + +#define BG_SCR_ON 0 /* Screen viewing area (Has modeline set) */ +#define BG_PAN_ON 1 /* Screen panning area (Has modeline set) */ +#define BG_SCR_OFF 2 /* Screen viewing area (Off/Disabled) */ +#define BG_PAN_OFF 3 /* Screen panning area (Off/Disabled) */ + +#define NUM_COLOR_PALETTES MAX_DEVICES /* One palette for each possible Device/GPU */ +#define NUM_COLORS_PER_PALETTE 4 /* Number of colors in a device's palette */ +#define NUM_COLORS ((NUM_COLOR_PALETTES) * (NUM_COLORS_PER_PALETTE)) + +#if MAX_DEVICES != 8 +#warning "Each GPU needs a color palette!" +#endif + +/* Each device will need a unique color palette */ +char *__palettes_color_names[NUM_COLORS] = { + + /* Blue */ + "#D9DBF4", /* View - Has modeline set */ + "#C9CBE4", /* Panning - Has modeline set */ + "#BABCD5", /* View - Off/Disabled */ + "#A3A5BE", /* Panning - OFf/Disabled */ + + /* Orange */ + "#FFDB94", + "#E8C47D", + "#C9A55E", + "#A6823B", + + /* Purple */ + "#E2D4F0", + "#CFC1DD", + "#B7A9C5", + "#9D8FAB", + + /* Beige */ + "#EAF1C9", + "#CBD2AA", + "#ADB48C", + "#838A62", + + /* Green */ + "#96E562", + "#70BF3C", + "#5BAA27", + "#3C8B08", + + /* Pink */ + "#FFD6E9", + "#E1B8CB", + "#C79EB1", + "#A87F92", + + /* Yellow */ + "#EEEE7E", + "#E0E070", + "#D5D565", + "#C4C454", + + /* Teal */ + "#C9EAF1", + "#A2C3CA", + "#8DAEB5", + "#76979E" + }; + + + + +/*** P R O T O T Y P E S *****************************************************/ + + +static gboolean expose_event_callback (GtkWidget *widget, + GdkEventExpose *event, + gpointer data); + +static gboolean configure_event_callback (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data); + +static gboolean motion_event_callback (GtkWidget *widget, + GdkEventMotion *event, + gpointer data); + +static gboolean button_press_event_callback (GtkWidget *widget, + GdkEventButton *event, + gpointer data); + +static gboolean button_release_event_callback (GtkWidget *widget, + GdkEventButton *event, + gpointer data); + + +static void calc_metamode(nvScreenPtr screen, nvMetaModePtr metamode); + + + + +/*** F U N C T I O N S *******************************************************/ + + +/** zorder_layout() ************************************************** + * + * In order to draw and allow selecting display devices, we need to + * keep them in a Z-ordered list. This function creates the initial + * Z-order list for the given layout based on the devices it has. + * + **/ + +static void zorder_layout(CtkDisplayLayout *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + int i; + + + /* Clear the list */ + if (ctk_object->Zorder) { + free(ctk_object->Zorder); + ctk_object->Zorder = NULL; + } + ctk_object->Zcount = 0; + ctk_object->Zselected = 0; + + + /* Count the number of displays in the layout */ + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + ctk_object->Zcount += gpu->num_displays; + } + + + /* If there are no displays, we're done */ + if (!ctk_object->Zcount) { + return; + } + + + /* Create the Z order list buffer */ + ctk_object->Zorder = + (nvDisplayPtr *)calloc(1, ctk_object->Zcount *sizeof(nvDisplayPtr)); + if (!ctk_object->Zorder) { + ctk_object->Zcount = 0; + return; + } + + + /* Populate the Z order list */ + i = 0; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + nvDisplayPtr display; + for (display = gpu->displays; display; display = display->next) { + ctk_object->Zorder[i++] = display; + } + } + +} /* zorder_layout() */ + + + +/** get_selected() *************************************************** + * + * Returns the currently selected display. The selected display + * device should always be at the top of the Z-order. + * + **/ + +static nvDisplayPtr get_selected(CtkDisplayLayout *ctk_object) +{ + if (!(ctk_object->Zselected) || !(ctk_object->Zcount)) { + return NULL; + } + + return ctk_object->Zorder[0]; + +} /* get_selected() */ + + + +/** get_metamode() *************************************************** + * + * Returns a screen's metamode_idx'th metamode, clamping to the last + * available metamode in the list. + * + **/ + +static nvMetaModePtr get_metamode(nvScreenPtr screen, int metamode_idx) +{ + nvMetaModePtr metamode = screen->metamodes; + + while (metamode && metamode->next && metamode_idx) { + metamode = metamode->next; + metamode_idx--; + } + + return metamode; + +} /* get_metamode() */ + + + +/** get_mode() ******************************************************* + * + * Returns a display device's mode_idx'th mode. + * + **/ + +static nvModePtr get_mode(nvDisplayPtr display, int mode_idx) +{ + nvModePtr mode = display->modes; + + while (mode && mode->next && mode_idx) { + mode = mode->next; + mode_idx--; + } + + return mode; + +} /* get_mode() */ + + + +/** sync_modify() **************************************************** + * + * When the user is moving/panning a display device around, a + * temporary dimension buffer is used to allow for snapping to other + * displays. + * + * This function sets up the temporary buffer by copying the actual + * dimensions of the selected display device to the temporary buffer. + * + **/ + +static void sync_modify(CtkDisplayLayout *ctk_object) +{ + nvDisplayPtr display = get_selected(ctk_object); + + if (display && display->cur_mode) { + ctk_object->modify_dim[X] = display->cur_mode->pan[X]; + ctk_object->modify_dim[Y] = display->cur_mode->pan[Y]; + ctk_object->modify_dim[W] = display->cur_mode->pan[W]; + ctk_object->modify_dim[H] = display->cur_mode->pan[H]; + } + +} /* sync_modify() */ + + + +/** sync_scaling() *************************************************** + * + * Computes the scaling required to display the layout image. + * + **/ + +static void sync_scaling(CtkDisplayLayout *ctk_object) +{ + int *dim = ctk_object->layout->dim; + float wscale; + float hscale; + + wscale = (float)(ctk_object->img_dim[W]) / (float)(dim[W]); + hscale = (float)(ctk_object->img_dim[H]) / (float)(dim[H]); + + if (wscale * dim[H] > ctk_object->img_dim[H]) { + ctk_object->scale = hscale; + } else { + ctk_object->scale = wscale; + } + +} /* sync_scaling() */ + + + +/** point_in_dim() *************************************************** + * + * Determines if a point lies within the given dimensions + * + **/ + +static int point_in_dim(int *dim, int x, int y) +{ + if (x > dim[X] && x < (dim[X] + dim[W]) && + y > dim[Y] && y < (dim[Y] + dim[H])) { + return 1; + } + + return 0; + +} /* point_in_dim() */ + + + +/** offset functions ************************************************* + * + * Offsetting functions + * + * These functions do the dirty work of actually moving display + * devices around in the layout. + * + **/ + +/* Offset a single mode */ +static void offset_mode(nvModePtr mode, int x, int y) +{ + mode->dim[X] += x; + mode->dim[Y] += y; + mode->pan[X] = mode->dim[X]; + mode->pan[Y] = mode->dim[Y]; +} + +/* Offset a display by offsetting the current mode */ +static void offset_display(nvDisplayPtr display, int x, int y, int full) +{ + /* XXX For now, if there is only one display, offset all + * of its modes. Later, allow the user to override + * this behavior. + */ + if ((display->screen && display->screen->num_displays == 1) || full) { + nvModePtr mode; + for (mode = display->modes; mode; mode = mode->next) { + offset_mode(mode, x, y); + } + } else if (display->cur_mode) { + offset_mode(display->cur_mode, x, y); + } +} + +/* Offsets an X screen */ +static void offset_screen(nvScreenPtr screen, int x, int y) +{ + nvMetaModePtr metamode; + + screen->dim[X] += x; + screen->dim[Y] += y; + + for (metamode = screen->metamodes; metamode; metamode = metamode->next) { + metamode->dim[X] += x; + metamode->dim[Y] += y; + metamode->edim[X] += x; + metamode->edim[Y] += y; + } +} + +/* Offsets the entire layout by offsetting its X screens and display devices */ +static void offset_layout(nvLayoutPtr layout, int x, int y, int full) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + nvDisplayPtr display; + + layout->dim[X] += x; + layout->dim[Y] += y; + + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + + /* Offset screens */ + for (screen = gpu->screens; screen; screen = screen->next) { + offset_screen(screen, x, y); + } + + /* Offset displays */ + for (display = gpu->displays; display; display = display->next) { + offset_display(display, x, y, full); + } + } +} /* offset functions */ + + + +/** resolve_display() ************************************************ + * + * Figures out where the current mode of the given display should be + * placed in relation to the layout. + * + * XXX This function assumes there are no relationship loops + * + **/ + +static int resolve_display(nvDisplayPtr display, int pos[4]) +{ + nvModePtr mode = display->cur_mode; + int relative_pos[4]; + + if (!mode) return 0; + + + /* Set the dimensions */ + pos[W] = mode->pan[W]; + pos[H] = mode->pan[H]; + + + /* Find the position */ + switch (mode->position_type) { + case CONF_ADJ_ABSOLUTE: + pos[X] = mode->pan[X]; + pos[Y] = mode->pan[Y]; + break; + + case CONF_ADJ_RIGHTOF: + resolve_display(mode->relative_to, relative_pos); + pos[X] = relative_pos[X] + relative_pos[W]; + pos[Y] = relative_pos[Y]; + break; + + case CONF_ADJ_LEFTOF: + resolve_display(mode->relative_to, relative_pos); + pos[X] = relative_pos[X] - pos[W]; + pos[Y] = relative_pos[Y]; + break; + + case CONF_ADJ_BELOW: + resolve_display(mode->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y] + relative_pos[H]; + break; + + case CONF_ADJ_ABOVE: + resolve_display(mode->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y] - pos[H]; + break; + + case CONF_ADJ_RELATIVE: /* Clone */ + resolve_display(mode->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y]; + break; + + default: + return 0; + } + + return 1; + +} /* resolve_display() */ + + + +/** resolve_displays_in_screen() ************************************* + * + * Resolves relative display positions into absolute positions for + * the currently selected metamode of the screen. + * + **/ + +static void resolve_displays_in_screen(nvScreenPtr screen) +{ + nvDisplayPtr display; + int pos[4]; + + /* Resolve the current mode of each display in the screen */ + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + if (resolve_display(display, pos)) { + display->cur_mode->dim[X] = pos[X]; + display->cur_mode->dim[Y] = pos[Y]; + display->cur_mode->pan[X] = pos[X]; + display->cur_mode->pan[Y] = pos[Y]; + } + } + + /* Get the new position of the metamode */ + calc_metamode(screen, screen->cur_metamode); + +} /* resolve_displays_in_screen() */ + + + +/** resolve_screen() ************************************************* + * + * Figures out where the current metamode of the given screen should be + * placed in relation to the layout. + * + * XXX This function assumes there are no relationship loops + * + **/ + +static int resolve_screen(nvScreenPtr screen, int pos[4]) +{ + nvMetaModePtr metamode = screen->cur_metamode; + int relative_pos[4]; + + if (!metamode) return 0; + + + /* Set the dimensions */ + pos[W] = metamode->dim[W]; + pos[H] = metamode->dim[H]; + + + /* Find the position */ + switch (screen->position_type) { + case CONF_ADJ_ABSOLUTE: + pos[X] = metamode->dim[X]; + pos[Y] = metamode->dim[Y]; + break; + + case CONF_ADJ_RIGHTOF: + resolve_screen(screen->relative_to, relative_pos); + pos[X] = relative_pos[X] + relative_pos[W]; + pos[Y] = relative_pos[Y]; + break; + + case CONF_ADJ_LEFTOF: + resolve_screen(screen->relative_to, relative_pos); + pos[X] = relative_pos[X] - pos[W]; + pos[Y] = relative_pos[Y]; + break; + + case CONF_ADJ_BELOW: + resolve_screen(screen->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y] + relative_pos[H]; + break; + + case CONF_ADJ_ABOVE: + resolve_screen(screen->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y] - pos[H]; + break; + + case CONF_ADJ_RELATIVE: /* Clone */ + resolve_screen(screen->relative_to, relative_pos); + pos[X] = relative_pos[X]; + pos[Y] = relative_pos[Y]; + break; + + default: + return 0; + } + + return 1; + +} /* resolve_screen() */ + + + +/* resolve_screen_in_layout() *************************************** + * + * Resolves relative screen positions into absolute positions for + * the currently selected metamode of the screen. + * + **/ + +static void resolve_screen_in_layout(nvScreenPtr screen) +{ + nvDisplayPtr display; + int pos[4]; + int x, y; + + + /* Resolve the current screen location */ + if (resolve_screen(screen, pos)) { + + /* Move the screen and the displays by offsetting */ + + x = pos[X] - screen->cur_metamode->dim[X]; + y = pos[Y] - screen->cur_metamode->dim[Y]; + + offset_screen(screen, x, y); + + for (display = screen->gpu->displays; + display; + display = display->next) { + + if (display->screen != screen) continue; + + offset_mode(display->cur_mode, x, y); + } + } + +} /* resolve_screen_in_layout() */ + + + +/** resolve_layout() ************************************************* + * + * Resolves relative positions into absolute positions for the + * the *current* layout. + * + **/ + +static void resolve_layout(nvLayoutPtr layout) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + + /* First, resolve TwinView relationships */ + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + resolve_displays_in_screen(screen); + } + } + + /* Next, resolve X Screen relationships */ + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + resolve_screen_in_layout(screen); + } + } + +} /* resolve_layout() */ + + + +/** calc_metamode() ************************************************** + * + * Calculates the dimensions of a metamode. + * + * - Calculates the smallest bounding box that can hold the given + * metamode of the X Screen. + * + **/ + +static void calc_metamode(nvScreenPtr screen, nvMetaModePtr metamode) +{ + nvDisplayPtr display; + nvModePtr mode; + int init = 1; + int einit = 1; + int *dim; // Bounding box for all modes, including NULL modes. + int *edim; // Bounding box for non-NULL modes. + + + if (!screen || !metamode) { + return; + } + + dim = metamode->dim; + edim = metamode->edim; + + dim[X] = edim[X] = 0; + dim[Y] = edim[Y] = 0; + dim[W] = edim[W] = 0; + dim[H] = edim[H] = 0; + + /* Calculate its dimensions */ + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + /* Get the display's mode that is part of the metamode. */ + for (mode = display->modes; mode; mode = mode->next) { + if (mode->metamode == metamode) break; + } + if (!mode) continue; + + if (init) { + dim[X] = mode->pan[X]; + dim[Y] = mode->pan[Y]; + dim[W] = mode->pan[X] +mode->pan[W]; + dim[H] = mode->pan[Y] +mode->pan[H]; + init = 0; + } else { + dim[X] = MIN(dim[X], mode->dim[X]); + dim[Y] = MIN(dim[Y], mode->dim[Y]); + dim[W] = MAX(dim[W], mode->dim[X] +mode->pan[W]); + dim[H] = MAX(dim[H], mode->dim[Y] +mode->pan[H]); + } + + /* Don't include NULL modes in the effective dimension calculation */ + if (!mode->modeline) continue; + + if (einit) { + edim[X] = mode->pan[X]; + edim[Y] = mode->pan[Y]; + edim[W] = mode->pan[X] +mode->pan[W]; + edim[H] = mode->pan[Y] +mode->pan[H]; + einit = 0; + } else { + edim[X] = MIN(edim[X], mode->dim[X]); + edim[Y] = MIN(edim[Y], mode->dim[Y]); + edim[W] = MAX(edim[W], mode->dim[X] +mode->pan[W]); + edim[H] = MAX(edim[H], mode->dim[Y] +mode->pan[H]); + } + } + + dim[W] = dim[W] - dim[X]; + dim[H] = dim[H] - dim[Y]; + + edim[W] = edim[W] - edim[X]; + edim[H] = edim[H] - edim[Y]; + +} /* calc_metamode() */ + + + +/** calc_screen() **************************************************** + * + * Calculates the dimensions of an X Screen + * + * - Calculates the smallest bounding box that can hold all of the + * metamodes of the X Screen. + * + **/ + +static void calc_screen(nvScreenPtr screen) +{ + nvMetaModePtr metamode; + int *dim; + + + if (!screen) return; + + dim = screen->dim; + metamode = screen->metamodes; + + if (!metamode) { + dim[X] = 0; + dim[Y] = 0; + dim[W] = 0; + dim[H] = 0; + return; + } + + calc_metamode(screen, metamode); + dim[X] = metamode->dim[X]; + dim[Y] = metamode->dim[Y]; + dim[W] = metamode->dim[X] +metamode->dim[W]; + dim[H] = metamode->dim[Y] +metamode->dim[H]; + + for (metamode = metamode->next; + metamode; + metamode = metamode->next) { + + calc_metamode(screen, metamode); + dim[X] = MIN(dim[X], metamode->dim[X]); + dim[Y] = MIN(dim[Y], metamode->dim[Y]); + dim[W] = MAX(dim[W], metamode->dim[X] +metamode->dim[W]); + dim[H] = MAX(dim[H], metamode->dim[Y] +metamode->dim[H]); + } + + dim[W] = dim[W] - dim[X]; + dim[H] = dim[H] - dim[Y]; + +} /* calc_screen() */ + + + +/** calc_layout() **************************************************** + * + * Calculates the dimensions (width & height) of the layout. This is + * the smallest bounding box that holds all the gpu's X screen's + * display device's (current) modes in the layout. (Bounding box of + * all the current metamodes of all X Screens.) + * + * As a side effect, all other screen/metamode dimensions are + * calculated. + * + **/ + +static void calc_layout(nvLayoutPtr layout) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + nvDisplayPtr display; + int init = 1; + int *dim; + int x; + + + if (!layout) return; + + resolve_layout(layout); + + dim = layout->dim; + dim[X] = 0; + dim[Y] = 0; + dim[W] = 0; + dim[H] = 0; + + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + + for (screen = gpu->screens; screen; screen = screen->next) { + int *sdim; + + calc_screen(screen); + sdim = screen->cur_metamode->dim; + + if (init) { + dim[X] = sdim[X]; + dim[Y] = sdim[Y]; + dim[W] = sdim[X] +sdim[W]; + dim[H] = sdim[Y] +sdim[H]; + init = 0; + continue; + } + + dim[X] = MIN(dim[X], sdim[X]); + dim[Y] = MIN(dim[Y], sdim[Y]); + dim[W] = MAX(dim[W], sdim[X] +sdim[W]); + dim[H] = MAX(dim[H], sdim[Y] +sdim[H]); + } + } + + dim[W] = dim[W] - dim[X]; + dim[H] = dim[H] - dim[Y]; + + + /* Position disabled display devices off to the top right */ + x = dim[W] + dim[X]; + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (display = gpu->displays; display; display = display->next) { + if (display->screen) continue; + + display->cur_mode->dim[X] = x; + display->cur_mode->pan[X] = x; + display->cur_mode->dim[Y] = 0; + display->cur_mode->pan[Y] = 0; + + x += display->cur_mode->dim[W]; + dim[W] += display->cur_mode->dim[W]; + dim[H] = MAX(dim[H], display->cur_mode->dim[H]); + } + } + +} /* calc_layout() */ + + + +/** set_screen_metamode() ******************************************** + * + * Updates the layout structure to make the screen and each of its + * displays point to the correct metamode/mode. + * + **/ + +static void set_screen_metamode(nvLayoutPtr layout, nvScreenPtr screen, + int new_metamode_idx) +{ + nvDisplayPtr display; + + + /* Set which metamode the screen is pointing to */ + screen->cur_metamode_idx = new_metamode_idx; + screen->cur_metamode = get_metamode(screen, new_metamode_idx); + + /* Make each display within the screen point to the new mode */ + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; /* Display not in screen */ + + display->cur_mode = get_mode(display, new_metamode_idx); + } + + /* Recalculate the layout dimensions */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + +} /* set_screen_metamode() */ + + + +/** recenter_layout() ************************************************ + * + * Recenters all metamodes of all screens in the layout. (Makes + * sure that the top left corner of each screen's metamode is (0,0) + * if possible.) + * + **/ + +static void recenter_layout(nvLayoutPtr layout) +{ + nvGpuPtr gpu; + nvScreenPtr screen; + int real_metamode_idx; + int metamode_idx; + + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + + for (screen = gpu->screens; screen; screen = screen->next) { + + real_metamode_idx = screen->cur_metamode_idx; + + for (metamode_idx = 0; + metamode_idx < screen->num_metamodes; + metamode_idx++) { + + if (metamode_idx == real_metamode_idx) continue; + + set_screen_metamode(layout, screen, metamode_idx); + } + + set_screen_metamode(layout, screen, real_metamode_idx); + } + } + +} /* recenter_layout() */ + + + +/** snap_dim_to_dim() *********************************************** + * + * Snaps the sides of two rectangles together. + * + * Snaps the dimensions of "src" to those of "snap" if any part + * of the "src" rectangle is within "snap_strength" of the "snap" + * rectangle. The resulting, snapped, rectangle is returned in + * "dst", along with the deltas (how far we needed to jump in order + * to produce a snap) in the vertical and horizontal directions. + * + * No vertically snapping occurs if 'best_vert' is NULL. + * No horizontal snapping occurs if 'best_horz' is NULL. + * + **/ + +static void snap_dim_to_dim(int *dst, int *src, int *snap, int snap_strength, + int *best_vert, int *best_horz) +{ + int dist; + + + /* Snap vertically */ + if (best_vert) { + + /* Snap top side to top side */ + dist = abs(snap[Y] - src[Y]); + if (dist <= snap_strength && dist < *best_vert) { + dst[Y] = snap[Y]; + *best_vert = dist; + } + + /* Snap top side to bottom side */ + dist = abs((snap[Y] + snap[H]) - src[Y]); + if (dist <= snap_strength && dist < *best_vert) { + dst[Y] = snap[Y] + snap[H]; + *best_vert = dist; + } + + /* Snap bottom side to top side */ + dist = abs(snap[Y] - (src[Y] + src[H])); + if (dist <= snap_strength && dist < *best_vert) { + dst[Y] = snap[Y] - src[H]; + *best_vert = dist; + } + + /* Snap bottom side to bottom side */ + dist = abs((snap[Y] + snap[H]) - (src[Y] + src[H])); + if (dist <= snap_strength && dist < *best_vert) { + dst[Y] = snap[Y] + snap[H] - src[H]; + *best_vert = dist; + } + + /* Snap midlines */ + if (/* Top of 'src' is above bottom of 'snap' */ + (src[Y] <= snap[Y] + snap[H] + snap_strength) && + /* Bottom of 'src' is below top of 'snap' */ + (src[Y] + src[H] >= snap[Y] - snap_strength)) { + + /* Snap vertically */ + dist = abs((snap[Y] + snap[H]/2) - (src[Y]+src[H]/2)); + if (dist <= snap_strength && dist < *best_vert) { + dst[Y] = snap[Y] + snap[H]/2 - src[H]/2; + *best_vert = dist; + } + } + } + + + /* Snap horizontally */ + if (best_horz) { + + /* Snap left side to left side */ + dist = abs(snap[X] - src[X]); + if (dist <= snap_strength && dist < *best_horz) { + dst[X] = snap[X]; + *best_horz = dist; + } + + /* Snap left side to right side */ + dist = abs((snap[X] + snap[W]) - src[X]); + if (dist <= snap_strength && dist < *best_horz) { + dst[X] = snap[X] + snap[W]; + *best_horz = dist; + } + + /* Snap right side to left side */ + dist = abs(snap[X] - (src[X] + src[W])); + if (dist <= snap_strength && dist < *best_horz) { + dst[X] = snap[X] - src[W]; + *best_horz = dist; + } + + /* Snap right side to right side */ + dist = abs((snap[X] + snap[W]) - (src[X]+src[W])); + if (dist <= snap_strength && dist < *best_horz) { + dst[X] = snap[X] + snap[W] - src[W]; + *best_horz = dist; + } + + /* Snap midlines */ + if (/* Left of 'src' is before right of 'snap' */ + (src[X] <= snap[X] + snap[W] + snap_strength) && + /* Right of 'src' is after left of 'snap' */ + (src[X] + src[W] >= snap[X] - snap_strength)) { + + /* Snap vertically */ + dist = abs((snap[X] + snap[W]/2) - (src[X]+src[W]/2)); + if (dist <= snap_strength && dist < *best_horz) { + dst[X] = snap[X] + snap[W]/2 - src[W]/2; + *best_horz = dist; + } + } + } + +} /* snap_dim_to_dim() */ + + + +/** snap_side_to_dim() ********************************************** + * + * Snaps the sides of src to snap and stores the result in dst + * + * Returns 1 if a snap occured. + * + **/ + +static void snap_side_to_dim(int *dst, int *src, int *snap, int snap_strength, + int *best_vert, int *best_horz) +{ + int dist; + + + /* Snap vertically */ + if (best_vert) { + + /* Snap side to top side */ + dist = abs(snap[Y] - (src[Y] + src[H])); + if (dist <= snap_strength && dist < *best_vert) { + dst[H] = snap[Y] - src[Y]; + *best_vert = dist; + } + + /* Snap side to bottom side */ + dist = abs((snap[Y] + snap[H]) - (src[Y] + src[H])); + if (dist <= snap_strength && dist < *best_vert) { + dst[H] = snap[Y] + snap[H] - src[Y]; + *best_vert = dist; + } + } + + + /* Snap horizontally */ + if (best_horz) { + + /* Snap side to left side */ + dist = abs(snap[X] - (src[X] + src[W])); + if (dist <= snap_strength && dist < *best_horz) { + dst[W] = snap[X] - src[X]; + *best_horz = dist; + } + + /* Snap side to right side */ + dist = abs((snap[X] + snap[W]) - (src[X] + src[W])); + if (dist <= snap_strength && dist < *best_horz) { + dst[W] = snap[X] + snap[W] - src[X]; + *best_horz = dist; + } + } + +} /* snap_side_to_dim() */ + + + +/** snap_move() ***************************************************** + * + * Snaps the given dimensions 'dim' (viewport or panning domain of + * a dislay) to other display devices' viewport and/or panning + * domains in the layout due to a move. + * + * Returns 1 if a snap occured, 0 if not. + * + **/ + +static int snap_move(CtkDisplayLayout *ctk_object, int *dim) +{ + int dim_orig[4]; + int best_vert; + int best_horz; + int *bv; + int *bh; + int z; + int dist; + nvDisplayPtr display; + nvDisplayPtr other; + nvGpuPtr gpu; + nvScreenPtr screen; + + + display = get_selected(ctk_object); + gpu = display->gpu; + screen = display->screen; + + + /* We will know that a snap occured if + * 'best_xxxx' <= ctk_object->snap_strength, so we + * initialize both directions to not having snapped here. + */ + best_vert = ctk_object->snap_strength +1; + best_horz = ctk_object->snap_strength +1; + + + /* Copy the original dimensions (Always snap from this reference) */ + dim_orig[X] = dim[X]; + dim_orig[Y] = dim[Y]; + dim_orig[W] = dim[W]; + dim_orig[H] = dim[H]; + + + /* Snap to other display's modes */ + for (z = 1; z < ctk_object->Zcount; z++) { + + other = ctk_object->Zorder[z]; + + /* Other display must have a mode */ + if (!other || !other->cur_mode || !other->screen) continue; + + + bv = &best_vert; + bh = &best_horz; + + /* We shouldn't snap horizontally to the other display if + * we are in a right-of/left-of relative relationship with + * the other display/display's screen. + */ + if (((other->cur_mode->position_type == CONF_ADJ_RIGHTOF) || + (other->cur_mode->position_type == CONF_ADJ_LEFTOF)) && + (other->cur_mode->relative_to == display)) { + bh = NULL; + } + if (((display->cur_mode->position_type == CONF_ADJ_RIGHTOF) || + (display->cur_mode->position_type == CONF_ADJ_LEFTOF)) && + (display->cur_mode->relative_to == other)) { + bh = NULL; + } + if (display->screen && other->screen && + ((other->screen->position_type == CONF_ADJ_RIGHTOF) || + (other->screen->position_type == CONF_ADJ_LEFTOF)) && + (other->screen->relative_to == display->screen)) { + bh = NULL; + } + if (display->screen && other->screen && + ((display->screen->position_type == CONF_ADJ_RIGHTOF) || + (display->screen->position_type == CONF_ADJ_LEFTOF)) && + (display->screen->relative_to == other->screen)) { + bh = NULL; + } + + /* If we aren't snapping horizontally with the other display, + * we shouldn't snap vertically either if this is the top-most + * display in the screen. + */ + if (!bh && display->cur_mode->dim[Y] == display->screen->dim[Y]) { + bv = NULL; + } + + + /* We shouldn't snap vertically to the other display if + * we are in a above/below relative relationship with + * the other display/display's screen. + */ + if (((other->cur_mode->position_type == CONF_ADJ_ABOVE) || + (other->cur_mode->position_type == CONF_ADJ_BELOW)) && + (other->cur_mode->relative_to == display)) { + bv = NULL; + } + if (((display->cur_mode->position_type == CONF_ADJ_ABOVE) || + (display->cur_mode->position_type == CONF_ADJ_BELOW)) && + (display->cur_mode->relative_to == other)) { + bv = NULL; + } + + if (display->screen && other->screen && + ((other->screen->position_type == CONF_ADJ_ABOVE) || + (other->screen->position_type == CONF_ADJ_BELOW)) && + (other->screen->relative_to == display->screen)) { + bv = NULL; + } + if (display->screen && other->screen && + ((display->screen->position_type == CONF_ADJ_ABOVE) || + (display->screen->position_type == CONF_ADJ_BELOW)) && + (display->screen->relative_to == other->screen)) { + bv = NULL; + } + + /* If we aren't snapping vertically with the other display, + * we shouldn't snap horizontally either if this is the left-most + * display in the screen. + */ + if (!bv && display->cur_mode->dim[X] == display->screen->dim[X]) { + bh = NULL; + } + + + /* Snap to other display's panning dimensions */ + snap_dim_to_dim(dim, + dim_orig, + ctk_object->Zorder[z]->cur_mode->pan, + ctk_object->snap_strength, + bv, bh); + + /* Snap to other display's dimensions */ + snap_dim_to_dim(dim, + dim_orig, + ctk_object->Zorder[z]->cur_mode->dim, + ctk_object->snap_strength, + bv, bh); + } + + + /* Snap to the maximum screen dimensions */ + dist = abs(screen->dim[X] + gpu->max_width - dim_orig[W] - dim_orig[X]); + if (dist <= ctk_object->snap_strength && dist < best_horz) { + dim[X] = screen->dim[X] + gpu->max_width - dim_orig[W]; + best_horz = dist; + } + dist = abs(screen->dim[Y] + gpu->max_height - dim_orig[H] - dim_orig[Y]); + if (dist <= ctk_object->snap_strength && dist < best_vert) { + dim[Y] = screen->dim[Y] + gpu->max_height - dim_orig[H]; + best_vert = dist; + } + + + return (best_vert <= ctk_object->snap_strength || + best_horz <= ctk_object->snap_strength); + +} /* snap_move() */ + + + +/** snap_pan() ****************************************************** + * + * Snaps the bottom right of the panning domain given 'pan' of the + * currently selected display to other display devices' viewport + * and/or panning domains in the layout due to a panning domain + * resize. + * + * Returns 1 if a snap happened, 0 if not. + * + **/ + +static int snap_pan(CtkDisplayLayout *ctk_object, int *pan, int *dim) +{ + int pan_orig[4]; + int best_vert; + int best_horz; + int *bv; + int *bh; + int z; + int dist; + nvDisplayPtr display; + nvDisplayPtr other; + nvGpuPtr gpu; + nvScreenPtr screen; + + + display = get_selected(ctk_object); + gpu = display->gpu; + screen = display->screen; + + + /* We will know that a snap occured if + * 'best_xxxx' <= ctk_object->snap_strength, so we + * initialize both directions to not having snapped here. + */ + best_vert = ctk_object->snap_strength +1; + best_horz = ctk_object->snap_strength +1; + + + /* Copy the original dimensions (Always snap from this reference) */ + pan_orig[X] = pan[X]; + pan_orig[Y] = pan[Y]; + pan_orig[W] = pan[W]; + pan_orig[H] = pan[H]; + + + /* Snap to other display's modes */ + for (z = 1; z < ctk_object->Zcount; z++) { + + other = ctk_object->Zorder[z]; + + /* Other display must have a mode */ + if (!other || !other->cur_mode || !other->screen) continue; + + bv = &best_vert; + bh = &best_horz; + + + /* Don't snap to other displays that are positioned right of + * the display being panned. + */ + if ((other->cur_mode->position_type == CONF_ADJ_RIGHTOF) && + other->cur_mode->relative_to == display) { + bh = NULL; + } + if ((display->cur_mode->position_type == CONF_ADJ_LEFTOF) && + display->cur_mode->relative_to == other) { + bh = NULL; + } + if (display->screen && other->screen && + (other->screen->position_type == CONF_ADJ_RIGHTOF) && + (other->screen->relative_to == display->screen)) { + bh = NULL; + } + if (display->screen && other->screen && + (display->screen->position_type == CONF_ADJ_LEFTOF) && + (display->screen->relative_to == other->screen)) { + bh = NULL; + } + + /* Don't snap to other displays that are positioned below of + * the display being panned. + */ + if ((other->cur_mode->position_type == CONF_ADJ_BELOW) && + other->cur_mode->relative_to == display) { + bv = NULL; + } + if ((display->cur_mode->position_type == CONF_ADJ_ABOVE) && + display->cur_mode->relative_to == other) { + bv = NULL; + } + if (display->screen && other->screen && + (other->screen->position_type == CONF_ADJ_BELOW) && + (other->screen->relative_to == display->screen)) { + bv = NULL; + } + if (display->screen && other->screen && + (display->screen->position_type == CONF_ADJ_ABOVE) && + (display->screen->relative_to == other->screen)) { + bv = NULL; + } + + /* Snap to other screen panning dimensions */ + snap_side_to_dim(pan, + pan_orig, + ctk_object->Zorder[z]->cur_mode->pan, + ctk_object->snap_strength, + bv, bh); + + /* Snap to other screen dimensions */ + snap_side_to_dim(pan, + pan_orig, + ctk_object->Zorder[z]->cur_mode->dim, + ctk_object->snap_strength, + bv, bh); + } + + + /* Snap to multiples of the display's dimensions */ + dist = pan_orig[W] % dim[W]; + if (dist <= ctk_object->snap_strength && dist < best_horz) { + pan[W] = dim[W] * (int)(pan_orig[W] / dim[W]); + best_horz = dist; + } + dist = dim[W] - (pan_orig[W] % dim[W]); + if (dist <= ctk_object->snap_strength && dist < best_horz) { + pan[W] = dim[W] * (1 + (int)(pan_orig[W] / dim[W])); + best_horz = dist; + } + dist = abs(pan_orig[H] % dim[H]); + if (dist <= ctk_object->snap_strength && dist < best_vert) { + pan[H] = dim[H] * (int)(pan_orig[H] / dim[H]); + best_vert = dist; + } + dist = dim[H] - (pan_orig[H] % dim[H]); + if (dist <= ctk_object->snap_strength && dist < best_vert) { + pan[H] = dim[H] * (1 + (int)(pan_orig[H] / dim[H])); + best_vert = dist; + } + + + /* Snap to the maximum screen dimensions */ + dist = abs((screen->dim[X] + gpu->max_width) + -(pan_orig[X] + pan_orig[W])); + if (dist <= ctk_object->snap_strength && dist < best_horz) { + pan[W] = screen->dim[X] + gpu->max_width - pan_orig[X]; + best_horz = dist; + } + dist = abs((screen->dim[Y] + gpu->max_height) + -(pan_orig[Y] + pan_orig[H])); + if (dist <= ctk_object->snap_strength && dist < best_vert) { + pan[H] = screen->dim[Y] + gpu->max_height - pan_orig[Y]; + best_vert = dist; + } + + + return (best_vert <= ctk_object->snap_strength || + best_horz <= ctk_object->snap_strength); + +} /* snap_pan() */ + + + +/** move_selected() ************************************************** + * + * Moves the selected display device by the given offset, optionally + * snapping to other displays. + * + * If something actually moved, this function returns 1. Otherwise + * 0 is returned. + * + **/ + +static int move_selected(CtkDisplayLayout *ctk_object, int x, int y, int snap) +{ + nvLayoutPtr layout = ctk_object->layout; + nvDisplayPtr display; + nvGpuPtr gpu; + nvScreenPtr screen; + int *pan; + int *dim; + int orig_pos[2]; + int post_snap_display_pos[2]; + int orig_mm_pos[2]; + int snap_dim[4]; + + + /* Get the dimensions of the display to move */ + display = get_selected(ctk_object); + if (!display || + !display->screen || + !display->cur_mode || + display->cur_mode->position_type != CONF_ADJ_ABSOLUTE) { + return 0; + } + gpu = display->gpu; + screen = display->screen; + dim = display->cur_mode->dim; + pan = display->cur_mode->pan; + orig_pos[X] = dim[X]; + orig_pos[Y] = dim[Y]; + orig_mm_pos[X] = display->screen->cur_metamode->dim[X]; + orig_mm_pos[Y] = display->screen->cur_metamode->dim[Y]; + + + /* Move the display */ + ctk_object->modify_dim[X] += x; + ctk_object->modify_dim[Y] += y; + snap_dim[X] = ctk_object->modify_dim[X]; /* Snap from move dim */ + snap_dim[Y] = ctk_object->modify_dim[Y]; + snap_dim[W] = dim[W]; + snap_dim[H] = dim[H]; + + + /* Snap */ + if (snap && ctk_object->snap_strength) { + + /* Snap our viewport to other screens */ + snap_move(ctk_object, snap_dim); + + /* Snap our panning domain to other screens */ + snap_dim[W] = pan[W]; + snap_dim[H] = pan[H]; + snap_move(ctk_object, snap_dim); + } + dim[X] = snap_dim[X]; + dim[Y] = snap_dim[Y]; + pan[X] = dim[X]; + pan[Y] = dim[Y]; + + + /* Prevent layout from growing too big */ + x = MAX_LAYOUT_WIDTH - pan[W]; + if (dim[X] > x) { + ctk_object->modify_dim[X] += x - dim[X]; + dim[X] = x; + } + y = MAX_LAYOUT_HEIGHT - pan[H]; + if (dim[Y] > y) { + ctk_object->modify_dim[Y] += y - dim[Y]; + dim[Y] = y; + } + x = layout->dim[W] - MAX_LAYOUT_WIDTH; + if (dim[X] < x) { + ctk_object->modify_dim[X] += x - dim[X]; + dim[X] = x; + } + y = layout->dim[H] - MAX_LAYOUT_HEIGHT; + if (dim[Y] < y) { + ctk_object->modify_dim[Y] += y - dim[Y]; + dim[Y] = y; + } + + + /* Prevent screen from growing too big */ + x = screen->dim[X] + gpu->max_width - pan[W]; + if (dim[X] > x) { + ctk_object->modify_dim[X] += x - dim[X]; + dim[X] = x; + } + y = screen->dim[Y] + gpu->max_height -pan[H]; + if (dim[Y] > y) { + ctk_object->modify_dim[Y] += y - dim[Y]; + dim[Y] = y; + } + x = screen->dim[X] + screen->dim[W] - gpu->max_width; + if (dim[X] < x) { + ctk_object->modify_dim[X] += x - dim[X]; + dim[X] = x; + } + y = screen->dim[Y] + screen->dim[H] - gpu->max_height; + if (dim[Y] < y) { + ctk_object->modify_dim[Y] += y - dim[Y]; + dim[Y] = y; + } + + + /* Sync panning position */ + pan[X] = dim[X]; + pan[Y] = dim[Y]; + + + /* Get the post-snap display position. If calculating the + * layout changes the display's position, the modify dim + * (used to mode the display) should be offset as well. + */ + post_snap_display_pos[X] = dim[X]; + post_snap_display_pos[Y] = dim[Y]; + + + /* If the display's screen is using absolute positioning, we should + * check to see if the position of the metamode has changed and if + * so, offset other metamodes on the screen (hence moving the screen's + * position.) + * + * If the screen is using relative positioning, don't offset + * metamodes since the screen's position is based on another + * screen. + */ + if (display->screen->position_type == CONF_ADJ_ABSOLUTE) { + resolve_displays_in_screen(display->screen); + calc_metamode(display->screen, display->screen->cur_metamode); + x = display->screen->cur_metamode->dim[X] - orig_mm_pos[X]; + y = display->screen->cur_metamode->dim[Y] - orig_mm_pos[Y]; + + if (x || y) { + nvDisplayPtr other; + nvModePtr mode; + + for (other = display->gpu->displays; other; other = other->next) { + + /* Other display must be in the same screen */ + if (other->screen != display->screen) continue; + + for (mode = other->modes; mode; mode = mode->next) { + + /* Only move non-current modes */ + if (mode == other->cur_mode) continue; + + /* Don't move modes that are relative */ + if (mode->position_type != CONF_ADJ_ABSOLUTE) continue; + + mode->dim[X] += x; + mode->dim[Y] += y; + mode->pan[X] = mode->dim[X]; + mode->pan[Y] = mode->dim[Y]; + } + } + } + } + + + /* Recalculate layout dimensions and scaling */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + + + /* Update the modify dim if the position of the selected display changed */ + if ((post_snap_display_pos[X] != dim[X] || + post_snap_display_pos[Y] != dim[Y])) { + ctk_object->modify_dim[X] += dim[X] - post_snap_display_pos[X]; + ctk_object->modify_dim[Y] += dim[Y] - post_snap_display_pos[Y]; + } + + + /* Did the actual position of the display device change? */ + if ((orig_pos[X] != dim[X] || orig_pos[Y] != dim[Y])) { + return 1; + } + + return 0; + +} /* move_selected() */ + + + +/** pan_selected() *************************************************** + * + * Changes the size of the panning domain of the selected display. + * + **/ + +static int pan_selected(CtkDisplayLayout *ctk_object, int x, int y, int snap) +{ + nvLayoutPtr layout = ctk_object->layout; + nvDisplayPtr display; + nvScreenPtr screen; + nvGpuPtr gpu; + int *dim; + int *pan; + int orig_dim[4]; + + + + /* Get the dimensions of the display to pan */ + display = get_selected(ctk_object); + if (!display || !display->screen || !display->cur_mode) { + return 0; + } + gpu = display->gpu; + screen = display->screen; + dim = display->cur_mode->dim; + pan = display->cur_mode->pan; + orig_dim[W] = pan[W]; + orig_dim[H] = pan[H]; + + + /* Resize the panning */ + ctk_object->modify_dim[W] += x; + ctk_object->modify_dim[H] += y; + + + /* Panning can never be smaller then the display viewport */ + if (ctk_object->modify_dim[W] < dim[W]) { + ctk_object->modify_dim[W] = dim[W]; + } + if (ctk_object->modify_dim[H] < dim[H]) { + ctk_object->modify_dim[H] = dim[H]; + } + + pan[W] = ctk_object->modify_dim[W]; /* Snap from panning dimensions */ + pan[H] = ctk_object->modify_dim[H]; + + + /* Snap to other screens and dimensions */ + if (snap && ctk_object->snap_strength) { + snap_pan(ctk_object, pan, dim); + } + + + /* Panning should not cause us to exceed the maximum layout dimensions */ + x = MAX_LAYOUT_WIDTH - pan[X]; + if (pan[W] > x) { + ctk_object->modify_dim[W] += x - pan[W]; + pan[W] = x; + } + y = MAX_LAYOUT_HEIGHT - pan[Y]; + if (pan[H] > y) { + ctk_object->modify_dim[H] += y - pan[H]; + pan[H] = y; + } + + + /* Panning should not cause us to exceed the maximum screen dimensions */ + x = screen->dim[X] + gpu->max_width - pan[X]; + if (pan[W] > x) { + ctk_object->modify_dim[W] += x - pan[W]; + pan[W] = x; + } + y = screen->dim[Y] + gpu->max_height - pan[Y]; + if (pan[H] > y) { + ctk_object->modify_dim[H] += y - pan[H]; + pan[H] = y; + } + + + /* Panning can never be smaller then the display viewport */ + if (pan[W] < dim[W]) { + pan[W] = dim[W]; + } + if (pan[H] < dim[H]) { + pan[H] = dim[H]; + } + + + /* Recalculate layout dimensions and scaling */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + + + if (orig_dim[W] != pan[W] || orig_dim[H] != pan[H]) { + return 1; + } + + return 0; + +} /* pan_selected() */ + + + +/** select_display() ************************************************* + * + * Moves the specified display to the top of the Zorder. + * + **/ + +static void select_display(CtkDisplayLayout *ctk_object, nvDisplayPtr display) +{ + int z; + + for (z = 0; z < ctk_object->Zcount; z++) { + + /* Find the display in question */ + if (ctk_object->Zorder[z] == display) { + + /* Bubble it to the top */ + while (z > 0) { + ctk_object->Zorder[z] = ctk_object->Zorder[z-1]; + z--; + } + ctk_object->Zorder[0] = display; + ctk_object->Zselected = 1; + break; + } + } + +} /* select_display() */ + + + +/** select_default_display() ***************************************** + * + * Select the top left most display + * + */ + +#define DIST_SQR(D) (((D)[X] * (D)[X]) + ((D)[Y] * (D)[Y])) + +static void select_default_display(CtkDisplayLayout *ctk_object) +{ + nvDisplayPtr display = NULL; + int z; + + for (z = 0; z < ctk_object->Zcount; z++) { + + if (!ctk_object->Zorder[z]->cur_mode) continue; + + if (!display || + (DIST_SQR(display->cur_mode->dim) > + DIST_SQR(ctk_object->Zorder[z]->cur_mode->dim))) { + display = ctk_object->Zorder[z]; + } + } + + if (display) { + select_display(ctk_object, display); + } + +} /* select_default_display() */ + + + +/** pushback_display() *********************************************** + * + * Moves the specified display to the end of the Zorder + * + **/ + +static void pushback_display(CtkDisplayLayout *ctk_object, + nvDisplayPtr display) +{ + int z; + + if (!ctk_object->Zcount) { + return; + } + + for (z = 0; z < ctk_object->Zcount; z++) { + + /* Find the display */ + if (ctk_object->Zorder[z] == display) { + + /* Bubble it down */ + while (z < ctk_object->Zcount -1) { + ctk_object->Zorder[z] = ctk_object->Zorder[z+1]; + z++; + } + ctk_object->Zorder[ctk_object->Zcount -1] = display; + break; + } + } + +} /* pushback_display() */ + + + +/** get_display_tooltip() ******************************************** + * + * Returns the text to use for displaying a tooltip from the given + * display: + * + * MONITOR NAME : WIDTHxHEIGHT @ HERTZ (GPU NAME) + * + * The caller should free the string that is returned. + * + **/ + +static char *get_display_tooltip(CtkDisplayLayout *ctk_object, + nvDisplayPtr display) +{ + char *tip; + + + /* No display given */ + if (!display) { + return NULL; + } + + + /* Display does not have a screen (not configured) */ + if (!(display->screen)) { + tip = g_strdup_printf("%s : Disabled (GPU: %s)", + display->name, display->gpu->name); + + + /* Basic view */ + } else if (!ctk_object->advanced_mode) { + + /* Display has no mode */ + if (!display->cur_mode) { + tip = g_strdup_printf("%s", display->name); + + + /* Display does not have a current modeline (Off) */ + } else if (!(display->cur_mode->modeline)) { + tip = g_strdup_printf("%s : Off", + display->name); + + /* Display has mode/modeline */ + } else { + float ref = GET_MODELINE_REFRESH_RATE(display->cur_mode->modeline); + tip = g_strdup_printf("%s : %dx%d @ %.0f Hz", + display->name, + display->cur_mode->modeline->data.hdisplay, + display->cur_mode->modeline->data.vdisplay, + ref); + } + + + /* Advanced view */ + } else { + + + /* Display has no mode */ + if (!display->cur_mode) { + tip = g_strdup_printf("%s : (Screen: %d) (GPU: %s)", + display->name, + display->screen->scrnum, + display->gpu->name); + + /* Display does not have a current modeline (Off) */ + } else if (!(display->cur_mode->modeline)) { + tip = g_strdup_printf("%s : Off (Screen: %d) (GPU: %s)", + display->name, + display->screen->scrnum, + display->gpu->name); + + /* Display has mode/modeline */ + } else { + float ref = GET_MODELINE_REFRESH_RATE(display->cur_mode->modeline); + tip = g_strdup_printf("%s : %dx%d @ %.0f Hz (Screen: %d) " + "(GPU: %s)", + display->name, + display->cur_mode->modeline->data.hdisplay, + display->cur_mode->modeline->data.vdisplay, + ref, + display->screen->scrnum, + display->gpu->name); + } + } + + return tip; + +} /* get_display_tooltip() */ + + + +/** get_display_tooltip_under_mouse() ******************************** + * + * Returns the tooltip text that should be used to give information + * about the display under the mouse at x, y. + * + * The caller should free the string that is returned. + * + **/ + +static char *get_display_tooltip_under_mouse(CtkDisplayLayout *ctk_object, + int x, int y) +{ + int z; + static nvDisplayPtr last_display = NULL; + + + /* Scale and offset x & y so they reside in clickable area */ + x = (x -ctk_object->img_dim[X]) / ctk_object->scale; + y = (y -ctk_object->img_dim[Y]) / ctk_object->scale; + + + /* Find the first display under the cursor */ + z = 0; + while (z < ctk_object->Zcount) { + if (ctk_object->Zorder[z]->cur_mode && + point_in_dim(ctk_object->Zorder[z]->cur_mode->dim, x, y)) { + if (ctk_object->Zorder[z] == last_display) { + return NULL; + } + last_display = ctk_object->Zorder[z]; + return get_display_tooltip(ctk_object, ctk_object->Zorder[z]); + } + z++; + } + + /* Check display pannings as a last resort */ + z = 0; + while (z < ctk_object->Zcount) { + if (ctk_object->Zorder[z]->cur_mode && + point_in_dim(ctk_object->Zorder[z]->cur_mode->pan, x, y)) { + if (ctk_object->Zorder[z] == last_display) { + return NULL; + } + last_display = ctk_object->Zorder[z]; + return get_display_tooltip(ctk_object, ctk_object->Zorder[z]); + } + z++; + } + + + if (last_display) { + last_display = NULL; + return g_strdup("*** No Display ***"); + } + + return NULL; + +} /* get_display_tooltip_under_mouse() */ + + + +/** click_layout() *************************************************** + * + * Preforms a click in the layout, possibly selecting a display. + * + **/ + +static int click_layout(CtkDisplayLayout *ctk_object, int x, int y) +{ + int z; + nvDisplayPtr cur_selected; + + + /* Make sure there is something to click */ + if (!ctk_object->Zcount) { + return 0; + } + + + /* Keep track of the currently selected display */ + cur_selected = ctk_object->Zorder[0]; + + /* Assume user didn't actually click inside a display for now */ + ctk_object->clicked_outside = 1; + + /* Push selected screen to the back of Z order */ + ctk_object->Zselected = 0; + if (ctk_object->select_next) { + pushback_display(ctk_object, ctk_object->Zorder[0]); + } + + /* Find the first display under the cursor */ + z = 0; + while (z < ctk_object->Zcount) { + if (ctk_object->Zorder[z]->cur_mode && + point_in_dim(ctk_object->Zorder[z]->cur_mode->dim, x, y)) { + select_display(ctk_object, ctk_object->Zorder[z]); + ctk_object->clicked_outside = 0; + break; + } + z++; + } + + /* Check if we clicked on a panning domain */ + if (!(ctk_object->Zselected)) { + z = 0; + while (z < ctk_object->Zcount) { + if (ctk_object->Zorder[z]->cur_mode && + point_in_dim(ctk_object->Zorder[z]->cur_mode->pan, x, y)) { + select_display(ctk_object, ctk_object->Zorder[z]); + ctk_object->clicked_outside = 0; + break; + } + z++; + } + } + + /* Reselect the last display */ + if (ctk_object->clicked_outside && cur_selected) { + select_display(ctk_object, cur_selected); + } + + /* Sync modify dimensions to the newly selected display */ + sync_modify(ctk_object); + + return 1; + +} /* click_layout() */ + + + +/** ctk_display_layout_get_type() ************************************ + * + * Returns the CtkDisplayLayout type. + * + **/ + +GType ctk_display_layout_get_type(void) +{ + static GType ctk_display_layout_type = 0; + + if (!ctk_display_layout_type) { + static const GTypeInfo ctk_display_layout_info = { + sizeof (CtkDisplayLayoutClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(CtkDisplayLayout), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_display_layout_type = g_type_register_static + (GTK_TYPE_VBOX, "CtkDisplayLayout", &ctk_display_layout_info, 0); + } + + return ctk_display_layout_type; + +} /* ctk_display_layout_get_type() */ + + + +/** ctk_display_layout_new() ***************************************** + * + * CTK Display Layout widget creation. + * + */ +GtkWidget* ctk_display_layout_new(NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config, + nvLayoutPtr layout, + int width, + int height, + ctk_display_layout_selected_callback selected_callback, + void *selected_callback_data, + ctk_display_layout_modified_callback modified_callback, + void *modified_callback_data) +{ + GObject *object; + CtkDisplayLayout *ctk_object; + GtkWidget *tmp; + PangoFontDescription *font_description; + int i; + + + /* Make sure we have a handle */ + g_return_val_if_fail(handle != NULL, NULL); + + + /* Create the ctk object */ + object = g_object_new(CTK_TYPE_DISPLAY_LAYOUT, NULL); + ctk_object = CTK_DISPLAY_LAYOUT(object); + + /* Setup widget properties */ + ctk_object->ctk_config = ctk_config; + ctk_object->selected_callback = selected_callback; + ctk_object->selected_callback_data = selected_callback_data; + ctk_object->modified_callback = modified_callback; + ctk_object->modified_callback_data = modified_callback_data; + + ctk_object->handle = handle; + ctk_object->layout = layout; + calc_layout(layout); + sync_scaling(ctk_object); + zorder_layout(ctk_object); + select_default_display(ctk_object); + + + /* Setup Pango layout/font */ + ctk_object->pango_layout = + gtk_widget_create_pango_layout(GTK_WIDGET(ctk_object), NULL); + + pango_layout_set_alignment(ctk_object->pango_layout, PANGO_ALIGN_CENTER); + + font_description = pango_font_description_new(); + pango_font_description_set_family(font_description, "Sans"); + pango_font_description_set_weight(font_description, PANGO_WEIGHT_BOLD); + + pango_layout_set_font_description(ctk_object->pango_layout, font_description); + + + /* Setup colors */ + gdk_color_parse(LAYOUT_IMG_FG_COLOR, &(ctk_object->fg_color)); + gdk_color_parse(LAYOUT_IMG_BG_COLOR, &(ctk_object->bg_color)); + gdk_color_parse(LAYOUT_IMG_SELECT_COLOR, &(ctk_object->select_color)); + + /* Parse the device color palettes */ + ctk_object->color_palettes = + (GdkColor *)calloc(1, NUM_COLORS * sizeof(GdkColor)); + for (i = 0; i < NUM_COLORS; i++) { + gdk_color_parse(__palettes_color_names[i], + &(ctk_object->color_palettes[i])); + } + + + /* Setup the layout state variables */ + ctk_object->snap_strength = DEFAULT_SNAP_STRENGTH; + ctk_object->need_swap = 0; + ctk_object->select_next = 0; + + + /* Make the drawing area */ + tmp = gtk_drawing_area_new(); + gtk_widget_add_events(tmp, + GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK); + + g_signal_connect (G_OBJECT (tmp), "expose_event", + G_CALLBACK (expose_event_callback), (gpointer)(ctk_object)); + + g_signal_connect (G_OBJECT (tmp), "configure_event", + G_CALLBACK (configure_event_callback), (gpointer)(ctk_object)); + + g_signal_connect (G_OBJECT (tmp), "motion_notify_event", + G_CALLBACK (motion_event_callback), (gpointer)(ctk_object)); + + g_signal_connect (G_OBJECT (tmp), "button_press_event", + G_CALLBACK (button_press_event_callback), (gpointer)(ctk_object)); + + g_signal_connect (G_OBJECT (tmp), "button_release_event", + G_CALLBACK (button_release_event_callback), (gpointer)(ctk_object)); + + GTK_WIDGET_SET_FLAGS(tmp, GTK_DOUBLE_BUFFERED); + + ctk_object->drawing_area = tmp; + gtk_widget_set_size_request(tmp, width, height); + + + /* Set container properties of the object */ + gtk_box_set_spacing(GTK_BOX(ctk_object), 0); + + ctk_object->tooltip_area = gtk_event_box_new(); + ctk_object->tooltip_group = gtk_tooltips_new(); + + gtk_tooltips_enable(ctk_object->tooltip_group); + gtk_tooltips_set_tip(ctk_object->tooltip_group, + ctk_object->tooltip_area, + "*** No Display ***", NULL); + + gtk_container_add(GTK_CONTAINER(ctk_object->tooltip_area), tmp); + gtk_box_pack_start(GTK_BOX(object), ctk_object->tooltip_area, + TRUE, TRUE, 0); + + return GTK_WIDGET(ctk_object); + +} /* ctk_display_layout_new() */ + + + +/** do_swap() ******************************************************** + * + * Preforms a swap from the back buffer if one is needed. + * + **/ + +static void do_swap(CtkDisplayLayout *ctk_object) +{ + if (ctk_object->need_swap) { + + gdk_draw_pixmap(ctk_object->drawing_area->window, + ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + ctk_object->pixmap, + 0,0, + 0,0, + ctk_object->width, + ctk_object->height); + + ctk_object->need_swap = 0; + } + +} /* do_swap() */ + + + +/** draw_rect() ****************************************************** + * + * Draws a solid or wireframe rectangle to scale of the given color + * in the given widget. + * + **/ + +static void draw_rect(CtkDisplayLayout *ctk_object, + int *dim, + GdkColor *color, + int fill) +{ + int w = (int)(ctk_object->scale * (dim[X] + dim[W])) - (int)(ctk_object->scale * (dim[X])); + int h = (int)(ctk_object->scale * (dim[Y] + dim[H])) - (int)(ctk_object->scale * (dim[Y])); + + /* Setup color to use */ + gdk_gc_set_rgb_fg_color(ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE (ctk_object->drawing_area)], + color); + + /* Draw the rectangle */ + gdk_draw_rectangle(ctk_object->pixmap, + ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE (ctk_object->drawing_area)], + fill, + ctk_object->img_dim[X] + ctk_object->scale * dim[X], + ctk_object->img_dim[Y] + ctk_object->scale * dim[Y], + w, + h); + + ctk_object->need_swap = 1; + +} /* draw_rect() */ + + + +/** draw_rect_strs() ************************************************* + * + * Draws possibly 2 rows of text in the middle of a bounding, + * scaled rectangle. If the text does not fit, it is not drawn. + * + **/ + +static void draw_rect_strs(CtkDisplayLayout *ctk_object, + int *dim, + GdkColor *color, + const char *str_1, + const char *str_2) +{ + GdkGC *gdk_gc; + GtkWidget *drawing_area; + char *str; + + int txt_w; + int txt_h; + int txt_x, txt_x1, txt_x2; + int txt_y, txt_y1, txt_y2; + + int draw_1 = 0; + int draw_2 = 0; + + drawing_area = ctk_object->drawing_area; + gdk_gc = drawing_area->style->fg_gc[GTK_WIDGET_STATE(drawing_area)]; + + if (str_1) { + pango_layout_set_text(ctk_object->pango_layout, str_1, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + if (txt_w +8 <= ctk_object->scale * dim[W] && + txt_h +8 <= ctk_object->scale * dim[H]) { + draw_1 = 1; + } + } + + if (str_2) { + pango_layout_set_text(ctk_object->pango_layout, str_2, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + if (txt_w +8 <= ctk_object->scale * dim[W] && + txt_h +8 <= ctk_object->scale * dim[H]) { + draw_2 = 1; + } + + str = g_strconcat(str_1, "\n", str_2, NULL); + + pango_layout_set_text(ctk_object->pango_layout, str, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + if (draw_1 && draw_2 && + txt_h +8 > ctk_object->scale * dim[H]) { + draw_2 = 0; + } + + g_free(str); + } + + if (draw_1 && !draw_2) { + pango_layout_set_text(ctk_object->pango_layout, str_1, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + txt_x1 = ctk_object->scale*(dim[X] + dim[W] / 2) - (txt_w / 2); + txt_y1 = ctk_object->scale*(dim[Y] + dim[H] / 2) - (txt_h / 2); + + /* Write name */ + gdk_gc_set_rgb_fg_color(gdk_gc, color); + + gdk_draw_layout(ctk_object->pixmap, gdk_gc, + ctk_object->img_dim[X] + txt_x1, + ctk_object->img_dim[Y] + txt_y1, + ctk_object->pango_layout); + + ctk_object->need_swap = 1; + } + + else if (!draw_1 && draw_2) { + pango_layout_set_text(ctk_object->pango_layout, str_2, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + txt_x2 = ctk_object->scale*(dim[X] + dim[W] / 2) - (txt_w / 2); + txt_y2 = ctk_object->scale*(dim[Y] + dim[H] / 2) - (txt_h / 2); + + /* Write dimensions */ + gdk_gc_set_rgb_fg_color(gdk_gc, color); + + gdk_draw_layout(ctk_object->pixmap, gdk_gc, + ctk_object->img_dim[X] + txt_x2, + ctk_object->img_dim[Y] + txt_y2, + ctk_object->pango_layout); + + ctk_object->need_swap = 1; + } + + else if (draw_1 && draw_2) { + str = g_strconcat(str_1, "\n", str_2, NULL); + + pango_layout_set_text(ctk_object->pango_layout, str, -1); + pango_layout_get_pixel_size(ctk_object->pango_layout, &txt_w, &txt_h); + + txt_x = ctk_object->scale*(dim[X] + dim[W] / 2) - (txt_w / 2); + txt_y = ctk_object->scale*(dim[Y] + dim[H] / 2) - (txt_h / 2); + + /* Write both */ + gdk_gc_set_rgb_fg_color(gdk_gc, color); + + gdk_draw_layout(ctk_object->pixmap, gdk_gc, + ctk_object->img_dim[X] + txt_x, + ctk_object->img_dim[Y] + txt_y, + ctk_object->pango_layout); + + g_free(str); + } + +} /* draw_rect_strs() */ + + + +/** draw_display() *************************************************** + * + * Draws a display to scale within the layout. + * + **/ + +static void draw_display(CtkDisplayLayout *ctk_object, + nvDisplayPtr display) +{ + nvModePtr mode; + int color; + char *tmp_str; + + if (!display || !(display->cur_mode)) { + return; + } + + mode = display->cur_mode; + color = NUM_COLORS_PER_PALETTE * NvCtrlGetTargetId(display->gpu->handle); + + + /* Draw panning */ + draw_rect(ctk_object, mode->pan, + &(ctk_object->color_palettes[color +((mode->modeline)?BG_PAN_ON:BG_PAN_OFF)]), + 1); + draw_rect(ctk_object, mode->pan, &(ctk_object->fg_color), 0); + + + /* Draw viewport */ + draw_rect(ctk_object, mode->dim, + &(ctk_object->color_palettes[color +((mode->modeline)?BG_SCR_ON:BG_SCR_OFF)]), + 1); + draw_rect(ctk_object, mode->dim, &(ctk_object->fg_color), 0); + + + /* Draw text information */ + if (!mode->display->screen) { + tmp_str = g_strdup("(Disabled)"); + } else if (mode->modeline) { + tmp_str = g_strdup_printf("%dx%d", mode->dim[W], mode->dim[H]); + } else { + tmp_str = g_strdup("(Off)"); + } + draw_rect_strs(ctk_object, + mode->dim, + &(ctk_object->fg_color), + display->name, + tmp_str); + g_free(tmp_str); + +} /* draw_display() */ + + + +/** draw_layout() **************************************************** + * + * Draws a layout. + * + **/ + +static void draw_layout(CtkDisplayLayout *ctk_object) +{ + int z; + GdkColor bg_color; /* Background color */ + GdkColor bd_color; /* Border color */ + nvGpuPtr gpu; + nvScreenPtr screen; + + + /* Draw the metamode's effective size */ + gdk_color_parse("#888888", &bg_color); + gdk_color_parse("#777777", &bd_color); + + gdk_gc_set_line_attributes + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_NOT_LAST, + GDK_JOIN_ROUND); + + for (gpu = ctk_object->layout->gpus; gpu; gpu = gpu->next) { + for (screen = gpu->screens; screen; screen = screen->next) { + draw_rect(ctk_object, screen->cur_metamode->edim, &bg_color, 1); + draw_rect(ctk_object, screen->cur_metamode->edim, + &(ctk_object->fg_color), 0); + } + } + + gdk_gc_set_line_attributes + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + 1, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, + GDK_JOIN_ROUND); + + + /* Draw display devices from back to front */ + for (z = ctk_object->Zcount - 1; z >= 0; z--) { + draw_display(ctk_object, ctk_object->Zorder[z]); + ctk_object->need_swap = 1; + } + + + /* Hilite the selected display device */ + if (ctk_object->Zselected && ctk_object->Zcount) { + GtkWidget *widget = ctk_object->drawing_area; + int w, h; + int size; /* Hilite line size */ + int offset; /* Hilite box offset */ + int *dim; + + dim = ctk_object->Zorder[0]->cur_mode->dim; + + /* Draw red selection border */ + w = (int)(ctk_object->scale * (dim[X] + dim[W])) - (int)(ctk_object->scale * (dim[X])); + h = (int)(ctk_object->scale * (dim[Y] + dim[H])) - (int)(ctk_object->scale * (dim[Y])); + + /* Setup color to use */ + gdk_gc_set_rgb_fg_color(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &(ctk_object->select_color)); + + /* If dislay is too small, just color the whole thing */ + size = 3; + offset = (size/2) +1; + + if ((w -(2* offset) < 0) || (h -(2 *offset) < 0)) { + draw_rect(ctk_object, dim, &(ctk_object->select_color), 1); + draw_rect(ctk_object, dim, &(ctk_object->fg_color), 0); + + } else { + gdk_gc_set_line_attributes(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + size, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); + + gdk_draw_rectangle(ctk_object->pixmap, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + 0, + ctk_object->img_dim[X] +(ctk_object->scale * dim[X]) +offset, + ctk_object->img_dim[Y] +(ctk_object->scale * dim[Y]) +offset, + w -(2 * offset), + h -(2 * offset)); + + gdk_gc_set_line_attributes(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); + } + + /* Uncomment to show unsnapped dimensions */ + //gdk_color_parse("#DD4444", &bg_color); + //gdk_gc_set_rgb_fg_color(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + // &(bg_color)); + //draw_rect(ctk_object, ctk_object->modify_dim, &bg_color, 0); + + ctk_object->need_swap = 1; + } + +} /* draw_layout() */ + + + +/** clear_layout() *************************************************** + * + * Clears the layout. + * + **/ + +static void clear_layout(CtkDisplayLayout *ctk_object) +{ + GtkWidget *widget = ctk_object->drawing_area; + GdkColor color; + + + + /* Clear to background color */ + gdk_gc_set_rgb_fg_color(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &(ctk_object->bg_color)); + gdk_draw_rectangle(ctk_object->pixmap, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + TRUE, + 2, + 2, + widget->allocation.width -4, + widget->allocation.height -4); + + + /* Add white trim */ + gdk_color_parse("white", &color); + gdk_gc_set_rgb_fg_color(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &color); + gdk_draw_rectangle(ctk_object->pixmap, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + FALSE, + 1, + 1, + widget->allocation.width -3, + widget->allocation.height -3); + + + /* Add layout border */ + gdk_gc_set_rgb_fg_color(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &(ctk_object->fg_color)); + gdk_draw_rectangle(ctk_object->pixmap, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + FALSE, + 0, + 0, + widget->allocation.width -1, + widget->allocation.height -1); + + ctk_object->need_swap = 1; + +} /* clear_layout() */ + + + +/** draw_all() ******************************************************* + * + * Clears and redraws the entire layout. + * + **/ + +static void draw_all(CtkDisplayLayout *ctk_object) +{ + GdkGCValues old_gc_values; + GtkWidget *widget = ctk_object->drawing_area; + + + /* Redraw everything */ + gdk_gc_get_values(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &old_gc_values); + + clear_layout(ctk_object); + + draw_layout(ctk_object); + + gdk_gc_set_values(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &old_gc_values, + GDK_GC_FOREGROUND); + +} /* draw_all() */ + + + +/** ctk_display_layout_redraw() ************************************** + * + * Redraw everything in the layout and makes sure the widget is + * updated. + * + **/ + +void ctk_display_layout_redraw(CtkDisplayLayout *ctk_object) +{ + nvLayoutPtr layout = ctk_object->layout; + + /* Recalculate layout dimensions and scaling */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + + /* Redraw */ + draw_all(ctk_object); + + /* Refresh GUI */ + do_swap(ctk_object); + +} /* ctk_display_layout_redraw() */ + + + +/** ctk_display_layout_set_layout() ********************************** + * + * Configures the display layout widget to show the given layout. + * + **/ + +void ctk_display_layout_set_layout(CtkDisplayLayout *ctk_object, + nvLayoutPtr layout) +{ + /* Setup for the new layout */ + ctk_object->layout = layout; + zorder_layout(ctk_object); + select_default_display(ctk_object); + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + + /* Redraw */ + draw_all(ctk_object); + + /* Refresh GUI */ + do_swap(ctk_object); + +} /* ctk_display_layout_set_layout() */ + + + +/** ctk_display_layout_get_selected_display() ************************ + * + * Returns the selected display. + * + **/ + +nvDisplayPtr ctk_display_layout_get_selected_display(CtkDisplayLayout *ctk_object) +{ + return get_selected(ctk_object); + +} /* ctk_display_layout_get_selected_display() */ + + + +/** ctk_display_layout_get_selected_screen() ************************* + * + * Returns the selected screen. + * + **/ + +nvScreenPtr ctk_display_layout_get_selected_screen(CtkDisplayLayout *ctk_object) +{ + nvDisplayPtr display = get_selected(ctk_object); + if (display) { + return display->screen; + } + return NULL; + +} /* ctk_display_layout_get_selected_screen() */ + + + +/** ctk_display_layout_get_selected_gpu() **************************** + * + * Returns the selected gpu. + * + **/ + +nvGpuPtr ctk_display_layout_get_selected_gpu(CtkDisplayLayout *ctk_object) +{ + nvDisplayPtr display = get_selected(ctk_object); + if (display) { + return display->gpu; + } + return NULL; + +} /* ctk_display_layout_get_selected_gpu() */ + + + +/** ctk_display_layout_set_screen_metamode() ************************* + * + * Sets which metamode the screen should be use. + * + **/ + +void ctk_display_layout_set_screen_metamode(CtkDisplayLayout *ctk_object, + nvScreenPtr screen, + int new_metamode_idx) +{ + if (!screen) return; + + /* Make sure the metamode exists */ + if (new_metamode_idx < 0) { + new_metamode_idx = 0; + } else if (new_metamode_idx >= screen->num_metamodes) { + new_metamode_idx = screen->num_metamodes -1; + } + + /* Select the new metamode and recalculate layout dimensions and scaling */ + set_screen_metamode(ctk_object->layout, screen, new_metamode_idx); + recenter_layout(ctk_object->layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + + /* Redraw the layout */ + ctk_display_layout_redraw(ctk_object); + +} /* ctk_display_layout_set_screen_metamode() */ + + + +/** ctk_display_layout_add_screen_metamode() ************************* + * + * Adds a new metamode to the screen. + * + **/ + +void ctk_display_layout_add_screen_metamode(CtkDisplayLayout *ctk_object, + nvScreenPtr screen) +{ + nvDisplayPtr display = get_selected(ctk_object); + nvMetaModePtr metamode; + + + if (!screen || !screen->gpu) return; + + + /* Add a metamode to the screen */ + metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode)); + if (!metamode) return; + + /* Duplicate the currently selected metamode */ + metamode->id = -1; + metamode->source = METAMODE_SOURCE_NVCONTROL; + + /* Add the metamode after the currently selected metamode */ + metamode->next = screen->cur_metamode->next; + screen->cur_metamode->next = metamode; + screen->num_metamodes++; + + + /* Add a mode to each display */ + for (display = screen->gpu->displays; display; display = display->next) { + nvModePtr mode; + + if (display->screen != screen) continue; /* Display not in screen */ + + /* Create the mode */ + mode = (nvModePtr)calloc(1, sizeof(nvMode)); + if (!mode) goto fail; + + /* Link the mode to the metamode */ + mode->metamode = metamode; + + /* Duplicate the currently selected mode */ + mode->display = display; + if (display->cur_mode) { + mode->modeline = display->cur_mode->modeline; + mode->dim[X] = display->cur_mode->dim[X]; + mode->dim[Y] = display->cur_mode->dim[Y]; + mode->dim[W] = display->cur_mode->dim[W]; + mode->dim[H] = display->cur_mode->dim[H]; + mode->pan[X] = display->cur_mode->pan[X]; + mode->pan[Y] = display->cur_mode->pan[Y]; + mode->pan[W] = display->cur_mode->pan[W]; + mode->pan[H] = display->cur_mode->pan[H]; + mode->position_type = display->cur_mode->position_type; + mode->relative_to = display->cur_mode->relative_to; + } + + /* Add the mode after the currently selected mode */ + mode->next = display->cur_mode->next; + display->cur_mode->next = mode; + display->num_modes++; + } + + /* Select the newly created metamode */ + ctk_display_layout_set_screen_metamode(ctk_object, + screen, + (screen->cur_metamode_idx+1)); + return; + + fail: + /* XXX Need to bail better: + * - Remove metamode from screen + * - Remove any excess metamodes from the displays + */ + return; + +} /* ctk_display_layout_add_screen_metamode() */ + + + +/** ctk_display_layout_delete_screen_metamode() ********************** + * + * Deletes a metamode from the screen (also deletes corresponding + * modes from the screen's displays.) + * + **/ + +void ctk_display_layout_delete_screen_metamode(CtkDisplayLayout *ctk_object, + nvScreenPtr screen, + int metamode_idx) +{ + nvDisplayPtr display; + nvMetaModePtr metamode; + nvMetaModePtr metamode_prev; + nvModePtr mode ; + nvModePtr mode_prev; + int i; + + + if (!screen || !screen->gpu || metamode_idx >= screen->num_metamodes) { + return; + } + + + /* Don't delete the last metamode */ + if (screen->num_metamodes <= 1) { + return; + } + + + /* Find the metamode */ + metamode_prev = NULL; + metamode = screen->metamodes; + i = 0; + while (metamode && i < metamode_idx) { + metamode_prev = metamode; + metamode = metamode->next; + i++; + } + + + /* Remove the metamode from the list */ + if (!metamode_prev) { + screen->metamodes = screen->metamodes->next; + } else { + metamode_prev->next = metamode->next; + } + screen->num_metamodes--; + + if (screen->cur_metamode == metamode) { + screen->cur_metamode = metamode->next; + } + if (screen->cur_metamode_idx >= screen->num_metamodes) { + screen->cur_metamode_idx = screen->num_metamodes -1; + } + + free(metamode); + + + /* Delete the mode from each display in the screen */ + for (display = screen->gpu->displays; display; display = display->next) { + + if (display->screen != screen) continue; + + /* Find the mode */ + mode_prev = NULL; + mode = display->modes; + for (i = 0; i != metamode_idx; i++) { + mode_prev = mode; + mode = mode->next; + } + + /* Remove the mode from the list */ + if (!mode_prev) { + display->modes = display->modes->next; + } else { + mode_prev->next = mode->next; + } + display->num_modes--; + + if (display->cur_mode == mode) { + display->cur_mode = mode->next; + } + + /* Delete the mode */ + free(mode); + } + + + /* Update which metamode should be selected */ + ctk_display_layout_set_screen_metamode + (ctk_object, screen, screen->cur_metamode_idx); + +} /* ctk_display_layout_delete_screen_metamode() */ + + + +/** ctk_display_layout_set_mode_modeline() *************************** + * + * Sets which modeline the mode should use. + * + **/ + +void ctk_display_layout_set_mode_modeline(CtkDisplayLayout *ctk_object, + nvModePtr mode, + nvModeLinePtr modeline) +{ + nvLayoutPtr layout = ctk_object->layout; + nvModeLinePtr old_modeline; + + if (!mode) { + return; + } + + /* Set the new modeline */ + old_modeline = mode->modeline; + mode->modeline = modeline; + + + /* Setup the mode's dimensions based on the modeline */ + if (modeline) { + mode->dim[W] = modeline->data.hdisplay; + mode->dim[H] = modeline->data.vdisplay; + + if (mode->pan[W] < modeline->data.hdisplay) { + mode->pan[W] = modeline->data.hdisplay; + } + if (mode->pan[H] < modeline->data.vdisplay) { + mode->pan[H] = modeline->data.vdisplay; + } + + /* If the old modeline did not have panning dimensions */ + if (!old_modeline || + (mode->pan[W] == old_modeline->data.hdisplay)) { + mode->pan[W] = modeline->data.hdisplay; + } + if (!old_modeline || + (mode->pan[H] == old_modeline->data.vdisplay)) { + mode->pan[H] = modeline->data.vdisplay; + } + + } else if (mode->display) { + /* Display is being turned off, set the default width/height */ + mode->dim[W] = mode->display->modelines->data.hdisplay; + mode->dim[H] = mode->display->modelines->data.vdisplay; + mode->pan[W] = mode->display->modelines->data.hdisplay; + mode->pan[H] = mode->display->modelines->data.vdisplay; + } + + /* The metamode that this mode belongs to should now be + * considered a user metamode. + */ + if (mode->metamode) { + mode->metamode->source = METAMODE_SOURCE_NVCONTROL; + } + + /* Recalculate layout dimensions and scaling */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + + + /* Redraw the layout */ + ctk_display_layout_redraw(ctk_object); + +} /* ctk_display_layout_set_display_modeline() */ + + + +/** ctk_display_layout_set_display_position() ************************ + * + * Sets the absolute/relative position of the display. + * + **/ + +void ctk_display_layout_set_display_position(CtkDisplayLayout *ctk_object, + nvDisplayPtr display, + int position_type, + nvDisplayPtr relative_to, + int x, int y) +{ + GdkGCValues old_gc_values; + int modified = 0; + nvLayoutPtr layout = ctk_object->layout; + + + if (!display) return; + + if (position_type != CONF_ADJ_ABSOLUTE && !relative_to) return; + + + /* Backup the foreground color and clear the layout */ + gdk_gc_get_values + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values); + + clear_layout(ctk_object); + + + /* XXX When transitioning from absolute to relative, make sure + * all displays that are relative to us become absolute. + * This is to avoid relationship loops. Eventually, we'll want + * to be able to handle weird loops since X does this. + */ + + if (display->cur_mode->position_type == CONF_ADJ_ABSOLUTE && + position_type != CONF_ADJ_ABSOLUTE) { + + nvDisplayPtr other; + + for (other = display->gpu->displays; other; other = other->next) { + + if (other->screen != display->screen) continue; + + if (!other->cur_mode) continue; + + if (other->cur_mode->relative_to == display) { + other->cur_mode->position_type = CONF_ADJ_ABSOLUTE; + other->cur_mode->relative_to = NULL; + } + } + } + + + /* Set the new positioning type */ + display->cur_mode->position_type = position_type; + display->cur_mode->relative_to = relative_to; + + switch (position_type) { + case CONF_ADJ_ABSOLUTE: + /* Do the move by offsetting */ + sync_modify(ctk_object); + modified = move_selected(ctk_object, + x - display->cur_mode->dim[X], + y - display->cur_mode->dim[Y], + 0); + + /* Report back result of move */ + if (ctk_object->modified_callback && + (modified || + x != display->cur_mode->dim[X] || + y != display->cur_mode->dim[Y])) { + ctk_object->modified_callback + (ctk_object->layout, ctk_object->modified_callback_data); + } + break; + + default: + /* Recalculate the layout */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + break; + } + + + /* Redraw the layout and reset the foreground color */ + draw_layout(ctk_object); + + gdk_gc_set_values + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values, GDK_GC_FOREGROUND); + + do_swap(ctk_object); + +} /* ctk_display_layout_set_display_position() */ + + + +/** ctk_display_layout_set_display_panning() ************************* + * + * Sets the panning domain of the display. + * + **/ + +void ctk_display_layout_set_display_panning(CtkDisplayLayout *ctk_object, + nvDisplayPtr display, + int width, int height) +{ + GdkGCValues old_gc_values; + int modified = 0; + + + if (!display) return; + + + /* Backup the foreground color */ + gdk_gc_get_values(ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values); + + clear_layout(ctk_object); + + + /* Change the panning */ + sync_modify(ctk_object); + modified = pan_selected(ctk_object, + width - display->cur_mode->pan[W], + height - display->cur_mode->pan[H], + 0); + + + /* Report back result of move */ + if (ctk_object->modified_callback && + (modified || + width != display->cur_mode->pan[W] || + height != display->cur_mode->pan[H])) { + ctk_object->modified_callback(ctk_object->layout, + ctk_object->modified_callback_data); + } + + draw_layout(ctk_object); + + + /* Reset the foreground color */ + gdk_gc_set_values(ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values, + GDK_GC_FOREGROUND); + + do_swap(ctk_object); + + +} /* ctk_display_layout_set_display_panning() */ + + + +/** ctk_display_layout_update_display_count() ************************ + * + * Updates the number of displays shown in the layout by re-building + * the Zorder list. + * + **/ + +void ctk_display_layout_update_display_count(CtkDisplayLayout *ctk_object, + nvDisplayPtr display) +{ + /* Update the Z order */ + zorder_layout(ctk_object); + if (display) { + /* Select the previously selected display */ + select_display(ctk_object, display); + } else if (ctk_object->Zcount) { + /* Select the new topmost display */ + select_display(ctk_object, ctk_object->Zorder[0]); + } + +} /* ctk_display_layout_update_display_count() */ + + + +/** ctk_display_layout_set_screen_depth() **************************** + * + * Sets which modeline the screen should use. + * + **/ + +void ctk_display_layout_set_screen_depth(CtkDisplayLayout *ctk_object, + nvScreenPtr screen, + int depth) +{ + /* Setup screen's default depth */ + if (screen) { + screen->depth = depth; + } + +} /* ctk_display_layout_set_screen_depth() */ + + + +/** ctk_display_layout_set_screen_position() ************************* + * + * Sets the absolute/relative position of the screen. + * + **/ + +void ctk_display_layout_set_screen_position(CtkDisplayLayout *ctk_object, + nvScreenPtr screen, + int position_type, + nvScreenPtr relative_to, + int x, int y) +{ + GdkGCValues old_gc_values; + int modified = 0; + nvLayoutPtr layout = ctk_object->layout; + nvGpuPtr gpu; + int draw; + + if (!screen) return; + + if (position_type != CONF_ADJ_ABSOLUTE && !relative_to) return; + + + /* If there is no GC for the drawing area, don't draw */ + draw = ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)] ? + 1 : 0; + + + /* Backup the foreground color and clear the layout */ + if (draw) { + gdk_gc_get_values + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values); + clear_layout(ctk_object); + } + + + /* XXX When transitioning from absolute to relative, make sure + * all screens that are relative to us become absolute. + * This is to avoid relationship loops. Eventually, we'll want + * to be able to handle weird loops since X does this. + */ + + if (screen->position_type == CONF_ADJ_ABSOLUTE && + position_type != CONF_ADJ_ABSOLUTE) { + + nvScreenPtr other; + + for (gpu = layout->gpus; gpu; gpu = gpu->next) { + for (other = gpu->screens; other; other = other->next) { + if (other->relative_to == screen) { + other->position_type = CONF_ADJ_ABSOLUTE; + other->relative_to = NULL; + } + } + } + } + + + /* Set the new positioning type */ + screen->relative_to = relative_to; + screen->position_type = position_type; + + switch (position_type) { + case CONF_ADJ_ABSOLUTE: + { + nvDisplayPtr other; + int x_offset = x - screen->dim[X]; + int y_offset = y - screen->dim[Y]; + + /* Do the move by offsetting */ + calc_screen(screen); + sync_modify(ctk_object); + offset_screen(screen, x_offset, y_offset); + for (other = screen->gpu->displays; other; other = other->next) { + if (other->screen != screen) continue; + offset_display(other, x_offset, y_offset, 1); + } + + /* Recalculate the layout */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + + /* Report back result of move */ + if (ctk_object->modified_callback && + (modified || + x != screen->cur_metamode->edim[X] || + y != screen->cur_metamode->edim[Y])) { + ctk_object->modified_callback + (ctk_object->layout, ctk_object->modified_callback_data); + } + } + break; + + case CONF_ADJ_RELATIVE: + + /* Fall Through */ + screen->x_offset = x; + screen->y_offset = y; + + default: + /* Other relative positioning */ + + /* XXX Need to validate cases where displays are + * positioned relative to each other in a + * circular setup + * + * eg. CRT-0 left of CRT-1 + * CRT-1 clones CRT-0 <- Shouldn't allow this + * + * also: + * + * CRT-0 left of CRT-1 + * CRT-1 left of CRT-2 + * CRT-2 clones CRT-0 ... Eep! + */ + + /* Recalculate the layout */ + calc_layout(layout); + offset_layout(layout, -layout->dim[X], -layout->dim[Y], 1); + recenter_layout(layout); + sync_scaling(ctk_object); + sync_modify(ctk_object); + break; + } + + + /* Redraw the layout and reset the foreground color */ + if (draw) { + draw_layout(ctk_object); + + gdk_gc_set_values + (ctk_object->drawing_area->style->fg_gc[GTK_WIDGET_STATE(ctk_object->drawing_area)], + &old_gc_values, GDK_GC_FOREGROUND); + + do_swap(ctk_object); + } + +} /* ctk_display_layout_set_screen_position() */ + + + +/** ctk_display_layout_set_advanced_mode() *************************** + * + * Enables/Disables the user's ability to modify advanced layout + * bells and whisles. + * + * In advanced mode the user has access to: + * + * - Per-display panning. + * - Modeline timing modifications. (Add/Delete) + * - Multiple metamodes. (Add/Delete) + * + * + * In basic mode: + * + * - User can only modify the current metamode. + * + * + **/ + +void ctk_display_layout_set_advanced_mode(CtkDisplayLayout *ctk_object, + int advanced_mode) +{ + ctk_object->advanced_mode = advanced_mode; + +} /* ctk_display_layout_set_allow_panning() */ + + + +/** expose_event_callback() ****************************************** + * + * Handles expose events. + * + **/ + +static gboolean +expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + CtkDisplayLayout *ctk_object = CTK_DISPLAY_LAYOUT(data); + + + if (event->count) { + return TRUE; + } + + /* Redraw the layout */ + ctk_display_layout_redraw(ctk_object); + + return TRUE; + +} /* expose_event_callback() */ + + + +/** configure_event_callback() *************************************** + * + * Handles configure events. + * + **/ + +static gboolean +configure_event_callback(GtkWidget *widget, GdkEventConfigure *event, + gpointer data) +{ + CtkDisplayLayout *ctk_object = CTK_DISPLAY_LAYOUT(data); + int width = widget->allocation.width; + int height = widget->allocation.height; + + ctk_object->width = width; + ctk_object->height = height; + ctk_object->img_dim[X] = LAYOUT_IMG_OFFSET + LAYOUT_IMG_BORDER_PADDING; + ctk_object->img_dim[Y] = LAYOUT_IMG_OFFSET + LAYOUT_IMG_BORDER_PADDING; + ctk_object->img_dim[W] = width -2*(ctk_object->img_dim[X]); + ctk_object->img_dim[H] = height -2*(ctk_object->img_dim[Y]); + + sync_scaling(ctk_object); + + ctk_object->pixmap = gdk_pixmap_new(widget->window, width, height, -1); + + return TRUE; + +} /* configure_event_callback() */ + + + +/** motion_event_callback() ****************************************** + * + * Handles mouse motion events. + * + **/ + +static gboolean +motion_event_callback(GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + CtkDisplayLayout *ctk_object = CTK_DISPLAY_LAYOUT(data); + GdkGCValues old_gc_values; + + static int init = 1; + static int __modify_panning; + + if (init) { + init = 0; + __modify_panning = (event->state & ShiftMask)?1:0; + } + + + if (ctk_object->last_mouse_x == event->x && + ctk_object->last_mouse_y == event->y) { + return TRUE; + } + + + /* Mouse moved, allow user to reselect the current display */ + ctk_object->select_next = 0; + + + /* Backup the foreground color */ + gdk_gc_get_values(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &old_gc_values); + + + /* Modify screen layout */ + if (ctk_object->button1 && !ctk_object->clicked_outside) { + int modified = 0; + int delta_x = + (event->x - ctk_object->last_mouse_x) / ctk_object->scale; + int delta_y = + (event->y - ctk_object->last_mouse_y) / ctk_object->scale; + + + clear_layout(ctk_object); + + /* Swap between panning and moving */ + if (__modify_panning != (event->state & ShiftMask)?1:0) { + __modify_panning = (event->state & ShiftMask)?1:0; + sync_modify(ctk_object); + } + if (!(event->state & ShiftMask) || !ctk_object->advanced_mode) { + modified = move_selected(ctk_object, delta_x, delta_y, 1); + } else { + modified = pan_selected(ctk_object, delta_x, delta_y, 1); + } + + if (modified && ctk_object->modified_callback) { + ctk_object->modified_callback(ctk_object->layout, + ctk_object->modified_callback_data); + } + + draw_layout(ctk_object); + + + + /* Update the tooltip under the mouse */ + } else { + char *tip = + get_display_tooltip_under_mouse(ctk_object, event->x, event->y); + + if (tip) { + gtk_tooltips_set_tip(ctk_object->tooltip_group, + ctk_object->tooltip_area, + tip, NULL); + + gtk_tooltips_force_window(ctk_object->tooltip_group); + g_free(tip); + } + } + + + ctk_object->last_mouse_x = event->x; + ctk_object->last_mouse_y = event->y; + + + /* Reset the foreground color */ + gdk_gc_set_values(widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + &old_gc_values, + GDK_GC_FOREGROUND); + + + /* Refresh GUI */ + do_swap(ctk_object); + + return TRUE; + +} /* motion_event_callback() */ + + + +/** button_press_event_callback() ************************************ + * + * Handles mouse button press events. + * + **/ + +static gboolean +button_press_event_callback(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + CtkDisplayLayout *ctk_object = CTK_DISPLAY_LAYOUT(data); + nvDisplayPtr last_selected; /* Last display selected */ + nvDisplayPtr new_selected; + + /* Scale and offset x & y so they reside in the clickable area */ + int x = (event->x -ctk_object->img_dim[X]) / ctk_object->scale; + int y = (event->y -ctk_object->img_dim[Y]) / ctk_object->scale; + + static Time time = 0; + + + ctk_object->last_mouse_x = event->x; + ctk_object->last_mouse_y = event->y; + + + switch (event->button) { + + /* Select a display device */ + case Button1: + ctk_object->button1 = 1; + last_selected = get_selected(ctk_object); + + + /* Do the click */ + click_layout(ctk_object, x, y); + + new_selected = get_selected(ctk_object); + + /* If the user just clicked on the currently selected display, + * the next time they click here, we should instead select + * the next display in the Z order. + */ + ctk_object->select_next = + (last_selected == new_selected)?1:0; + + if (ctk_object->selected_callback) { + ctk_object->selected_callback(ctk_object->layout, + ctk_object->selected_callback_data); + } + + if (last_selected != new_selected) { + /* Selected new display - Redraw */ + time = event->time; + + } else if (new_selected && time && (event->time - time < 500)) { + /* Double clicked on display - XXX Could flash display here */ + time = 0; + + } else { + /* Selected same display - Do noting */ + time = event->time; + } + + + /* Redraw everything */ + draw_all(ctk_object); + break; + + default: + break; + } + + + /* Refresh GUI */ + do_swap(ctk_object); + + return TRUE; + +} /* button_press_event_callback() */ + + + +/** button_release_event_callback() ********************************** + * + * Handles mouse button release events. + * + **/ + +static gboolean +button_release_event_callback(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + CtkDisplayLayout *ctk_object = CTK_DISPLAY_LAYOUT(data); + + + switch (event->button) { + + case Button1: + ctk_object->button1 = 0; + break; + + case Button2: + ctk_object->button2 = 0; + break; + + case Button3: + ctk_object->button3 = 0; + break; + + default: + break; + } + + + /* Refresh GUI */ + do_swap(ctk_object); + + return TRUE; + +} /* button_release_event_callback() */ diff --git a/src/gtk+-2.x/ctkdisplaylayout.h b/src/gtk+-2.x/ctkdisplaylayout.h new file mode 100644 index 0000000..8b0da25 --- /dev/null +++ b/src/gtk+-2.x/ctkdisplaylayout.h @@ -0,0 +1,457 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_DISPLAYLAYOUT_H__ +#define __CTK_DISPLAYLAYOUT_H__ + +#include "ctkevent.h" +#include "ctkconfig.h" + +#include "XF86Config-parser/xf86Parser.h" + + +G_BEGIN_DECLS + +#define CTK_TYPE_DISPLAY_LAYOUT (ctk_display_layout_get_type()) + +#define CTK_DISPLAY_LAYOUT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_DISPLAY_LAYOUT, \ + CtkDisplayLayout)) + +#define CTK_DISPLAY_LAYOUT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_DISPLAY_LAYOUT, \ + CtkDisplayLayoutClass)) + +#define CTK_IS_DISPLAY_LAYOUT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_DISPLAY_LAYOUT)) + +#define CTK_IS_DISPLAY_LAYOUT_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_DISPLAY_LAYOUT)) + +#define CTK_DISPLAY_LAYOUT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_DISPLAY_LAYOUT, \ + CtkDisplayLayoutClass)) + +#define CTK_DISPLAY_LAYOUT_TOOLTIP_WIDGET(obj) \ + ((CTK_SCALE(obj))->tooltip_widget) + + + +/* Maximums */ +#define MAX_DEVICES 8 /* Max number of GPUs */ + + +/* Rectangle/Dim data positions */ +#define LEFT 0 +#define TOP 1 +#define WIDTH 2 +#define HEIGHT 3 +#define X LEFT +#define Y TOP +#define W WIDTH +#define H HEIGHT + + +/* XF86VIDMODE */ +#define V_PHSYNC 0x0001 +#define V_NHSYNC 0x0002 +#define V_PVSYNC 0x0004 +#define V_NVSYNC 0x0008 +#define V_INTERLACE 0x0010 +#define V_DBLSCAN 0x0020 +#define V_CSYNC 0x0040 +#define V_PCSYNC 0x0080 +#define V_NCSYNC 0x0100 +#define V_HSKEW 0x0200 /* hskew provided */ +#define V_BCAST 0x0400 +#define V_CUSTOM 0x0800 /* timing numbers customized by editor */ +#define V_VSCAN 0x1000 + + +/* NV-CONTROL modeline sources */ +#define MODELINE_SOURCE_XSERVER 0x001 +#define MODELINE_SOURCE_XCONFIG 0x002 +#define MODELINE_SOURCE_BUILTIN 0x004 +#define MODELINE_SOURCE_VESA 0x008 +#define MODELINE_SOURCE_EDID 0x010 +#define MODELINE_SOURCE_NVCONTROL 0x020 + +#define MODELINE_SOURCE_USER \ + ((MODELINE_SOURCE_XCONFIG)|(MODELINE_SOURCE_NVCONTROL)) + + +/* NV-CONTROL metamode sources */ +#define METAMODE_SOURCE_XCONFIG 0x001 +#define METAMODE_SOURCE_IMPLICIT 0x002 +#define METAMODE_SOURCE_NVCONTROL 0x004 + +#define METAMODE_SOURCE_USER \ + ((METAMODE_SOURCE_XCONFIG)|(METAMODE_SOURCE_NVCONTROL)) + + + + +/*** M A C R O S *************************************************************/ + + +#define NV_MIN(A, B) ((A)<(B)?(A):(B)) +#define NV_MAX(A, B) ((A)>(B)?(A):(B)) + + +/* Determines if the mode is the nvidia-auto-select mode. */ +#define IS_NVIDIA_DEFAULT_MODE(m) \ +(!strcmp(( m )->data.identifier, "nvidia-auto-select")) + + +/* Calculates the vertical refresh rate of the modeline in Hz */ +#define GET_MODELINE_REFRESH_RATE(m) \ +(((double)((m)->data.clock) * 1000) / \ + ((double)((m)->data.htotal) * (double)((m)->data.vtotal))) + + +/* Calculates the horizontal refresh rate (sync) of the modeline in kHz */ +#define GET_MODELINE_HSYNC(m) \ +(((double)((m)->data.clock)) / (2.0f * (double)((m)->data.htotal))) + + + + +/*** T Y P E D E F I N I T I O N S *****************************************/ + + +typedef struct nvModeLineRec { + struct nvModeLineRec *next; + + XConfigModeLineRec data; /* Modeline information */ + + /* Extra information */ + unsigned int source; + char *xconfig_name; + +} nvModeLine, *nvModeLinePtr; + + + +/* Mode (A particular configuration for a display within an X Screen) */ +typedef struct nvModeRec { + struct nvModeRec *next; + + /* Defines a single mode for a dispay device as part of an X Screen's + * metamode. + * + * "WxH_Hz +x+y @WxH" + * + * "modeline_reference_name +offset @panning" + */ + + struct nvDisplayRec *display; /* Display device mode belongs to */ + struct nvMetaModeRec *metamode; /* Metamode the mode is in */ + struct nvModeLineRec *modeline; /* Modeline this mode references */ + int dummy; /* Dummy mode, don't print out */ + + int dim[4]; /* Viewport (absolute) */ + int pan[4]; /* Panning Domain (absolute) */ + + int position_type; /* Relative, Absolute, etc. */ + struct nvDisplayRec *relative_to; /* Display Relative/RightOf etc */ + +} nvMode, *nvModePtr; + + + +/* Display Device (CRT, DFP, TV, Projector ...) */ +typedef struct nvDisplayRec { + struct nvDisplayRec *next; + XConfigMonitorPtr conf_monitor; + + struct nvGpuRec *gpu; /* GPU the display belongs to */ + struct nvScreenRec *screen; /* X Screen the display is tied to */ + + unsigned int device_mask; /* Bit mask to identify the display */ + char *name; /* Display name (from NV-CONTROL) */ + + nvModeLinePtr modelines; /* Modelines validated by X */ + int num_modelines; + + nvModePtr modes; /* List of modes this display uses */ + int num_modes; + nvModePtr cur_mode; /* Current mode display uses */ + +} nvDisplay, *nvDisplayPtr; + + + +/* MetaMode (A particular configuration for an X Screen) */ +typedef struct nvMetaModeRec { + struct nvMetaModeRec *next; + + int id; /* Magic id */ + int source; /* Source of the metamode */ + Bool switchable; /* Can the metamode be accessed through Ctrl Alt +- */ + + // Used for drawing metamode boxes + int dim[4]; /* Bounding box of all modes */ + + // Used for applying and generating metamodes (effective dimensions) + int edim[4]; /* Bounding box of all non-NULL modes */ + + char *string; /* Temp string used for modifying the metamode list */ + +} nvMetaMode, *nvMetaModePtr; + + + +/* X Screen */ +typedef struct nvScreenRec { + struct nvScreenRec *next; + XConfigScreenPtr conf_screen; + XConfigDevicePtr conf_device; + + /* An X Screen may have one or more displays connected to it + * if TwinView is on. + * + * Fathers all displays (and their modes). From this + * Structure a metamodes string can be generated: + * + * "AAA,BBB,CCC ; DDD,EEE,FFF ; GGG,HHH,III" + */ + + NvCtrlAttributeHandle *handle; /* NV-CONTROL handle to X Screen */ + CtkEvent *ctk_event; + int scrnum; + + struct nvGpuRec *gpu; /* GPU driving this X screen */ + + int depth; /* Depth of the screen */ + + unsigned int displays_mask; /* Display devices on this X Screen */ + int num_displays; /* # of displays using this screen */ + + nvMetaModePtr metamodes; /* List of metamodes */ + int num_metamodes; /* # modes per display device */ + nvMetaModePtr cur_metamode; /* Current metamode to display */ + int cur_metamode_idx; /* Current metamode to display */ + + // Used for generating metamode strings. + int dim[4]; /* Bounding box of all metamodes (Absolute coords) */ + + int position_type; /* Relative, Absolute, etc. */ + struct nvScreenRec *relative_to; /* Screen Relative/RightOf etc */ + int x_offset; /* Offsets for relative positioning */ + int y_offset; + +} nvScreen, *nvScreenPtr; + + + +/* GPU (Device) */ +typedef struct nvGpuRec { + struct nvGpuRec *next; + + NvCtrlAttributeHandle *handle; /* NV-CONTROL handle to GPU */ + CtkEvent *ctk_event; + + struct nvLayoutRec *layout; /* Layout this GPU belongs to */ + + int max_width; + int max_height; + int max_displays; + + char *name; /* Name of the GPU */ + + unsigned int connected_displays; /* Bitmask of connected displays */ + + int pci_bus; + int pci_device; + int pci_func; + + nvScreenPtr screens; /* List of screens this GPU drives */ + int num_screens; + + nvDisplayPtr displays; /* List of displays attached to screen */ + int num_displays; + +} nvGpu, *nvGpuPtr; + + + +/* Layout */ +typedef struct nvLayoutRec { + XConfigLayoutPtr conf_layout; + char *filename; + + NvCtrlAttributeHandle *handle; + + nvGpuPtr gpus; /* List of GPUs in the layout */ + int num_gpus; + + // Used for drawing the layout. + int dim[4]; /* Bounding box of All X Screens (Absolute coords) */ + + int xinerama_enabled; + +} nvLayout, *nvLayoutPtr; + + + +typedef void (* ctk_display_layout_selected_callback) (nvLayoutPtr, void *); +typedef void (* ctk_display_layout_modified_callback) (nvLayoutPtr, void *); + + + +typedef struct _CtkDisplayLayout +{ + GtkVBox parent; + + NvCtrlAttributeHandle *handle; + CtkConfig *ctk_config; + + GtkWidget *drawing_area; /* Drawing area */ + GtkWidget *tooltip_area; /* Tooltip area */ + GtkTooltips *tooltip_group; /* Tooltip group */ + + /* Layout configuration */ + nvLayoutPtr layout; + + /* Double buffering of layout image */ + GdkPixmap *pixmap; + int need_swap; + + /* Image information */ + int width; /* Real widget dimensions */ + int height; + int img_dim[4]; /* Dimensions used to draw in */ + float scale; + + /* Colors */ + GdkColor *color_palettes; /* Colors to use to display screens */ + GdkColor fg_color; + GdkColor bg_color; + GdkColor select_color; + + /* Pango layout for strings in layout image */ + + PangoLayout *pango_layout; + + /* Display Z-Order */ + nvDisplayPtr *Zorder; /* Z ordering of dispays in layout */ + int Zcount; /* Number of displays in Z order list */ + int Zselected; /* Is first item selected? */ + + /* Settings */ + int snap_strength; + int advanced_mode; /* Allow advanced layout modifications: */ + /* - panning */ + /* - multiple modes */ + + /* State */ + int select_next; /* On click, select next screen in Z order. */ + int modify_dim[4]; /* Used to snap when moving/panning */ + int clicked_outside; /* User clicked outside displays, don't move */ + + int button1; + int button2; + int button3; + int last_mouse_x; + int last_mouse_y; + + ctk_display_layout_selected_callback selected_callback; + void *selected_callback_data; + ctk_display_layout_modified_callback modified_callback; + void *modified_callback_data; + +} CtkDisplayLayout; + + +typedef struct _CtkDisplayLayoutClass +{ + GtkVBoxClass parent_class; +} CtkDisplayLayoutClass; + + + +GType ctk_display_layout_get_type (void) G_GNUC_CONST; + +GtkWidget* ctk_display_layout_new (NvCtrlAttributeHandle *, + CtkConfig *, + nvLayoutPtr, /* Layout to display */ + int, /* Width of image */ + int, /* Height of image */ + ctk_display_layout_selected_callback, + void *selected_callback_data, + ctk_display_layout_modified_callback, + void *modified_callback_data + ); + +void ctk_display_layout_redraw (CtkDisplayLayout *); + + +void ctk_display_layout_set_layout (CtkDisplayLayout *, nvLayoutPtr); + + +nvDisplayPtr ctk_display_layout_get_selected_display (CtkDisplayLayout *); +nvScreenPtr ctk_display_layout_get_selected_screen (CtkDisplayLayout *); +nvGpuPtr ctk_display_layout_get_selected_gpu (CtkDisplayLayout *); + + +void ctk_display_layout_set_mode_modeline (CtkDisplayLayout *, + nvModePtr mode, + nvModeLinePtr modeline); + +void ctk_display_layout_set_display_position (CtkDisplayLayout *ctk_object, + nvDisplayPtr display, + int position_type, + nvDisplayPtr relative_to, + int x, int y); +void ctk_display_layout_set_display_panning (CtkDisplayLayout *ctk_object, + nvDisplayPtr display, + int width, int height); + +void ctk_display_layout_update_display_count (CtkDisplayLayout *, + nvDisplayPtr); + +void ctk_display_layout_set_screen_depth (CtkDisplayLayout *ctk_object, + nvScreenPtr screen, int depth); +void ctk_display_layout_set_screen_position (CtkDisplayLayout *ctk_object, + nvScreenPtr screen, + int position_type, + nvScreenPtr relative_to, + int x, int y); +void ctk_display_layout_set_screen_metamode (CtkDisplayLayout *, + nvScreenPtr screen, + int new_mode); +void ctk_display_layout_add_screen_metamode (CtkDisplayLayout *, nvScreenPtr); +void ctk_display_layout_delete_screen_metamode (CtkDisplayLayout *, + nvScreenPtr, + int metamode_idx); + + +void ctk_display_layout_set_advanced_mode (CtkDisplayLayout *ctk_object, + int advanced_mode); + + + +G_END_DECLS + +#endif /* __CTK_DISPLAYLAYOUT_H__ */ diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c index 30b77ff..4103436 100644 --- a/src/gtk+-2.x/ctkevent.c +++ b/src/gtk+-2.x/ctkevent.c @@ -219,10 +219,21 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_SIGNAL(NV_CTRL_XV_SYNC_TO_DISPLAY); MAKE_SIGNAL(NV_CTRL_GVO_OVERRIDE_HW_CSC); MAKE_SIGNAL(NV_CTRL_GVO_COMPOSITE_TERMINATION); + MAKE_SIGNAL(NV_CTRL_ASSOCIATED_DISPLAY_DEVICES); MAKE_SIGNAL(NV_CTRL_FRAMELOCK_SLAVES); MAKE_SIGNAL(NV_CTRL_FRAMELOCK_MASTERABLE); MAKE_SIGNAL(NV_CTRL_PROBE_DISPLAYS); MAKE_SIGNAL(NV_CTRL_REFRESH_RATE); + MAKE_SIGNAL(NV_CTRL_INITIAL_PIXMAP_PLACEMENT); + MAKE_SIGNAL(NV_CTRL_PCI_BUS); + MAKE_SIGNAL(NV_CTRL_PCI_DEVICE); + MAKE_SIGNAL(NV_CTRL_PCI_FUNCTION); + MAKE_SIGNAL(NV_CTRL_FRAMELOCK_FPGA_REVISION); + MAKE_SIGNAL(NV_CTRL_MAX_SCREEN_WIDTH); + MAKE_SIGNAL(NV_CTRL_MAX_SCREEN_HEIGHT); + MAKE_SIGNAL(NV_CTRL_MAX_DISPLAYS); + MAKE_SIGNAL(NV_CTRL_DYNAMIC_TWINVIEW); + MAKE_SIGNAL(NV_CTRL_MULTIGPU_DISPLAY_OWNER); #undef MAKE_SIGNAL @@ -233,7 +244,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) * knows about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_REFRESH_RATE +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_MULTIGPU_DISPLAY_OWNER #warning "There are attributes that do not emit signals!" #endif @@ -347,7 +358,7 @@ static void ctk_event_register_source(CtkEvent *ctk_event) -GtkObject *ctk_event_new (NvCtrlAttributeHandle *handle) +GtkObject *ctk_event_new(NvCtrlAttributeHandle *handle) { GObject *object; CtkEvent *ctk_event; @@ -368,6 +379,7 @@ GtkObject *ctk_event_new (NvCtrlAttributeHandle *handle) } /* ctk_event_new() */ + static gboolean ctk_event_prepare(GSource *source, gint *timeout) { *timeout = -1; @@ -380,6 +392,8 @@ static gboolean ctk_event_prepare(GSource *source, gint *timeout) return FALSE; } + + static gboolean ctk_event_check(GSource *source) { CtkEventSource *event_source = (CtkEventSource *) source; @@ -393,6 +407,26 @@ static gboolean ctk_event_check(GSource *source) } + +static int get_screen_of_root(Display *dpy, Window root) +{ + int screen = -1; + + /* Find the screen the window belongs to */ + screen = XScreenCount(dpy); + + while (screen > 0) { + screen--; + if (root == RootWindow(dpy, screen)) { + break; + } + } + + return screen; +} + + + #define CTK_EVENT_BROADCAST(ES, SIG, PTR, TYPE, ID) \ do { \ CtkEventNode *e = (ES)->ctk_events; \ @@ -494,16 +528,8 @@ static gboolean ctk_event_dispatch(GSource *source, int screen; /* Find the screen the window belongs to */ - screen = XScreenCount(xrandrevent->display); - screen--; - while (screen > 0) { - if (xrandrevent->root == - RootWindow(xrandrevent->display, screen)) { - break; - } - screen--; - } - if (screen > 0) { + screen = get_screen_of_root(xrandrevent->display, xrandrevent->root); + if (screen >= 0) { CTK_EVENT_BROADCAST(event_source, signal_RRScreenChangeNotify, &event, @@ -515,3 +541,44 @@ static gboolean ctk_event_dispatch(GSource *source, return TRUE; } /* ctk_event_dispatch() */ + + + +/* ctk_event_emit() - Emits signal(s) on a registered ctk_event object. + * This function is primarly used to simulate NV-CONTROL events such + * that various parts of nvidia-settings can communicate (internally) + */ +void ctk_event_emit(CtkEvent *ctk_event, + unsigned int mask, int attrib, int value) +{ + CtkEventStruct event; + CtkEventSource *source; + Display *dpy = NvCtrlGetDisplayPtr(ctk_event->handle); + + + if (attrib > NV_CTRL_LAST_ATTRIBUTE) return; + + + /* Find the event source */ + source = event_sources; + while (source) { + if (source->dpy == dpy) { + break; + } + source = source->next; + } + if (!source) return; + + + /* Broadcast event to all relavent ctk_event objects */ + event.attribute = attrib; + event.value = value; + event.display_mask = mask; + + CTK_EVENT_BROADCAST(source, + signals[attrib], + &event, + NvCtrlGetTargetType(ctk_event->handle), + NvCtrlGetTargetId(ctk_event->handle)); + +} /* ctk_event_emit() */ diff --git a/src/gtk+-2.x/ctkevent.h b/src/gtk+-2.x/ctkevent.h index 45d83a7..9eb77d4 100644 --- a/src/gtk+-2.x/ctkevent.h +++ b/src/gtk+-2.x/ctkevent.h @@ -74,6 +74,9 @@ struct _CtkEventStruct GType ctk_event_get_type (void) G_GNUC_CONST; GtkObject* ctk_event_new (NvCtrlAttributeHandle*); +void ctk_event_emit(CtkEvent *ctk_event, + unsigned int mask, int attrib, int value); + #define CTK_EVENT_NAME(x) ("CTK_EVENT_" #x) diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c index 4f013d7..2c7fca9 100644 --- a/src/gtk+-2.x/ctkframelock.c +++ b/src/gtk+-2.x/ctkframelock.c @@ -172,9 +172,6 @@ struct _nvDisplayDataRec { GtkWidget *rate_text; guint rate; - GtkWidget *timing_label; - GtkWidget *timing_hbox; /* LED */ - GtkWidget *stereo_label; GtkWidget *stereo_hbox; /* LED */ }; @@ -187,6 +184,9 @@ struct _nvGPUDataRec { guint clients_mask; gboolean enabled; /* Sync enabled */ + GtkWidget *timing_label; + GtkWidget *timing_hbox; /* LED */ + /* Signal Handler IDs */ gulong signal_ids[NUM_GPU_SIGNALS]; @@ -221,7 +221,10 @@ struct _nvFrameLockDataRec { GtkWidget *port1_label; GtkWidget *port1_hbox; /* IMAGE */ guint port1_ethernet_error; - + + GtkWidget *revision_label; + GtkWidget *revision_text; + GtkWidget *extra_info_hbox; }; @@ -1360,6 +1363,7 @@ static void do_select_gpu_data(nvGPUDataPtr data, gint select) return; } SELECT_WIDGET(data->label, select); + SELECT_WIDGET(data->timing_label, select); } @@ -1380,7 +1384,6 @@ static void do_select_display_data(nvDisplayDataPtr data, gint select) SELECT_WIDGET(data->client_label, select); SELECT_WIDGET(data->rate_label, select); SELECT_WIDGET(data->rate_text, select); - SELECT_WIDGET(data->timing_label, select); SELECT_WIDGET(data->stereo_label, select); } @@ -1924,6 +1927,15 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data) gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), data->delay_text, FALSE, FALSE, 0); + vseparator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), vseparator, + FALSE, FALSE, 0); + + gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), data->revision_label, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), data->revision_text, + FALSE, FALSE, 0); + return entry; } @@ -1949,6 +1961,21 @@ static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data) gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label, FALSE, FALSE, 5); + { + GtkWidget *frame; + GtkWidget *hbox; + + hbox = gtk_hbox_new(FALSE, 5); + + frame = gtk_frame_new(NULL); + gtk_box_pack_end(GTK_BOX(entry->data_hbox), frame, FALSE, FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_container_add(GTK_CONTAINER(frame), hbox); + + gtk_box_pack_start(GTK_BOX(hbox), data->timing_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->timing_hbox, FALSE, FALSE, 0); + } + return entry; } @@ -2006,12 +2033,6 @@ static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data) vseparator = gtk_vseparator_new(); gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), data->timing_label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), data->timing_hbox, FALSE, FALSE, 0); - - vseparator = gtk_vseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), data->stereo_label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), data->stereo_hbox, FALSE, FALSE, 0); } @@ -3042,7 +3063,43 @@ void list_entry_update_framelock_status(CtkFramelock *ctk_framelock, void list_entry_update_gpu_status(CtkFramelock *ctk_framelock, nvListEntryPtr entry) { - /* Do nothing */ + nvGPUDataPtr data = (nvGPUDataPtr)(entry->data); + gboolean framelock_enabled; + gboolean has_server; + gboolean has_client; + gboolean use_house_sync; + gint house = 0; + + framelock_enabled = ctk_framelock->framelock_enabled; + + use_house_sync = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync)); + + if (entry->parent && entry->parent->data) { + nvFrameLockDataPtr framelock_data = + (nvFrameLockDataPtr)(entry->parent->data); + + NvCtrlGetAttribute(framelock_data->handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, + &house); + } + + has_client = data->clients_mask; + has_server = data->server_mask; + + /* Check Timing Sync */ + if (!framelock_enabled || + (!has_server && !has_client) || + (has_server && (use_house_sync || !house))) { + gtk_widget_set_sensitive(data->timing_label, FALSE); + update_image(data->timing_hbox, ctk_framelock->led_grey); + } else { + gint timing; + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_TIMING, &timing); + gtk_widget_set_sensitive(data->timing_label, TRUE); + update_image(data->timing_hbox, + timing ? ctk_framelock->led_green : + ctk_framelock->led_red); + } } @@ -3078,26 +3135,6 @@ void list_entry_update_display_status(CtkFramelock *ctk_framelock, gpu_is_server = (gpu_server_entry && (gpu_server_entry == entry->parent)); - /* Check Timing Sync. Due to a current restriction, timing information - * is unavailable on client display devices that are driven by the same - * gpu that is driving the server display device while "use house sync" - * is off (gpu is using the internal timings of the server display - * device). - */ - if (!framelock_enabled || - (!is_server && !is_client) || - (gpu_is_server && !use_house_sync)) { - gtk_widget_set_sensitive(data->timing_label, FALSE); - update_image(data->timing_hbox, ctk_framelock->led_grey); - } else { - gint timing; - NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_TIMING, &timing); - gtk_widget_set_sensitive(data->timing_label, TRUE); - update_image(data->timing_hbox, - timing ? ctk_framelock->led_green : - ctk_framelock->led_red); - } - /* Check Stereo Sync. If frame lock is disabled or this display device * is neither a client/server or the display device is a server and the * GPU driving it is not using the house sync signal, gray out the LED. @@ -3775,7 +3812,7 @@ GtkWidget* ctk_framelock_new(NvCtrlAttributeHandle *handle, ret = NvCtrlQueryTargetCount(handle, NV_CTRL_TARGET_TYPE_FRAMELOCK, - &num_framelocks); + (int *)&num_framelocks); if (ret != NvCtrlSuccess) return NULL; if (!num_framelocks) return NULL; @@ -4297,7 +4334,7 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock, /* Query list of devices on this GPU. */ ret = NvCtrlGetAttribute(gpu_data->handle, NV_CTRL_ENABLED_DISPLAYS, - &enabled_displays); + (int *)&enabled_displays); if (ret != NvCtrlSuccess || !enabled_displays) { goto fail; } @@ -4305,7 +4342,7 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock, /* Query master device */ ret = NvCtrlGetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_MASTER, - &master_mask); + (int *)&master_mask); if (ret != NvCtrlSuccess) { goto fail; } @@ -4313,7 +4350,7 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock, /* Query slave devices */ ret = NvCtrlGetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SLAVES, - &slaves_mask); + (int *)&slaves_mask); if (ret != NvCtrlSuccess) { goto fail; } @@ -4370,7 +4407,7 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock, ret = NvCtrlGetDisplayAttribute(gpu_data->handle, display_mask, NV_CTRL_REFRESH_RATE, - &(display_data->rate)); + (int *)&(display_data->rate)); if (ret != NvCtrlSuccess) { goto fail; } @@ -4393,9 +4430,6 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock, fvalue = ((float)(display_data->rate)) / 100.0f; snprintf(str, 32, "%.2f Hz", fvalue); display_data->rate_text = gtk_label_new(str); - - display_data->timing_label = gtk_label_new("Timing:"); - display_data->timing_hbox = gtk_hbox_new(FALSE, 0); display_data->stereo_label = gtk_label_new("Stereo:"); display_data->stereo_hbox = gtk_hbox_new(FALSE, 0); @@ -4536,6 +4570,9 @@ static unsigned int add_gpu_devices(CtkFramelock *ctk_framelock, NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); gpu_data->label = gtk_label_new(""); + gpu_data->timing_label = gtk_label_new("Timing:"); + gpu_data->timing_hbox = gtk_hbox_new(FALSE, 0); + /* Create the GPU list entry */ entry = list_entry_new_with_gpu(gpu_data); @@ -4610,32 +4647,10 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock, /* Get number of G-Sync devices on this server */ - /* XXX If we check for FRAMELOCK_SUPPORTED here, we - * might get a false negative since another - * X screen on the same server could support - * frame lock. - */ - - /* does this NV-CONTROL handle support frame lock? */ - /* - NvCtrlGetAttribute(h, NV_CTRL_FRAMELOCK, &value); - if (value != NV_CTRL_FRAMELOCK_SUPPORTED) { - if (error_dialog) { - error_msg(ctk_framelock, "<span weight=\"bold\" " - "size=\"larger\">Unable " - "to add X screen to frame lock group</span>\n\n" - "This X Screen does not support frame lock."); - } else { - nv_error_msg("Unable to add X screen to frame lock group; " - "this X Screen does not support frame lock."); - } - NvCtrlAttributeClose(h); - return NULL; - }*/ ret = NvCtrlQueryTargetCount(handle, NV_CTRL_TARGET_TYPE_FRAMELOCK, - &num_framelocks); + (int *)&num_framelocks); if (ret != NvCtrlSuccess) { goto fail; } @@ -4643,6 +4658,8 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock, /* Add frame lock devices found */ for (framelock_id = 0; framelock_id < num_framelocks; framelock_id++) { int gpus_added = 0; + int val; + char *revision_str = NULL; /* Create the frame lock data structure */ framelock_data = @@ -4658,6 +4675,17 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock, framelock_id, NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + /* Get the framelock revision information */ + + ret = NvCtrlGetAttribute(framelock_data->handle, + NV_CTRL_FRAMELOCK_FPGA_REVISION, + &val); + if (ret != NvCtrlSuccess) { + goto fail; + } + revision_str = g_strdup_printf("%d", val); + + framelock_data->label = gtk_label_new(""); framelock_data->receiving_label = gtk_label_new("Receiving:"); @@ -4678,6 +4706,10 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock, framelock_data->port1_label = gtk_label_new("Port 1:"); framelock_data->port1_hbox = gtk_hbox_new(FALSE, 0); + framelock_data->revision_label = gtk_label_new("FPGA Revision:"); + framelock_data->revision_text = gtk_label_new(revision_str); + g_free(revision_str); + framelock_data->extra_info_hbox = gtk_hbox_new(FALSE, 5); /* Create the frame lock list entry */ @@ -5114,6 +5146,9 @@ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table) ctk_help_para(b, &i, "GPU Device entries display the GPU name and number " "of a GPU connected to a G-Sync device. Display devices " "driven by the GPU will be listed under this entry."); + ctk_help_para(b, &i, "Timing LED: This indicates that the GPU " + "is synchronized with the incoming timing signal from the " + "G-Sync device"); ctk_help_heading(b, &i, "Display Device Entry Information"); ctk_help_para(b, &i, "Display Device entries display information and " @@ -5123,8 +5158,6 @@ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table) "The following options are available:"); ctk_help_para(b, &i, __server_checkbox_help); ctk_help_para(b, &i, __client_checkbox_help); - ctk_help_para(b, &i, "Timing LED: This indicates that the display device " - "is synchronized with the incoming timing signal."); ctk_help_para(b, &i, "Stereo LED: This indicates whether or not the " "display device is sync'ed to the stereo signal coming from " "the G-Sync device. This LED is only available to display " @@ -5217,10 +5250,12 @@ void ctk_framelock_select(GtkWidget *w) /* Start the frame lock timers */ ctk_config_start_timer(ctk_framelock->ctk_config, - (GSourceFunc) update_framelock_status); + (GSourceFunc) update_framelock_status, + (gpointer) ctk_framelock); ctk_config_start_timer(ctk_framelock->ctk_config, - (GSourceFunc) check_for_ethernet); + (GSourceFunc) check_for_ethernet, + (gpointer) ctk_framelock); } @@ -5238,8 +5273,10 @@ void ctk_framelock_unselect(GtkWidget *w) /* Stop the frame lock timers */ ctk_config_stop_timer(ctk_framelock->ctk_config, - (GSourceFunc) update_framelock_status); + (GSourceFunc) update_framelock_status, + (gpointer) ctk_framelock); ctk_config_stop_timer(ctk_framelock->ctk_config, - (GSourceFunc) check_for_ethernet); + (GSourceFunc) check_for_ethernet, + (gpointer) ctk_framelock); } diff --git a/src/gtk+-2.x/ctkglx.c b/src/gtk+-2.x/ctkglx.c index cd09875..650b625 100644 --- a/src/gtk+-2.x/ctkglx.c +++ b/src/gtk+-2.x/ctkglx.c @@ -33,6 +33,7 @@ #include "glx_banner.h" #include "ctkimage.h" #include "ctkglx.h" +#include "ctkutils.h" #include "ctkconfig.h" #include "ctkhelp.h" @@ -151,32 +152,6 @@ GType ctk_glx_get_type(void) } /* ctk_glx_get_type() */ -static void add_table_row(GtkWidget *table, - const gint row, - const gint value_alignment, - const gchar *name, - const gchar *value) -{ - GtkWidget *label; - - - label = gtk_label_new(name); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.0f); - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, - GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - - label = gtk_label_new(value); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), value_alignment, 0.0f); - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - - gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row + 1, - GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); -} /* add_table_row() */ - - static void dummy_button_signal(GtkWidget *widget, gpointer user_data) { @@ -452,10 +427,10 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle, /* Failure (no GLX) */ fail_glx_not_supported: - label = gtk_label_new("The OpenGL extension 'GLX' is not supported by\n" - "the X server or there was a problem retrieving\n" - "GLX information from the X server." - ); + label = + gtk_label_new("GLX not available: either the GLX extension is not\n" + "available on this X server, or there was a problem\n" + "retrieving GLX information from the X server."); gtk_label_set_selectable(GTK_LABEL(label), TRUE); gtk_container_add(GTK_CONTAINER(ctk_glx), label); @@ -601,9 +576,12 @@ void ctk_glx_probe_info(GtkWidget *widget) table = gtk_table_new(2, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 3); gtk_table_set_col_spacings(GTK_TABLE(table), 15); - add_table_row(table, 0, 0, "Direct Rendering:", direct_rendering); - add_table_row(table, 1, 0, "GLX Extensions:", - glx_extensions?glx_extensions:""); + add_table_row(table, 0, + 0, 0, "Direct Rendering:", + 0, 0, direct_rendering); + add_table_row(table, 1, + 0, 0, "GLX Extensions:", + 0, 0, glx_extensions); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0); @@ -622,12 +600,15 @@ void ctk_glx_probe_info(GtkWidget *widget) table = gtk_table_new(3, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 3); gtk_table_set_col_spacings(GTK_TABLE(table), 15); - add_table_row(table, 0, 0, "Vendor:", - server_vendor?server_vendor:""); - add_table_row(table, 1, 0, "Version:", - server_version?server_version:""); - add_table_row(table, 2, 0, "Extensions:", - server_extensions?server_extensions:""); + add_table_row(table, 0, + 0, 0, "Vendor:", + 0, 0, server_vendor); + add_table_row(table, 1, + 0, 0, "Version:", + 0, 0, server_version); + add_table_row(table, 2, + 0, 0, "Extensions:", + 0, 0, server_extensions); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0); @@ -646,12 +627,15 @@ void ctk_glx_probe_info(GtkWidget *widget) table = gtk_table_new(3, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 3); gtk_table_set_col_spacings(GTK_TABLE(table), 15); - add_table_row(table, 0, 0, "Vendor:", - client_vendor?client_vendor:""); - add_table_row(table, 1, 0, "Version:", - client_version?client_version:""); - add_table_row(table, 2, 0, "Extensions:", - client_extensions?client_extensions:""); + add_table_row(table, 0, + 0, 0, "Vendor:", + 0, 0, client_vendor); + add_table_row(table, 1, + 0, 0, "Version:", + 0, 0, client_version); + add_table_row(table, 2, + 0, 0, "Extensions:", + 0, 0, client_extensions); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0); @@ -671,10 +655,18 @@ void ctk_glx_probe_info(GtkWidget *widget) vbox2 = gtk_vbox_new(FALSE, 0); gtk_table_set_row_spacings(GTK_TABLE(table), 3); gtk_table_set_col_spacings(GTK_TABLE(table), 15); - add_table_row(table, 0, 0, "Vendor:", opengl_vendor); - add_table_row(table, 1, 0, "Renderer:", opengl_renderer); - add_table_row(table, 2, 0, "Version:", opengl_version); - add_table_row(table, 3, 0, "Extensions:", opengl_extensions); + add_table_row(table, 0, + 0, 0, "Vendor:", + 0, 0, opengl_vendor); + add_table_row(table, 1, + 0, 0, "Renderer:", + 0, 0, opengl_renderer); + add_table_row(table, 2, + 0, 0, "Version:", + 0, 0, opengl_version); + add_table_row(table, 3, + 0, 0, "Extensions:", + 0, 0, opengl_extensions); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox2, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0); diff --git a/src/gtk+-2.x/ctkgpu.c b/src/gtk+-2.x/ctkgpu.c new file mode 100644 index 0000000..0a2d7d3 --- /dev/null +++ b/src/gtk+-2.x/ctkgpu.c @@ -0,0 +1,480 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <gtk/gtk.h> +#include "NvCtrlAttributes.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "thermal_banner.h" +#include "ctkimage.h" + +#include "ctkgpu.h" +#include "ctkhelp.h" +#include "ctkutils.h" + + +static void probe_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data); + +GType ctk_gpu_get_type( + void +) +{ + static GType ctk_gpu_type = 0; + + if (!ctk_gpu_type) { + static const GTypeInfo info_ctk_gpu = { + sizeof (CtkGpuClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CtkGpu), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_gpu_type = + g_type_register_static(GTK_TYPE_VBOX, + "CtkGpu", &info_ctk_gpu, 0); + } + + return ctk_gpu_type; +} + + +static gchar *make_display_device_list(NvCtrlAttributeHandle *handle, + unsigned int display_devices) +{ + gchar *displays = NULL; + gchar *type; + gchar *name; + gchar *tmp_str; + unsigned int mask; + ReturnStatus ret; + + + /* List of Display Device connected on GPU */ + + for (mask = 1; mask; mask <<= 1) { + + if (!(mask & display_devices)) continue; + + type = display_device_mask_to_display_device_name(mask); + name = NULL; + + ret = + NvCtrlGetStringDisplayAttribute(handle, + mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &name); + if (ret != NvCtrlSuccess) { + tmp_str = g_strdup_printf("Unknown (%s)", type); + } else { + tmp_str = g_strdup_printf("%s (%s)", name, type); + XFree(name); + } + free(type); + + if (displays) { + name = g_strdup_printf("%s,\n%s", tmp_str, displays); + g_free(displays); + g_free(tmp_str); + } else { + name = tmp_str; + } + displays = name; + } + + if (!displays) { + displays = g_strdup("None"); + } + + return displays; + +} /* make_display_device_list() */ + + + +GtkWidget* ctk_gpu_new( + NvCtrlAttributeHandle *handle, + NvCtrlAttributeHandle **screen_handles, + CtkEvent *ctk_event +) +{ + GObject *object; + CtkGpu *ctk_gpu; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *banner; + GtkWidget *hseparator; + GtkWidget *table; + + char *product_name, *vbios_version, *video_ram, *irq; + gchar *bus_type, *bus_rate, *bus; + int pci_bus; + int pci_device; + int pci_func; + gchar *pci_bus_id; + + gchar *__pci_bus_id_unknown = "?:?:?"; + + int tmp; + ReturnStatus ret; + + gchar *screens; + gchar *displays; + + unsigned int display_devices; + int xinerama_enabled; + int *pData; + int len; + int i; + + + /* + * get the data that we will display below + * + * XXX should be able to update any of this if an attribute + * changes. + */ + + /* NV_CTRL_XINERAMA */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA, &xinerama_enabled); + if (ret != NvCtrlSuccess) { + xinerama_enabled = FALSE; + } + + /* NV_CTRL_STRING_PRODUCT_NAME */ + + ret = NvCtrlGetStringAttribute(handle, NV_CTRL_STRING_PRODUCT_NAME, + &product_name); + if (ret != NvCtrlSuccess) product_name = NULL; + + /* NV_CTRL_BUS_TYPE */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_BUS_TYPE, &tmp); + bus_type = NULL; + if (ret == NvCtrlSuccess) { + if (tmp == NV_CTRL_BUS_TYPE_AGP) bus_type = "AGP"; + else if (tmp == NV_CTRL_BUS_TYPE_PCI) bus_type = "PCI"; + else if (tmp == NV_CTRL_BUS_TYPE_PCI_EXPRESS) bus_type = "PCI Express"; + else if (tmp == NV_CTRL_BUS_TYPE_INTEGRATED) bus_type = "Integrated"; + } + + /* NV_CTRL_BUS_RATE */ + + bus_rate = NULL; + if (tmp == NV_CTRL_BUS_TYPE_AGP || + tmp == NV_CTRL_BUS_TYPE_PCI_EXPRESS) { + ret = NvCtrlGetAttribute(handle, NV_CTRL_BUS_RATE, &tmp); + if (ret == NvCtrlSuccess) { + bus_rate = g_strdup_printf("%dX", tmp); + } + } + + if (bus_rate) { + bus = g_strdup_printf("%s %s", bus_type, bus_rate); + g_free(bus_rate); + } else { + bus = g_strdup(bus_type); + } + + /* NV_CTRL_PCI_BUS & NV_CTRL_PCI_DEVICE & NV__CTRL_PCI_FUNCTION */ + + pci_bus_id = NULL; + ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_BUS, &pci_bus); + if (ret != NvCtrlSuccess) pci_bus_id = __pci_bus_id_unknown; + + ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_DEVICE, &pci_device); + if (ret != NvCtrlSuccess) pci_bus_id = __pci_bus_id_unknown; + + ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_FUNCTION, &pci_func); + if (ret != NvCtrlSuccess) pci_bus_id = __pci_bus_id_unknown; + + if (!pci_bus_id) { + pci_bus_id = g_strdup_printf("%d:%d:%d", + pci_bus, pci_device, pci_func); + } else { + pci_bus_id = g_strdup(__pci_bus_id_unknown); + } + + /* NV_CTRL_STRING_VBIOS_VERSION */ + + ret = NvCtrlGetStringAttribute(handle, NV_CTRL_STRING_VBIOS_VERSION, + &vbios_version); + if (ret != NvCtrlSuccess) vbios_version = NULL; + + /* NV_CTRL_VIDEO_RAM */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_VIDEO_RAM, &tmp); + if (ret != NvCtrlSuccess) { + video_ram = NULL; + } else { + video_ram = g_strdup_printf("%d MB", tmp >> 10); + } + + /* NV_CTRL_IRQ */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_IRQ, &tmp); + if (ret != NvCtrlSuccess) { + irq = NULL; + } else { + irq = g_strdup_printf("%d", tmp); + } + + /* List of X Screens using GPU */ + + if (xinerama_enabled) { + + /* In Xinerama, there is only one logical X screen */ + + screens = g_strdup("Screen 0 (Xinerama)"); + + } else { + gchar *tmp_str; + screens = NULL; + + ret = NvCtrlGetBinaryAttribute(handle, + 0, + NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU, + (unsigned char **)(&pData), + &len); + if (ret == NvCtrlSuccess) { + for (i = 1; i <= pData[0]; i++) { + + if (screens) { + tmp_str = g_strdup_printf("%s,\nScreen %d", + screens, pData[i]); + } else { + tmp_str = g_strdup_printf("Screen %d", pData[i]); + } + g_free(screens); + screens = tmp_str; + } + if (!screens) { + screens = g_strdup("None"); + + } else if (pData[0] > 0) { + + ret = NvCtrlGetAttribute(screen_handles[pData[1]], + NV_CTRL_SHOW_SLI_HUD, + &tmp); + + if (ret == NvCtrlSuccess) { + tmp_str = g_strdup_printf("%s (SLI)", screens); + g_free(screens); + screens = tmp_str; + } + } + } + } + + /* List of Display Device connected on GPU */ + + displays = NULL; + ret = NvCtrlGetAttribute(handle, NV_CTRL_CONNECTED_DISPLAYS, + (int *)&display_devices); + if (ret == NvCtrlSuccess) { + displays = make_display_device_list(handle, display_devices); + } + + /* now, create the object */ + + object = g_object_new(CTK_TYPE_GPU, NULL); + ctk_gpu = CTK_GPU(object); + + /* cache the attribute handle */ + + ctk_gpu->handle = handle; + + /* set container properties of the object */ + + gtk_box_set_spacing(GTK_BOX(ctk_gpu), 10); + + /* banner */ + + banner = ctk_banner_image_new(&thermal_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_gpu), banner, FALSE, FALSE, 0); + + /* + * GPU information: TOP->MIDDLE - LEFT->RIGHT + * + * This displays basic display adatper information, including + * product name, bios version, bus type, video ram and interrupt + * line. + */ + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_gpu), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("Graphics Card Information"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); + + table = gtk_table_new(17, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + add_table_row(table, 0, + 0, 0.5, "Graphics Processor:", + 0, 0.5, product_name); + add_table_row(table, 1, + 0, 0.5, "VBIOS Version:", + 0, 0.5, vbios_version); + add_table_row(table, 2, + 0, 0.5, "Memory:", + 0, 0.5, video_ram); + /* spacing */ + add_table_row(table, 6, + 0, 0.5, "Bus Type:", + 0, 0.5, bus); + add_table_row(table, 7, + 0, 0.5, "Bus ID:", + 0, 0.5, pci_bus_id); + add_table_row(table, 8, + 0, 0.5, "IRQ:", + 0, 0.5, irq); + /* spacing */ + add_table_row(table, 12, + 0, 0, "X Screens:", + 0, 0, screens); + /* spacing */ + ctk_gpu->displays = + add_table_row(table, 16, + 0, 0, "Display Devices:", + 0, 0, displays); + + XFree(product_name); + XFree(vbios_version); + g_free(video_ram); + g_free(bus); + g_free(pci_bus_id); + g_free(irq); + g_free(screens); + g_free(displays); + + gtk_widget_show_all(GTK_WIDGET(object)); + + /* Handle events */ + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_PROBE_DISPLAYS), + G_CALLBACK(probe_displays_received), + (gpointer) ctk_gpu); + + return GTK_WIDGET(object); +} + + +GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *table) +{ + GtkTextIter i; + GtkTextBuffer *b; + + b = gtk_text_buffer_new(table); + + gtk_text_buffer_get_iter_at_offset(b, &i, 0); + + ctk_help_title(b, &i, "Graphics Card Information Help"); + + ctk_help_para(b, &i, "This page in the NVIDIA " + "X Server Control Panel describes basic " + "information about the Graphics Processing Unit " + "(GPU)."); + + ctk_help_heading(b, &i, "Graphics Processor"); + ctk_help_para(b, &i, "This is the product name of the GPU."); + + ctk_help_heading(b, &i, "VBIOS Version"); + ctk_help_para(b, &i, "This is the Video BIOS version."); + + ctk_help_heading(b, &i, "Memory"); + ctk_help_para(b, &i, "This is the overall amount of memory " + "available to your GPU. With TurboCache(TM) GPUs, " + "this value may exceed the amount of video " + "memory installed on the graphics card. With " + "integrated GPUs, the value may exceed the amount of " + "dedicated system memory set aside by the system " + "BIOS for use by the integrated GPU."); + + ctk_help_heading(b, &i, "Bus Type"); + ctk_help_para(b, &i, "This is the bus type which is " + "used to connect the NVIDIA GPU to the rest of " + "your computer; possible values are AGP, PCI, " + "PCI Express and Integrated."); + + ctk_help_heading(b, &i, "Bus ID"); + ctk_help_para(b, &i, "This is the GPU's PCI identification string, " + "reported in the form 'bus:device:function'. It uniquely " + "identifies the GPU's location in the host system. " + "This string can be used as-is with the 'BusID' X " + "configuration file option to unambiguously associate " + "Device sections with this GPU."); + + ctk_help_heading(b, &i, "IRQ"); + ctk_help_para(b, &i, "This is the interrupt request line assigned to " + "this GPU."); + + ctk_help_heading(b, &i, "X Screens"); + ctk_help_para(b, &i, "This is the list of X Screens driven by this GPU."); + + ctk_help_heading(b, &i, "Display Devices"); + ctk_help_para(b, &i, "This is the list of Display Devices (CRTs, TVs etc) " + "enabled on this GPU."); + + ctk_help_finish(b); + + return b; +} + + + +static void probe_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + CtkEventStruct *event_struct = (CtkEventStruct *) arg1; + CtkGpu *ctk_object = CTK_GPU(user_data); + unsigned int probed_displays = event_struct->value; + gchar *str; + + + str = make_display_device_list(ctk_object->handle, probed_displays); + + gtk_label_set_text(GTK_LABEL(ctk_object->displays), str); + + g_free(str); +} diff --git a/src/gtk+-2.x/ctkdevice.h b/src/gtk+-2.x/ctkgpu.h index d567383..60a6220 100644 --- a/src/gtk+-2.x/ctkdevice.h +++ b/src/gtk+-2.x/ctkgpu.h @@ -22,54 +22,62 @@ * */ -#ifndef __CTK_DEVICE_H__ -#define __CTK_DEVICE_H__ +#ifndef __CTK_GPU_H__ +#define __CTK_GPU_H__ #include <gtk/gtk.h> +#include "ctkevent.h" + #include "NvCtrlAttributes.h" G_BEGIN_DECLS -#define CTK_TYPE_DEVICE (ctk_device_get_type()) +#define CTK_TYPE_GPU (ctk_gpu_get_type()) -#define CTK_DEVICE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_DEVICE, CtkDevice)) +#define CTK_GPU(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_GPU, CtkGpu)) -#define CTK_DEVICE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_DEVICE, CtkDeviceClass)) +#define CTK_GPU_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_GPU, CtkGpuClass)) -#define CTK_IS_DEVICE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_DEVICE)) +#define CTK_IS_GPU(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_GPU)) -#define CTK_IS_DEVICE_CLASS(class) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_DEVICE)) +#define CTK_IS_GPU_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_GPU)) -#define CTK_DEVICE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_DEVICE, CtkDeviceClass)) +#define CTK_GPU_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_GPU, CtkGpuClass)) -typedef struct _CtkDevice CtkDevice; -typedef struct _CtkDeviceClass CtkDeviceClass; +typedef struct _CtkGpu CtkGpu; +typedef struct _CtkGpuClass CtkGpuClass; -struct _CtkDevice +struct _CtkGpu { GtkVBox parent; NvCtrlAttributeHandle *handle; + + GtkWidget *displays; }; -struct _CtkDeviceClass +struct _CtkGpuClass { GtkVBoxClass parent_class; }; -GType ctk_device_get_type (void) G_GNUC_CONST; -GtkWidget* ctk_device_new (NvCtrlAttributeHandle *handle); +GType ctk_gpu_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_gpu_new (NvCtrlAttributeHandle *handle, + NvCtrlAttributeHandle **screen_handles, + CtkEvent *ctk_event); + +GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *); + -GtkTextBuffer *ctk_device_create_help(GtkTextTagTable *, const gchar *); G_END_DECLS -#endif /* __CTK_DEVICE_H__ */ +#endif /* __CTK_GPU_H__ */ diff --git a/src/gtk+-2.x/ctkgvo-csc.c b/src/gtk+-2.x/ctkgvo-csc.c index 1a7f06e..5b0366b 100644 --- a/src/gtk+-2.x/ctkgvo-csc.c +++ b/src/gtk+-2.x/ctkgvo-csc.c @@ -27,7 +27,6 @@ #include <string.h> -#include "crt_banner.h" #include "ctkimage.h" #include "ctkgvo-csc.h" @@ -70,8 +69,6 @@ /* * TODO: ability to save/restore CSC to/from file. - * - * TODO: should use the same banner used on the front SDI page */ @@ -167,11 +164,11 @@ GType ctk_gvo_csc_get_type(void) GtkWidget* ctk_gvo_csc_new(NvCtrlAttributeHandle *handle, CtkConfig *ctk_config, - CtkEvent *ctk_event) + CtkEvent *ctk_event, + CtkGvo *gvo_parent) { GObject *object; CtkGvoCsc *ctk_gvo_csc; - GtkWidget *banner; GtkWidget *frame; GtkWidget *hbox, *hbox2; GtkWidget *vbox, *vbox2; @@ -217,13 +214,21 @@ GtkWidget* ctk_gvo_csc_new(NvCtrlAttributeHandle *handle, ctk_gvo_csc = CTK_GVO_CSC(object); ctk_gvo_csc->handle = handle; ctk_gvo_csc->ctk_config = ctk_config; + ctk_gvo_csc->gvo_parent = gvo_parent; gtk_box_set_spacing(GTK_BOX(object), 10); /* banner */ - banner = ctk_banner_image_new(&crt_banner_image); - gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); + + frame = gtk_frame_new(NULL); + gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); + + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + + ctk_gvo_csc->banner_frame = frame; /* checkbox to enable override of HW CSC */ @@ -1045,3 +1050,42 @@ static GtkWidget *build_opengl_only_msg(void) return frame; } /* build_opengl_only_msg() */ + + + +void ctk_gvo_csc_select(GtkWidget *widget) +{ + CtkGvoCsc *ctk_gvo_csc = CTK_GVO_CSC(widget); + CtkGvo *ctk_gvo = ctk_gvo_csc->gvo_parent; + + /* Grab the GVO parent banner table */ + + gtk_container_add(GTK_CONTAINER(ctk_gvo_csc->banner_frame), + ctk_gvo->banner.table); + + /* Set lastest LED state of this GVO device */ + + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 1, ctk_gvo->banner.img.vid1); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 2, ctk_gvo->banner.img.vid2); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 3, ctk_gvo->banner.img.sdi); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 4, ctk_gvo->banner.img.comp); + + ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) ctk_gvo_probe, + (gpointer) ctk_gvo); +} + + + +void ctk_gvo_csc_unselect(GtkWidget *widget) +{ + CtkGvoCsc *ctk_gvo_csc = CTK_GVO_CSC(widget); + CtkGvo *ctk_gvo = ctk_gvo_csc->gvo_parent; + + /* Return the GVO parent banner table */ + + gtk_container_remove(GTK_CONTAINER(ctk_gvo_csc->banner_frame), + ctk_gvo->banner.table); + + ctk_config_stop_timer(ctk_gvo->ctk_config, (GSourceFunc) ctk_gvo_probe, + (gpointer) ctk_gvo); +} diff --git a/src/gtk+-2.x/ctkgvo-csc.h b/src/gtk+-2.x/ctkgvo-csc.h index 7561039..bdbf1f4 100644 --- a/src/gtk+-2.x/ctkgvo-csc.h +++ b/src/gtk+-2.x/ctkgvo-csc.h @@ -27,6 +27,7 @@ #include "ctkevent.h" #include "ctkconfig.h" +#include "ctkgvo.h" G_BEGIN_DECLS @@ -61,6 +62,9 @@ struct _CtkGvoCsc NvCtrlAttributeHandle *handle; CtkConfig *ctk_config; + CtkGvo *gvo_parent; + GtkWidget *banner_frame; + float matrix[3][3]; // [row][column] float offset[3]; float scale[3]; @@ -90,11 +94,14 @@ struct _CtkGvoCscClass GType ctk_gvo_csc_get_type (void) G_GNUC_CONST; GtkWidget* ctk_gvo_csc_new (NvCtrlAttributeHandle *, - CtkConfig *, CtkEvent *); + CtkConfig *, CtkEvent *, CtkGvo *); //GtkTextBuffer *ctk_gvo_csc_create_help(GtkTextTagTable *, // CtkGvoCsc *); +void ctk_gvo_csc_select(GtkWidget *); +void ctk_gvo_csc_unselect(GtkWidget *); + G_END_DECLS #endif /* __CTK_GVO_CSC_H__ */ diff --git a/src/gtk+-2.x/ctkgvo.c b/src/gtk+-2.x/ctkgvo.c index 93f624c..f364ad9 100644 --- a/src/gtk+-2.x/ctkgvo.c +++ b/src/gtk+-2.x/ctkgvo.c @@ -145,8 +145,6 @@ static void update_offset_spin_buttons(CtkGvo *ctk_gvo); static void x_offset_changed(GtkSpinButton *spinbutton, gpointer user_data); static void y_offset_changed(GtkSpinButton *spinbutton, gpointer user_data); -static gint probe(gpointer data); - static void register_for_gvo_events(CtkGvo *ctk_gvo); static void gvo_event_received(GtkObject *object, @@ -226,16 +224,16 @@ static const FormatName videoFormatNames[] = { { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274, "1920 x 1080PsF 25.00 Hz (SMPTE274)" }, { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274, "1920 x 1080PsF 29.97 Hz (SMPTE274)" }, { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274, "1920 x 1080PsF 30.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_23_98_SMPTE372, "2048 x 1080i 23.98 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_24_00_SMPTE372, "2048 x 1080i 24.00 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_25_00_SMPTE372, "2048 x 1080i 25.00 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_29_97_SMPTE372, "2048 x 1080i 29.97 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_30_00_SMPTE372, "2048 x 1080i 30.00 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_98_SMPTE372, "2048 x 1080p 23.98 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE372, "2048 x 1080p 24.00 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE372, "2048 x 1080p 25.00 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE372, "2048 x 1080p 29.97 Hz (SMPTE372)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE372, "2048 x 1080p 30.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_47_96_SMPTE372, "2048 x 1080i 47.96 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_48_00_SMPTE372, "2048 x 1080i 48.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_50_00_SMPTE372, "2048 x 1080i 50.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_59_94_SMPTE372, "2048 x 1080i 59.94 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_60_00_SMPTE372, "2048 x 1080i 60.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_23_98_SMPTE372, "2048 x 1080p 23.98 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_24_00_SMPTE372, "2048 x 1080p 24.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_25_00_SMPTE372, "2048 x 1080p 25.00 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_29_97_SMPTE372, "2048 x 1080p 29.97 Hz (SMPTE372)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_30_00_SMPTE372, "2048 x 1080p 30.00 Hz (SMPTE372)" }, { -1, NULL }, }; @@ -269,16 +267,16 @@ static FormatDetails videoFormatDetails[] = { { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_23_98_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_24_00_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_25_00_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_29_97_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_30_00_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_98_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE372, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_47_96_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_48_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_50_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_59_94_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048I_60_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_23_98_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_24_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_25_00_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_29_97_SMPTE372, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_2048P_30_00_SMPTE372, 0, 0, 0 }, { -1, -1, -1, -1 }, }; @@ -426,11 +424,17 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle, } } - add_table_row(table, 0, 0, "Firmware Version:", firmware); + add_table_row(table, 0, + 0, 0.5, "Firmware Version:", + 0, 0.5, firmware); ctk_gvo->current_resolution_label = - add_table_row(table, 1, 0, "Current SDI Resolution:", "Inactive"); + add_table_row(table, 1, + 0, 0.5, "Current SDI Resolution:", + 0, 0.5, "Inactive"); ctk_gvo->current_state_label = - add_table_row(table, 2, 0, "Current SDI State:", "Inactive"); + add_table_row(table, 2, + 0, 0.5, "Current SDI State:", + 0, 0.5, "Inactive"); /* @@ -793,7 +797,7 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle, ctk_config_add_timer(ctk_gvo->ctk_config, DEFAULT_GVO_PROBE_TIME_INTERVAL, "Graphics To Video Probe", - (GSourceFunc) probe, + (GSourceFunc) ctk_gvo_probe, (gpointer) ctk_gvo); @@ -808,55 +812,12 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle, } /* ctk_gvo_new() */ -void ctk_gvo_select(GtkWidget *widget) -{ - CtkGvo *ctk_gvo = CTK_GVO(widget); - - gtk_container_add(GTK_CONTAINER(ctk_gvo->banner_frame), - ctk_gvo->banner.table); - - ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) probe); -} - -void ctk_gvo_unselect(GtkWidget *widget) -{ - CtkGvo *ctk_gvo = CTK_GVO(widget); - - gtk_container_remove(GTK_CONTAINER(ctk_gvo->banner_frame), - ctk_gvo->banner.table); - - ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) probe); -} - /**************************************************************************/ /* * code for handling the GVO banner */ - -#define GVO_BANNER_LEFT 0 -#define GVO_BANNER_VID1_GREEN 1 -#define GVO_BANNER_VID1_GREY 2 -#define GVO_BANNER_VID1_RED 3 -#define GVO_BANNER_VID1_YELLOW 4 -#define GVO_BANNER_VID2_GREEN 5 -#define GVO_BANNER_VID2_GREY 6 -#define GVO_BANNER_VID2_RED 7 -#define GVO_BANNER_VID2_YELLOW 8 -#define GVO_BANNER_SDI_SYNC_GREEN 9 -#define GVO_BANNER_SDI_SYNC_GREY 10 -#define GVO_BANNER_SDI_SYNC_RED 11 -#define GVO_BANNER_SDI_SYNC_YELLOW 12 -#define GVO_BANNER_COMP_SYNC_GREEN 13 -#define GVO_BANNER_COMP_SYNC_GREY 14 -#define GVO_BANNER_COMP_SYNC_RED 15 -#define GVO_BANNER_COMP_SYNC_YELLOW 16 -#define GVO_BANNER_RIGHT 17 - -#define GVO_BANNER_COUNT 18 - - /* value for controlling LED state */ #define GVO_LED_VID_OUT_NOT_IN_USE 0 @@ -872,8 +833,6 @@ void ctk_gvo_unselect(GtkWidget *widget) #define GVO_LED_COMP_SYNC_SYNC 1 -static GtkWidget *__gvo_banner_widget[GVO_BANNER_COUNT]; - /* XXX we can get rid of a bunch of these images */ static const nv_image_t *__gvo_banner_imgs[GVO_BANNER_COUNT] = { @@ -899,22 +858,26 @@ static const nv_image_t *__gvo_banner_imgs[GVO_BANNER_COUNT] = { /* - * pack_gvo_banner_slot() - update slot 'slot' in the banner with the + * ctk_gvo_pack_banner_slot() - update slot 'slot' in the banner with the * image specified by 'new' */ -static void pack_gvo_banner_slot(CtkGvoBanner *banner, - gint slot, gint new, gint old) +void ctk_gvo_pack_banner_slot(CtkGvoBanner *banner, gint slot, gint new) { - if (old >= 0) { + GList *list; + + /* Remove last image, if any */ + list = gtk_container_get_children(GTK_CONTAINER(banner->slots[slot])); + if (list) { gtk_container_remove(GTK_CONTAINER(banner->slots[slot]), - __gvo_banner_widget[old]); + (GtkWidget *)(list->data)); + g_list_free(list); } - gtk_box_pack_start(GTK_BOX(banner->slots[slot]), - __gvo_banner_widget[new], TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(banner->slots[slot]), banner->imgs[new], + TRUE, TRUE, 0); -} /* pack_gvo_banner_slot() */ +} /* ctk_gvo_pack_banner_slot() */ @@ -928,21 +891,25 @@ static void init_gvo_banner(CtkGvoBanner *banner) const nv_image_t *img; guint8 *image_buffer = NULL; + /* Create the banner table */ + banner->table = gtk_table_new(1, 6, FALSE); gtk_object_ref(GTK_OBJECT(banner->table)); - + gtk_table_set_row_spacings(GTK_TABLE(banner->table), 0); gtk_table_set_col_spacings(GTK_TABLE(banner->table), 0); + /* Create the banner images */ + for (i = 0; i < GVO_BANNER_COUNT; i++) { - - if (__gvo_banner_widget[i]) continue; - + + if (banner->imgs[i]) continue; + img = __gvo_banner_imgs[i]; - + image_buffer = decompress_image_data(img); - __gvo_banner_widget[i] = gtk_image_new_from_pixbuf + banner->imgs[i] = gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, FALSE, 8, img->width, img->height, img->width * img->bytes_per_pixel, @@ -953,33 +920,25 @@ static void init_gvo_banner(CtkGvoBanner *banner) * gtk_container_remove() later, it doesn't get destroyed */ - gtk_object_ref(GTK_OBJECT(__gvo_banner_widget[i])); - + gtk_object_ref(GTK_OBJECT(banner->imgs[i])); - gtk_widget_show(__gvo_banner_widget[i]); + + gtk_widget_show(banner->imgs[i]); } + /* - * fill in the banner table with initial images, and the - * containers for the LED images that will get swapped in and out. + * fill in the banner table containers for the LED images + * that will get swapped in and out. */ - - gtk_table_attach(GTK_TABLE(banner->table), - __gvo_banner_widget[GVO_BANNER_LEFT], - 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); - - for (i = 0; i < 4; i++) { + for (i = 0; i < 6; i++) { banner->slots[i] = gtk_hbox_new(FALSE, 0); gtk_object_ref(GTK_OBJECT(banner->slots[i])); gtk_table_attach(GTK_TABLE(banner->table), banner->slots[i], i+1, i+2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); } - - gtk_table_attach(GTK_TABLE(banner->table), - __gvo_banner_widget[GVO_BANNER_RIGHT], - 5, 6, 0, 1, GTK_FILL, GTK_FILL, 0, 0); - + /* * initialize LED state @@ -995,10 +954,8 @@ static void init_gvo_banner(CtkGvoBanner *banner) banner->img.sdi = GVO_BANNER_SDI_SYNC_GREY; banner->img.comp = GVO_BANNER_COMP_SYNC_GREY; - pack_gvo_banner_slot(banner, 0, banner->img.vid1, -1); - pack_gvo_banner_slot(banner, 1, banner->img.vid2, -1); - pack_gvo_banner_slot(banner, 2, banner->img.sdi, -1); - pack_gvo_banner_slot(banner, 3, banner->img.comp, -1); + ctk_gvo_pack_banner_slot(banner, 0, GVO_BANNER_LEFT); + ctk_gvo_pack_banner_slot(banner, 5, GVO_BANNER_RIGHT); gtk_widget_show_all(GTK_WIDGET(banner->table)); @@ -1047,7 +1004,7 @@ static gboolean update_gvo_banner(gpointer data) } if (old != new) { - pack_gvo_banner_slot(banner, 0, new, old); + ctk_gvo_pack_banner_slot(banner, 1, new); banner->img.vid1 = new; } @@ -1078,7 +1035,7 @@ static gboolean update_gvo_banner(gpointer data) } if (old != new) { - pack_gvo_banner_slot(banner, 1, new, old); + ctk_gvo_pack_banner_slot(banner, 2, new); banner->img.vid2 = new; } @@ -1111,7 +1068,7 @@ static gboolean update_gvo_banner(gpointer data) } if (old != new) { - pack_gvo_banner_slot(banner, 2, new, old); + ctk_gvo_pack_banner_slot(banner, 3, new); banner->img.sdi = new; } @@ -1132,7 +1089,7 @@ static gboolean update_gvo_banner(gpointer data) } if (old != new) { - pack_gvo_banner_slot(banner, 3, new, old); + ctk_gvo_pack_banner_slot(banner, 4, new); banner->img.comp = new; } @@ -2133,7 +2090,7 @@ static gint detect_input_done(gpointer data) /* reprobe */ - probe((gpointer) ctk_gvo); + ctk_gvo_probe((gpointer) ctk_gvo); /* un-press the detect button */ @@ -2470,10 +2427,10 @@ static void y_offset_changed(GtkSpinButton *spinbutton, gpointer user_data) /**************************************************************************/ /* - * probe() - query the incoming signal + * ctk_gvo_probe() - query the incoming signal */ -static gint probe(gpointer data) +gint ctk_gvo_probe(gpointer data) { ReturnStatus ret; gint input, sdi, comp; @@ -2534,7 +2491,7 @@ static gint probe(gpointer data) return TRUE; -} /* probe() */ +} /* ctk_gvo_probe() */ /**************************************************************************/ @@ -2761,6 +2718,38 @@ static void gvo_event_received(GtkObject *object, /**************************************************************************/ +void ctk_gvo_select(GtkWidget *widget) +{ + CtkGvo *ctk_gvo = CTK_GVO(widget); + + gtk_container_add(GTK_CONTAINER(ctk_gvo->banner_frame), + ctk_gvo->banner.table); + + /* Set lastest LED state of this GVO device */ + + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 1, ctk_gvo->banner.img.vid1); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 2, ctk_gvo->banner.img.vid2); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 3, ctk_gvo->banner.img.sdi); + ctk_gvo_pack_banner_slot(&ctk_gvo->banner, 4, ctk_gvo->banner.img.comp); + + ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) ctk_gvo_probe, + (gpointer) ctk_gvo); +} + + + +void ctk_gvo_unselect(GtkWidget *widget) +{ + CtkGvo *ctk_gvo = CTK_GVO(widget); + + gtk_container_remove(GTK_CONTAINER(ctk_gvo->banner_frame), + ctk_gvo->banner.table); + + ctk_config_stop_timer(ctk_gvo->ctk_config, (GSourceFunc) ctk_gvo_probe, + (gpointer) ctk_gvo); +} + + GtkTextBuffer* ctk_gvo_create_help (GtkTextTagTable *table) { diff --git a/src/gtk+-2.x/ctkgvo.h b/src/gtk+-2.x/ctkgvo.h index b495cfd..7a1734f 100644 --- a/src/gtk+-2.x/ctkgvo.h +++ b/src/gtk+-2.x/ctkgvo.h @@ -57,11 +57,35 @@ typedef struct _CtkGvoClass CtkGvoClass; typedef struct _CtkGvoBanner CtkGvoBanner; +#define GVO_BANNER_LEFT 0 +#define GVO_BANNER_VID1_GREEN 1 +#define GVO_BANNER_VID1_GREY 2 +#define GVO_BANNER_VID1_RED 3 +#define GVO_BANNER_VID1_YELLOW 4 +#define GVO_BANNER_VID2_GREEN 5 +#define GVO_BANNER_VID2_GREY 6 +#define GVO_BANNER_VID2_RED 7 +#define GVO_BANNER_VID2_YELLOW 8 +#define GVO_BANNER_SDI_SYNC_GREEN 9 +#define GVO_BANNER_SDI_SYNC_GREY 10 +#define GVO_BANNER_SDI_SYNC_RED 11 +#define GVO_BANNER_SDI_SYNC_YELLOW 12 +#define GVO_BANNER_COMP_SYNC_GREEN 13 +#define GVO_BANNER_COMP_SYNC_GREY 14 +#define GVO_BANNER_COMP_SYNC_RED 15 +#define GVO_BANNER_COMP_SYNC_YELLOW 16 +#define GVO_BANNER_RIGHT 17 + +#define GVO_BANNER_COUNT 18 + + struct _CtkGvoBanner { + GtkWidget *imgs[GVO_BANNER_COUNT]; + GtkWidget *table; - - GtkWidget *slots[4]; + + GtkWidget *slots[6]; struct { guint8 vid1; @@ -143,6 +167,8 @@ GtkWidget* ctk_gvo_new (NvCtrlAttributeHandle *, void ctk_gvo_select (GtkWidget *); void ctk_gvo_unselect (GtkWidget *); GtkTextBuffer* ctk_gvo_create_help (GtkTextTagTable *); +void ctk_gvo_pack_banner_slot (CtkGvoBanner *, gint slot, gint new); +gint ctk_gvo_probe (gpointer data); G_END_DECLS diff --git a/src/gtk+-2.x/ctkhelp.c b/src/gtk+-2.x/ctkhelp.c index 5df77ca..378efb4 100644 --- a/src/gtk+-2.x/ctkhelp.c +++ b/src/gtk+-2.x/ctkhelp.c @@ -29,6 +29,7 @@ #include "ctkconstants.h" #include "help_banner.h" +#include "ctkimage.h" #include <stdlib.h> @@ -74,13 +75,10 @@ GtkWidget* ctk_help_new(GtkWidget *toggle_button, GtkTextTagTable *tag_table) GtkWidget *alignment; GtkWidget *button; GtkWidget *sw; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *textview; - guint8 *image_buffer = NULL; - const nv_image_t *img; - object = g_object_new(CTK_TYPE_HELP, NULL); ctk_help = CTK_HELP(object); @@ -102,22 +100,8 @@ GtkWidget* ctk_help_new(GtkWidget *toggle_button, GtkTextTagTable *tag_table) hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - - img = &help_banner_image; - - image_buffer = decompress_image_data(img); - - image = gtk_image_new_from_pixbuf - (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, img->width, img->height, - img->width * img->bytes_per_pixel, - free_decompressed_image, NULL)); - - gtk_container_add(GTK_CONTAINER(frame), image); + banner = ctk_banner_image_new(&help_banner_image); + gtk_box_pack_start(GTK_BOX(hbox), banner, TRUE, TRUE, 0); /* create the scroll window to hold the text viewer */ diff --git a/src/gtk+-2.x/ctkimage.c b/src/gtk+-2.x/ctkimage.c index 319c55f..d8939f5 100644 --- a/src/gtk+-2.x/ctkimage.c +++ b/src/gtk+-2.x/ctkimage.c @@ -32,6 +32,7 @@ #include "image.h" #include "ctkimage.h" +#include "ctkbanner.h" /* @@ -108,14 +109,14 @@ GtkWidget* ctk_banner_image_new(const nv_image_t *img) GtkWidget *frame; - image = ctk_image_new(img); + image = ctk_banner_new(img); if (!image) return NULL; hbox = gtk_hbox_new(FALSE, 0); frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(frame), image); diff --git a/src/gtk+-2.x/ctkimagesliders.c b/src/gtk+-2.x/ctkimagesliders.c index 5c3ee1e..80152a0 100644 --- a/src/gtk+-2.x/ctkimagesliders.c +++ b/src/gtk+-2.x/ctkimagesliders.c @@ -34,22 +34,27 @@ #define FRAME_PADDING 5 -static void -dvc_adjustment_value_changed(GtkAdjustment *, gpointer); +static const char *__digital_vibrance_help = "The Digital Vibrance slider " +"alters the level of Digital Vibrance for this display device."; -static void dvc_update_slider(CtkImageSliders *ctk_image_sliders, gint value); +static const char *__image_sharpening_help = "The Image Sharpening slider " +"alters the level of Image Sharpening for this display device."; -static void dvc_update_received(GtkObject *, gpointer arg1, gpointer); -static void -image_sharpening_adjustment_value_changed(GtkAdjustment *, gpointer); +static GtkWidget * add_scale(CtkConfig *ctk_config, + int attribute, + char *name, + const char *help, + gint value_type, + gpointer callback_data); -static void -image_sharpening_update_slider(CtkImageSliders *ctk_image_sliders, gint value); +static void setup_scale(CtkImageSliders *ctk_image_sliders, + int attribute, GtkWidget *scale); -static void image_sharpening_update_received(GtkObject *, gpointer arg1, - gpointer); +static void scale_value_changed(GtkAdjustment *adjustment, + gpointer user_data); +static void scale_value_received(GtkObject *, gpointer arg1, gpointer); GType ctk_image_sliders_get_type(void) @@ -89,40 +94,7 @@ GtkWidget* ctk_image_sliders_new(NvCtrlAttributeHandle *handle, GtkWidget *frame; GtkWidget *vbox; - GtkWidget *scale; - GtkWidget *widget; - - ReturnStatus ret0, ret1, ret2, ret3; - - NVCTRLAttributeValidValuesRec dvc_valid, sharp_valid; - - int dvc, sharp; - - /* - * retrieve the valid values and current value for DVC and Image - * Sharpening; if we were unable to query any of those, then - * return NULL. - */ - - ret0 = NvCtrlGetValidDisplayAttributeValues(handle, display_device_mask, - NV_CTRL_DIGITAL_VIBRANCE, - &dvc_valid); - - ret1 = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_DIGITAL_VIBRANCE, - &dvc); - ret2 = NvCtrlGetValidDisplayAttributeValues(handle, display_device_mask, - NV_CTRL_IMAGE_SHARPENING, - &sharp_valid); - - ret3 = NvCtrlGetDisplayAttribute(handle, display_device_mask, - NV_CTRL_IMAGE_SHARPENING, - &sharp); - - if ((ret0 != NvCtrlSuccess) && (ret1 != NvCtrlSuccess) && - (ret2 != NvCtrlSuccess) && (ret3 != NvCtrlSuccess)) return NULL; - /* * now that we know that we will have atleast one attribute, * create the object @@ -133,6 +105,7 @@ GtkWidget* ctk_image_sliders_new(NvCtrlAttributeHandle *handle, ctk_image_sliders = CTK_IMAGE_SLIDERS(object); ctk_image_sliders->handle = handle; ctk_image_sliders->ctk_config = ctk_config; + ctk_image_sliders->ctk_event = ctk_event; ctk_image_sliders->reset_button = reset_button; ctk_image_sliders->display_device_mask = display_device_mask; ctk_image_sliders->name = name; @@ -144,83 +117,44 @@ GtkWidget* ctk_image_sliders_new(NvCtrlAttributeHandle *handle, gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0); + ctk_image_sliders->frame = frame; - - /* DVC */ + /* Digital Vibrance */ - if ((ret0 == NvCtrlSuccess) && (ret1 == NvCtrlSuccess)) { - - ctk_image_sliders->dvc_adjustment = - gtk_adjustment_new(dvc, - dvc_valid.u.range.min, - dvc_valid.u.range.max, - 1, 5, 0); - - g_signal_connect(G_OBJECT(ctk_image_sliders->dvc_adjustment), - "value_changed", - G_CALLBACK(dvc_adjustment_value_changed), - (gpointer) ctk_image_sliders); - - g_signal_connect(G_OBJECT(ctk_event), - CTK_EVENT_NAME(NV_CTRL_DIGITAL_VIBRANCE), - G_CALLBACK(dvc_update_received), - (gpointer) ctk_image_sliders); - - scale = ctk_scale_new - (GTK_ADJUSTMENT(ctk_image_sliders->dvc_adjustment), - "Digital Vibrance", ctk_config, G_TYPE_DOUBLE); - - gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0); - - widget = CTK_SCALE(scale)->gtk_scale; + ctk_image_sliders->digital_vibrance = + add_scale(ctk_config, + NV_CTRL_DIGITAL_VIBRANCE, "Digital Vibrance", + __digital_vibrance_help, G_TYPE_DOUBLE, ctk_image_sliders); + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_DIGITAL_VIBRANCE), + G_CALLBACK(scale_value_received), + (gpointer) ctk_image_sliders); + + gtk_box_pack_start(GTK_BOX(vbox), ctk_image_sliders->digital_vibrance, + TRUE, TRUE, 0); - ctk_config_set_tooltip(ctk_config, widget, - "The Digital Vibrance slider alters the level " - "of Digital Vibrance for this display device."); - } else { - ctk_image_sliders->dvc_adjustment = NULL; - } - - /* Image Sharpening */ + + ctk_image_sliders->image_sharpening = + add_scale(ctk_config, + NV_CTRL_IMAGE_SHARPENING, "Image Sharpening", + __image_sharpening_help, G_TYPE_DOUBLE, ctk_image_sliders); - if ((ret2 == NvCtrlSuccess) && (ret3 == NvCtrlSuccess)) { - - ctk_image_sliders->image_sharpening_adjustment = - gtk_adjustment_new(sharp, - sharp_valid.u.range.min, - sharp_valid.u.range.max, - 1, 5, 0); - - g_signal_connect - (G_OBJECT(ctk_image_sliders->image_sharpening_adjustment), - "value_changed", - G_CALLBACK(image_sharpening_adjustment_value_changed), - (gpointer) ctk_image_sliders); - - g_signal_connect(G_OBJECT(ctk_event), - CTK_EVENT_NAME(NV_CTRL_IMAGE_SHARPENING), - G_CALLBACK(image_sharpening_update_received), - (gpointer) ctk_image_sliders); - - scale = ctk_scale_new - (GTK_ADJUSTMENT(ctk_image_sliders->image_sharpening_adjustment), - "Image Sharpening", ctk_config, G_TYPE_DOUBLE); - - gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0); - - widget = CTK_SCALE(scale)->gtk_scale; - - ctk_config_set_tooltip(ctk_config, widget, - "The Image Sharpening slider alters the level " - "of Image Sharpening for this display device."); - } else { - ctk_image_sliders->image_sharpening_adjustment = NULL; - } + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_IMAGE_SHARPENING), + G_CALLBACK(scale_value_received), + (gpointer) ctk_image_sliders); + gtk_box_pack_start(GTK_BOX(vbox), ctk_image_sliders->image_sharpening, + TRUE, TRUE, 0); gtk_widget_show_all(GTK_WIDGET(object)); + /* update the GUI */ + + ctk_image_sliders_setup(ctk_image_sliders); + return GTK_WIDGET(object); } /* ctk_image_sliders_new() */ @@ -228,257 +162,314 @@ GtkWidget* ctk_image_sliders_new(NvCtrlAttributeHandle *handle, /* - * ctk_image_sliders_reset() - + * Returns whether or not the scale is active */ -void ctk_image_sliders_reset(CtkImageSliders *ctk_image_sliders) +static gint get_scale_active(CtkScale *scale) { - if (!ctk_image_sliders) return; + GtkAdjustment *adj = scale->gtk_adjustment; - if (ctk_image_sliders->dvc_adjustment) { + return + GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adj), "attribute active")); + +} /* get_scale_active() */ + + + +/* + * add_scale() - if the specified attribute exists and we can + * query its valid values, create a new scale widget + */ + +static GtkWidget * add_scale(CtkConfig *ctk_config, + int attribute, + char *name, + const char *help, + gint value_type, + gpointer callback_data) +{ + GtkObject *adj; + GtkWidget *scale; + + + adj = gtk_adjustment_new(0, 0, 10, 1, 1, 0); - NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, - ctk_image_sliders->display_device_mask, - NV_CTRL_DIGITAL_VIBRANCE, - 0); + g_object_set_data(G_OBJECT(adj), "attribute", + GINT_TO_POINTER(attribute)); - dvc_update_slider(ctk_image_sliders, 0); - } + g_object_set_data(G_OBJECT(adj), "attribute name", name); + + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(0)); - if (ctk_image_sliders->image_sharpening_adjustment) { + g_signal_connect(G_OBJECT(adj), "value_changed", + G_CALLBACK(scale_value_changed), + (gpointer) callback_data); - NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, - ctk_image_sliders->display_device_mask, - NV_CTRL_IMAGE_SHARPENING, - 0); + scale = ctk_scale_new(GTK_ADJUSTMENT(adj), name, ctk_config, value_type); - image_sharpening_update_slider(ctk_image_sliders, 0); + if (help) { + ctk_config_set_tooltip(ctk_config, CTK_SCALE_TOOLTIP_WIDGET(scale), + help); } -} /* ctk_image_sliders_reset() */ + return scale; + +} /* add_scale() */ /* - * post_dvc_update() - helper function for - * dvc_adjustment_value_changed() and dvc_update_received(); this does - * whatever work is necessary after the the DVC adjustment widget is - * updated -- currently, this is just posting a statusbar message. + * post_scale_value_changed() - helper function for + * scale_value_changed() and value_changed(); this does whatever + * work is necessary after the adjustment has been updated -- + * currently, this just means posting a statusbar message. */ -static void post_dvc_update(CtkImageSliders *ctk_image_sliders, int value) +static void post_scale_value_changed(GtkAdjustment *adjustment, + CtkImageSliders *ctk_image_sliders, + gint value) { + char *name = g_object_get_data(G_OBJECT(adjustment), "attribute name"); + + gtk_widget_set_sensitive(ctk_image_sliders->reset_button, TRUE); + ctk_config_statusbar_message(ctk_image_sliders->ctk_config, - "Digital Vibrance for %s set to %d.", - ctk_image_sliders->name, value); + "%s set to %d.", name, value); -} /* post_dvc_update() */ +} /* post_scale_value_changed() */ /* - * dvc_adjustment_value_changed() - update the DVC value with the - * current value of the adjustment widget. + * scale_value_changed() - callback when any of the adjustments + * in the CtkImageSliders are changed: get the new value from the + * adjustment, send it to the X server, and do any post-adjustment + * work. */ -static void dvc_adjustment_value_changed(GtkAdjustment *adjustment, - gpointer user_data) +static void scale_value_changed(GtkAdjustment *adjustment, + gpointer user_data) { - CtkImageSliders *ctk_image_sliders; - int value; + CtkImageSliders *ctk_image_sliders = + CTK_IMAGE_SLIDERS(user_data); - ctk_image_sliders = CTK_IMAGE_SLIDERS(user_data); + gint value; + gint attribute; - value = (int) gtk_adjustment_get_value(adjustment); + value = (gint) gtk_adjustment_get_value(adjustment); + + user_data = g_object_get_data(G_OBJECT(adjustment), "attribute"); + attribute = GPOINTER_TO_INT(user_data); NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, ctk_image_sliders->display_device_mask, - NV_CTRL_DIGITAL_VIBRANCE, - value); + attribute, (int) value); - post_dvc_update(ctk_image_sliders, value); - -} /* dvc_adjustment_value_changed() */ + post_scale_value_changed(adjustment, ctk_image_sliders, value); + +} /* scale_value_changed() */ /* - * dvc_update_slider() - update the slider with the specified value + * ctk_image_sliders_reset() - */ -static void dvc_update_slider(CtkImageSliders *ctk_image_sliders, gint value) +void ctk_image_sliders_reset(CtkImageSliders *ctk_image_sliders) { - GtkAdjustment *adjustment = - GTK_ADJUSTMENT(ctk_image_sliders->dvc_adjustment); - - g_signal_handlers_block_by_func(G_OBJECT(adjustment), - G_CALLBACK(dvc_adjustment_value_changed), - (gpointer) ctk_image_sliders); - - gtk_adjustment_set_value(adjustment, value); - - g_signal_handlers_unblock_by_func(G_OBJECT(adjustment), - G_CALLBACK(dvc_adjustment_value_changed), - (gpointer) ctk_image_sliders); + if (!ctk_image_sliders) return; + + if (get_scale_active(CTK_SCALE(ctk_image_sliders->digital_vibrance))) { + NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, + ctk_image_sliders->display_device_mask, + NV_CTRL_DIGITAL_VIBRANCE, + 0); + } + + if (get_scale_active(CTK_SCALE(ctk_image_sliders->image_sharpening))) { + NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, + ctk_image_sliders->display_device_mask, + NV_CTRL_IMAGE_SHARPENING, + 0); + } + + ctk_image_sliders_setup(ctk_image_sliders); -} /* dvc_update_slider() */ +} /* ctk_image_sliders_reset() */ /* - * dvc_update_received() - callback function for when the - * NV_CTRL_DIGITAL_VIBRANCE attribute is changed by another NV-CONTROL - * client. + * scale_value_received() - callback function for changed image settings; this + * is called when we receive an event indicating that another + * NV-CONTROL client changed any of the settings that we care about. */ -static void dvc_update_received(GtkObject *object, - gpointer arg1, gpointer user_data) +static void scale_value_received(GtkObject *object, gpointer arg1, + gpointer user_data) { - CtkEventStruct *event_struct = (CtkEventStruct *) arg1; - CtkImageSliders *ctk_image_sliders = CTK_IMAGE_SLIDERS(user_data); + CtkEventStruct *event_struct; + CtkImageSliders *ctk_image_sliders = + CTK_IMAGE_SLIDERS(user_data); - /* if the event is not for this display device, return */ + GtkAdjustment *adj; + GtkWidget *scale; + gint val; + + event_struct = (CtkEventStruct *) arg1; + + /* if the event is not for this display device, return */ + if (!(event_struct->display_mask & ctk_image_sliders->display_device_mask)) { return; } - dvc_update_slider(ctk_image_sliders, event_struct->value); - - post_dvc_update(ctk_image_sliders, event_struct->value); + switch (event_struct->attribute) { + case NV_CTRL_DIGITAL_VIBRANCE: + scale = ctk_image_sliders->digital_vibrance; + break; + case NV_CTRL_IMAGE_SHARPENING: + scale = ctk_image_sliders->image_sharpening; + break; + default: + return; + } -} /* dvc_update_received() */ - + adj = CTK_SCALE(scale)->gtk_adjustment; + val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj)); + if (val != event_struct->value) { + + val = event_struct->value; -/* - * post_image_sharpening_update() - helper function for - * image_sharpening_adjustment_value_changed() and - * image_sharpening_update_received(); this does whatever work is - * necessary after the the image sharpening adjustment widget is - * updated -- currently, this is just posting a statusbar message. - */ + g_signal_handlers_block_by_func(adj, scale_value_changed, + ctk_image_sliders); + + gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), val); + + post_scale_value_changed(GTK_ADJUSTMENT(adj), + ctk_image_sliders, val); + + g_signal_handlers_unblock_by_func(adj, scale_value_changed, + ctk_image_sliders); + } -static void -post_image_sharpening_update(CtkImageSliders *ctk_image_sliders, gint value) -{ - ctk_config_statusbar_message(ctk_image_sliders->ctk_config, - "Image Sharpening for %s set to %d.", - ctk_image_sliders->name, value); - -} /* post_image_sharpening_update() */ +} /* scale_value_received() */ /* - * image_sharpening_adjustment_value_changed() - + * add_image_sliders_help() - */ -static void -image_sharpening_adjustment_value_changed(GtkAdjustment *adjustment, - gpointer user_data) +void add_image_sliders_help(CtkImageSliders *ctk_image_sliders, + GtkTextBuffer *b, + GtkTextIter *i) { - CtkImageSliders *ctk_image_sliders; - int value; - - ctk_image_sliders = CTK_IMAGE_SLIDERS(user_data); - - value = (int) gtk_adjustment_get_value(adjustment); + ctk_help_heading(b, i, "Digital Vibrance"); + ctk_help_para(b, i, "Digital Vibrance, a mechanism for " + "controlling color separation and intensity, boosts " + "the color saturation of an image so that all images " + "including 2D, 3D, and video appear brighter and " + "crisper (even on flat panels) in your applications."); + + ctk_help_heading(b, i, "Image Sharpening"); + ctk_help_para(b, i, "Use the Image Sharpening slider to adjust the " + "sharpness of the image quality by amplifying high " + "frequency content."); - NvCtrlSetDisplayAttribute(ctk_image_sliders->handle, - ctk_image_sliders->display_device_mask, - NV_CTRL_IMAGE_SHARPENING, - value); - - post_image_sharpening_update(ctk_image_sliders, value); - -} /* image_sharpening_adjustment_value_changed() */ +} /* add_image_sliders_help() */ -/* - * image_sharpening_update_slider() - update the slider with the - * specified value +/* Update GUI state of the scale to reflect current settings + * on the X Driver. */ -static void image_sharpening_update_slider(CtkImageSliders *ctk_image_sliders, - gint value) +static void setup_scale(CtkImageSliders *ctk_image_sliders, + int attribute, + GtkWidget *scale) { - GtkAdjustment *adjustment = - GTK_ADJUSTMENT(ctk_image_sliders->image_sharpening_adjustment); - - g_signal_handlers_block_by_func - (G_OBJECT(adjustment), - G_CALLBACK(image_sharpening_adjustment_value_changed), - (gpointer) ctk_image_sliders); + ReturnStatus ret0, ret1; + NVCTRLAttributeValidValuesRec valid; + NvCtrlAttributeHandle *handle = ctk_image_sliders->handle; + unsigned int mask = ctk_image_sliders->display_device_mask; + int val; + GtkAdjustment *adj = CTK_SCALE(scale)->gtk_adjustment; - gtk_adjustment_set_value(adjustment, value); + + /* Read settings from X server */ + ret0 = NvCtrlGetValidDisplayAttributeValues(handle, mask, + attribute, &valid); - g_signal_handlers_unblock_by_func - (G_OBJECT(adjustment), - G_CALLBACK(image_sharpening_adjustment_value_changed), - (gpointer) ctk_image_sliders); + ret1 = NvCtrlGetDisplayAttribute(handle, mask, attribute, &val); -} /* image_sharpening_update_slider() */ + if ((ret0 == NvCtrlSuccess) && (ret1 == NvCtrlSuccess) && + (valid.type == ATTRIBUTE_TYPE_RANGE)) { + g_signal_handlers_block_by_func(adj, scale_value_changed, + ctk_image_sliders); + adj->lower = valid.u.range.min; + adj->upper = valid.u.range.max; + gtk_adjustment_changed(GTK_ADJUSTMENT(adj)); -/* - * image_sharpening_update_received() - callback function for when the - * NV_CTRL_IMAGE_SHARPENING attribute is change by another NV-CONTROL - * client. - */ + gtk_adjustment_set_value(GTK_ADJUSTMENT(adj), val); -static void image_sharpening_update_received(GtkObject *object, - gpointer arg1, gpointer user_data) -{ - CtkEventStruct *event_struct = (CtkEventStruct *) arg1; - CtkImageSliders *ctk_image_sliders = CTK_IMAGE_SLIDERS(user_data); - - /* if the event is not for this display device, return */ + g_signal_handlers_unblock_by_func(adj, scale_value_changed, + ctk_image_sliders); - if (!(event_struct->display_mask & - ctk_image_sliders->display_device_mask)) { - return; + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(1)); + + gtk_widget_set_sensitive(scale, TRUE); + gtk_widget_show(scale); + } else { + g_object_set_data(G_OBJECT(adj), "attribute active", + GINT_TO_POINTER(0)); + + gtk_widget_set_sensitive(scale, FALSE); + gtk_widget_hide(scale); } - - image_sharpening_update_slider(ctk_image_sliders, event_struct->value); - post_image_sharpening_update(ctk_image_sliders, event_struct->value); - -} /* image_sharpening_update_received() */ +} /* setup_scale() */ /* - * add_image_sliders_help() - + * Updates the page to reflect the current configuration of + * the display device. */ - -gboolean add_image_sliders_help(CtkImageSliders *ctk_image_sliders, - GtkTextBuffer *b, - GtkTextIter *i) +void ctk_image_sliders_setup(CtkImageSliders *ctk_image_sliders) { - gboolean ret = FALSE; - - if (ctk_image_sliders->dvc_adjustment) { - ctk_help_heading(b, i, "Digital Vibrance"); - ctk_help_para(b, i, "Digital Vibrance, a mechanism for " - "controlling color separation and intensity, boosts " - "the color saturation of an image so that all images " - "including 2D, 3D, and video appear brighter and " - "crisper (even on flat panels) in your applications."); - ret = TRUE; - } + int active; - if (ctk_image_sliders->image_sharpening_adjustment) { - ctk_help_heading(b, i, "Image Sharpening"); - ctk_help_para(b, i, "Use the Image Sharpening slider to adjust the " - "sharpness of the image quality by amplifying high " - "frequency content."); - ret = TRUE; - } - return ret; + if (!ctk_image_sliders) return; + + /* Update sliders */ -} /* add_image_sliders_help() */ + /* NV_CTRL_DIGITAL_VIBRANCE */ + + setup_scale(ctk_image_sliders, NV_CTRL_DIGITAL_VIBRANCE, + ctk_image_sliders->digital_vibrance); + + /* NV_CTRL_IMAGE_SHARPENING */ + + setup_scale(ctk_image_sliders, NV_CTRL_IMAGE_SHARPENING, + ctk_image_sliders->image_sharpening); + + active = + get_scale_active(CTK_SCALE(ctk_image_sliders->digital_vibrance)) || + get_scale_active(CTK_SCALE(ctk_image_sliders->image_sharpening)); + + if (!active) { + gtk_widget_hide(ctk_image_sliders->frame); + } else { + gtk_widget_show(ctk_image_sliders->frame); + } + +} /* ctk_image_sliders_setup() */ diff --git a/src/gtk+-2.x/ctkimagesliders.h b/src/gtk+-2.x/ctkimagesliders.h index 1b9fc87..21172e6 100644 --- a/src/gtk+-2.x/ctkimagesliders.h +++ b/src/gtk+-2.x/ctkimagesliders.h @@ -58,16 +58,16 @@ struct _CtkImageSliders GtkVBox parent; NvCtrlAttributeHandle *handle; + unsigned int display_device_mask; + char *name; + CtkConfig *ctk_config; + CtkEvent *ctk_event; GtkWidget *reset_button; - GtkObject *dvc_adjustment; - GtkObject *image_sharpening_adjustment; - - char *name; - - unsigned int display_device_mask; - unsigned int active_attributes; + GtkWidget *frame; + GtkWidget *digital_vibrance; + GtkWidget *image_sharpening; }; struct _CtkImageSlidersClass @@ -84,9 +84,11 @@ GtkWidget* ctk_image_sliders_new (NvCtrlAttributeHandle *, void ctk_image_sliders_reset(CtkImageSliders *); -gboolean add_image_sliders_help(CtkImageSliders *ctk_image_sliders, - GtkTextBuffer *b, - GtkTextIter *i); +void ctk_image_sliders_setup(CtkImageSliders *ctk_image_sliders); + +void add_image_sliders_help(CtkImageSliders *ctk_image_sliders, + GtkTextBuffer *b, + GtkTextIter *i); G_END_DECLS diff --git a/src/gtk+-2.x/ctkmultisample.c b/src/gtk+-2.x/ctkmultisample.c index 79795d1..7c1a560 100644 --- a/src/gtk+-2.x/ctkmultisample.c +++ b/src/gtk+-2.x/ctkmultisample.c @@ -33,6 +33,7 @@ #include "ctkconfig.h" #include "ctkhelp.h" +#include "ctkimage.h" /* local prototypes */ @@ -184,14 +185,11 @@ GtkWidget *ctk_multisample_new(NvCtrlAttributeHandle *handle, GObject *object; CtkMultisample *ctk_multisample; GtkWidget *hbox, *vbox = NULL; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *check_button; GtkWidget *scale; - guint8 *image_buffer = NULL; - const nv_image_t *img; - gint val, app_control, override, i; NVCTRLAttributeValidValuesRec valid; @@ -214,21 +212,9 @@ GtkWidget *ctk_multisample_new(NvCtrlAttributeHandle *handle, hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); - frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - img = &antialiasing_banner_image; - image_buffer = decompress_image_data(img); + banner = ctk_banner_image_new(&antialiasing_banner_image); + gtk_box_pack_start(GTK_BOX(hbox), banner, TRUE, TRUE, 0); - image = gtk_image_new_from_pixbuf - (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, img->width, img->height, - img->width * img->bytes_per_pixel, - free_decompressed_image, NULL)); - - gtk_container_add(GTK_CONTAINER(frame), image); - /* FSAA slider */ ret = NvCtrlGetValidAttributeValues(handle, NV_CTRL_FSAA_MODE, &valid); @@ -1205,9 +1191,9 @@ GtkTextBuffer *ctk_multisample_create_help(GtkTextTagTable *table, "expense of some performance."); ctk_help_para(b, &i, "You can also configure Anisotropic filtering " - "using the __GL_DEFAULT_LOG_ANISO environment varible " + "using the __GL_LOG_MAX_ANISO environment varible " "(see the README for details). The " - "__GL_DEFAULT_LOG_ANISO environment variable overrides " + "__GL_LOG_MAX_ANISO environment variable overrides " "the value in nvidia-settings."); ctk_help_term(b, &i, "Override Application Setting"); diff --git a/src/gtk+-2.x/ctkopengl.c b/src/gtk+-2.x/ctkopengl.c index 82d867a..bd34faa 100644 --- a/src/gtk+-2.x/ctkopengl.c +++ b/src/gtk+-2.x/ctkopengl.c @@ -151,10 +151,74 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, GtkWidget *vbox; GtkWidget *check_button; GtkWidget *scale; - gint force_generic_cpu_value, aa_line_gamma_value, val; - ReturnStatus ret; - NVCTRLAttributeValidValuesRec valid; + gint sync_to_vblank; + gint flipping_allowed; + gint force_stereo; + gint xinerama_stereo; + NVCTRLAttributeValidValuesRec image_settings_valid; + gint image_settings_value; + gint aa_line_gamma; + gint force_generic_cpu; + gint show_sli_hud; + + ReturnStatus ret_sync_to_vblank; + ReturnStatus ret_flipping_allowed; + ReturnStatus ret_force_stereo; + ReturnStatus ret_xinerama_stereo; + ReturnStatus ret_image_settings; + ReturnStatus ret_aa_line_gama; + ReturnStatus ret_force_generic_cpu; + ReturnStatus ret_show_sli_hud; + + /* Query OpenGL settings */ + + ret_sync_to_vblank = + NvCtrlGetAttribute(handle, NV_CTRL_SYNC_TO_VBLANK, &sync_to_vblank); + + ret_flipping_allowed = + NvCtrlGetAttribute(handle, NV_CTRL_FLIPPING_ALLOWED, + &flipping_allowed); + + ret_force_stereo = + NvCtrlGetAttribute(handle, NV_CTRL_FORCE_STEREO, &force_stereo); + + ret_xinerama_stereo = + NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA_STEREO, &xinerama_stereo); + + ret_image_settings = + NvCtrlGetValidAttributeValues(handle, NV_CTRL_IMAGE_SETTINGS, + &image_settings_valid); + if ((ret_image_settings == NvCtrlSuccess) && + (image_settings_valid.type == ATTRIBUTE_TYPE_RANGE)) { + ret_image_settings = + NvCtrlGetAttribute(handle, NV_CTRL_IMAGE_SETTINGS, + &image_settings_value); + } else { + ret_image_settings = NvCtrlError; + } + + ret_aa_line_gama = NvCtrlGetAttribute(handle, NV_CTRL_OPENGL_AA_LINE_GAMMA, + &aa_line_gamma); + + ret_force_generic_cpu = NvCtrlGetAttribute(handle, + NV_CTRL_FORCE_GENERIC_CPU, + &force_generic_cpu); + + ret_show_sli_hud = NvCtrlGetAttribute(handle, NV_CTRL_SHOW_SLI_HUD, + &show_sli_hud); + + /* There are no OpenGL settings to change (OpenGL disabled?) */ + if ((ret_sync_to_vblank != NvCtrlSuccess) && + (ret_flipping_allowed != NvCtrlSuccess) && + (ret_force_stereo != NvCtrlSuccess) && + (ret_xinerama_stereo != NvCtrlSuccess) && + (ret_image_settings != NvCtrlSuccess) && + (ret_aa_line_gama != NvCtrlSuccess) && + (ret_force_generic_cpu != NvCtrlSuccess) && + (ret_show_sli_hud != NvCtrlSuccess)) { + return NULL; + } object = g_object_new(CTK_TYPE_OPENGL, NULL); @@ -197,15 +261,15 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, * retrace. */ - ret = NvCtrlGetAttribute(handle, NV_CTRL_SYNC_TO_VBLANK, &val); - if (ret == NvCtrlSuccess) { + if (ret_sync_to_vblank == NvCtrlSuccess) { label = gtk_label_new("Sync to VBlank"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), + sync_to_vblank); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -229,15 +293,15 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, * allow flipping */ - ret = NvCtrlGetAttribute(handle, NV_CTRL_FLIPPING_ALLOWED, &val); - if (ret == NvCtrlSuccess) { + if (ret_flipping_allowed == NvCtrlSuccess) { label = gtk_label_new("Allow Flipping"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), + flipping_allowed); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -259,15 +323,15 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, ctk_opengl->allow_flipping_button = check_button; } - ret = NvCtrlGetAttribute(handle, NV_CTRL_FORCE_STEREO, &val); - if (ret == NvCtrlSuccess) { + if (ret_force_stereo == NvCtrlSuccess) { label = gtk_label_new("Force Stereo Flipping"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), + force_stereo); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -286,15 +350,15 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, ctk_opengl->force_stereo_button = check_button; } - ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA_STEREO, &val); - if (ret == NvCtrlSuccess) { + if (ret_xinerama_stereo == NvCtrlSuccess) { label = gtk_label_new("Allow Xinerama Stereo Flipping"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), + xinerama_stereo); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -317,10 +381,7 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, * Image Quality settings. */ - ret = NvCtrlGetValidAttributeValues(handle, NV_CTRL_IMAGE_SETTINGS, &valid); - - if ((ret == NvCtrlSuccess) && (valid.type == ATTRIBUTE_TYPE_RANGE) && - (NvCtrlGetAttribute(handle, NV_CTRL_IMAGE_SETTINGS, &val) == NvCtrlSuccess)) { + if (ret_image_settings == NvCtrlSuccess) { frame = gtk_frame_new("Image Settings"); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 3); @@ -329,8 +390,9 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, gtk_container_set_border_width(GTK_CONTAINER(hbox), FRAME_PADDING); gtk_container_add(GTK_CONTAINER(frame), hbox); - scale = gtk_hscale_new_with_range(valid.u.range.min, valid.u.range.max, 1); - gtk_range_set_value(GTK_RANGE(scale), val); + scale = gtk_hscale_new_with_range(image_settings_valid.u.range.min, + image_settings_valid.u.range.max, 1); + gtk_range_set_value(GTK_RANGE(scale), image_settings_value); gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE); gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP); @@ -377,18 +439,14 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, * NV_CTRL_OPENGL_AA_LINE_GAMMA */ - ret = NvCtrlGetAttribute(ctk_opengl->handle, - NV_CTRL_OPENGL_AA_LINE_GAMMA, - &aa_line_gamma_value); - - if (ret == NvCtrlSuccess) { + if (ret_aa_line_gama == NvCtrlSuccess) { label = gtk_label_new("Enable gamma correction for antialiased lines"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), - aa_line_gamma_value == + aa_line_gamma == NV_CTRL_OPENGL_AA_LINE_GAMMA_ENABLE); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -416,18 +474,14 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, * Force Generic CPU */ - ret = NvCtrlGetAttribute(ctk_opengl->handle, - NV_CTRL_FORCE_GENERIC_CPU, - &force_generic_cpu_value); - - if (ret == NvCtrlSuccess) { + if (ret_force_generic_cpu == NvCtrlSuccess) { label = gtk_label_new("Disable use of enhanced CPU instruction sets"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), - force_generic_cpu_value == + force_generic_cpu == NV_CTRL_FORCE_GENERIC_CPU_ENABLE); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); @@ -448,15 +502,15 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, ctk_opengl->force_generic_cpu_button = check_button; } - ret = NvCtrlGetAttribute(handle, NV_CTRL_SHOW_SLI_HUD, &val); - if (ret == NvCtrlSuccess) { + if (ret_show_sli_hud == NvCtrlSuccess) { label = gtk_label_new("Enable SLI Heads-Up-Display"); check_button = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(check_button), label); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), + show_sli_hud); gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0); diff --git a/src/gtk+-2.x/ctkscreen.c b/src/gtk+-2.x/ctkscreen.c new file mode 100644 index 0000000..0931328 --- /dev/null +++ b/src/gtk+-2.x/ctkscreen.c @@ -0,0 +1,474 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <gtk/gtk.h> +#include "NvCtrlAttributes.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xlib.h> +#include <X11/extensions/Xrandr.h> + + +#include "big_banner_penguin.h" +#include "big_banner_bsd.h" +#include "big_banner_sun.h" + +#include "image.h" + +#include "ctkscreen.h" +#include "ctkhelp.h" +#include "ctkutils.h" +#include "ctkimage.h" + +void ctk_screen_event_handler(GtkWidget *widget, + XRRScreenChangeNotifyEvent *ev, + gpointer data); + +static void associated_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data); + +GType ctk_screen_get_type( + void +) +{ + static GType ctk_screen_type = 0; + + if (!ctk_screen_type) { + static const GTypeInfo info_ctk_screen = { + sizeof (CtkScreenClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CtkScreen), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_screen_type = + g_type_register_static(GTK_TYPE_VBOX, + "CtkScreen", &info_ctk_screen, 0); + } + + return ctk_screen_type; +} + + + +static gchar *make_display_device_list(NvCtrlAttributeHandle *handle, + unsigned int display_devices) +{ + gchar *displays = NULL; + gchar *type; + gchar *name; + gchar *tmp_str; + unsigned int mask; + ReturnStatus ret; + + + /* List of Display Device connected on GPU */ + + for (mask = 1; mask; mask <<= 1) { + + if (!(mask & display_devices)) continue; + + type = display_device_mask_to_display_device_name(mask); + name = NULL; + + ret = + NvCtrlGetStringDisplayAttribute(handle, + mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &name); + if (ret != NvCtrlSuccess) { + tmp_str = g_strdup_printf("Unknown (%s)", type); + } else { + tmp_str = g_strdup_printf("%s (%s)", name, type); + XFree(name); + } + free(type); + + if (displays) { + name = g_strdup_printf("%s,\n%s", tmp_str, displays); + g_free(displays); + g_free(tmp_str); + } else { + name = tmp_str; + } + displays = name; + } + + if (!displays) { + displays = g_strdup("None"); + } + + return displays; + +} /* make_display_device_list() */ + + + +/* + * Calculations of the screen dimensions and resolution are based on + * the dxpyinfo utility code. + * + * Copyright Information for xdpyinfo: + * + *********************************************************************** + * + * xdpyinfo - print information about X display connecton + * + * +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 THE +OPEN GROUP 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 The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Jim Fulton, MIT X Consortium + * + *********************************************************************** + * + */ + +GtkWidget* ctk_screen_new(NvCtrlAttributeHandle *handle, + CtkEvent *ctk_event) +{ + GObject *object; + CtkScreen *ctk_screen; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *banner; + GtkWidget *hseparator; + GtkWidget *table; + + ReturnStatus ret; + + gchar *screen_number; + gchar *display_name; + gchar *dimensions; + gchar *resolution; + gchar *depth; + gchar *gpus; + gchar *displays; + + double xres, yres; + gint os_val; + + unsigned int display_devices; + + int *pData; + int len; + int i; + + /* + * get the data that we will display below + */ + + screen_number = g_strdup_printf("%d", NvCtrlGetTargetId(handle)); + + display_name = NvCtrlGetDisplayName(handle); + + dimensions = g_strdup_printf("%dx%d pixels (%dx%d millimeters)", + NvCtrlGetScreenWidth(handle), + NvCtrlGetScreenHeight(handle), + NvCtrlGetScreenWidthMM(handle), + NvCtrlGetScreenHeightMM(handle)); + + /* + * there are 2.54 centimeters to an inch; so there are 25.4 millimeters. + * + * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch)) + * = N pixels / (M inch / 25.4) + * = N * 25.4 pixels / M inch + */ + + xres = (((double) NvCtrlGetScreenWidth(handle)) * 25.4) / + ((double) NvCtrlGetScreenWidthMM(handle)); + + yres = (((double) NvCtrlGetScreenHeight(handle)) * 25.4) / + ((double) NvCtrlGetScreenHeightMM(handle)); + + resolution = g_strdup_printf("%dx%d dots per inch", + (int) (xres + 0.5), + (int) (yres + 0.5)); + + depth = g_strdup_printf("%d", NvCtrlGetScreenPlanes(handle)); + + /* get the list of GPUs driving this X screen */ + + gpus = NULL; + ret = NvCtrlGetBinaryAttribute(handle, + 0, + NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, + (unsigned char **)(&pData), + &len); + if (ret == NvCtrlSuccess) { + for (i = 1; i <= pData[0]; i++) { + gchar *tmp_str; + gchar *gpu_name; + + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_PRODUCT_NAME, + &gpu_name); + if (ret != NvCtrlSuccess) { + gpu_name = "Unknown"; + } + if (gpus) { + tmp_str = g_strdup_printf("%s,\n%s (GPU %d)", + gpus, gpu_name, pData[i]); + } else { + tmp_str = g_strdup_printf("%s (GPU %d)", gpu_name, pData[i]); + } + if (ret == NvCtrlSuccess) { + XFree(gpu_name); + } + g_free(gpus); + gpus = tmp_str; + } + if (!gpus) { + gpus = g_strdup("None"); + } + } + + /* get the list of Display Devices displaying this X screen */ + + displays = NULL; + ret = NvCtrlGetAttribute(handle, NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, + (int *)&display_devices); + if (ret == NvCtrlSuccess) { + displays = make_display_device_list(handle, display_devices); + } + + /* NV_CTRL_OPERATING_SYSTEM */ + + os_val = NV_CTRL_OPERATING_SYSTEM_LINUX; + ret = NvCtrlGetAttribute(handle, NV_CTRL_OPERATING_SYSTEM, &os_val); + + + /* now, create the object */ + + object = g_object_new(CTK_TYPE_SCREEN, NULL); + ctk_screen = CTK_SCREEN(object); + + /* cache the attribute handle */ + + ctk_screen->handle = handle; + + /* set container properties of the object */ + + gtk_box_set_spacing(GTK_BOX(ctk_screen), 10); + + /* banner */ + + if (os_val == NV_CTRL_OPERATING_SYSTEM_LINUX) { + banner = ctk_banner_image_new(&big_banner_penguin_image); + } else if (os_val == NV_CTRL_OPERATING_SYSTEM_FREEBSD) { + banner = ctk_banner_image_new(&big_banner_bsd_image); + } else if (os_val == NV_CTRL_OPERATING_SYSTEM_SUNOS) { + banner = ctk_banner_image_new(&big_banner_sun_image); + } else { + banner = ctk_banner_image_new(&big_banner_penguin_image); + } + gtk_box_pack_start(GTK_BOX(ctk_screen), banner, FALSE, FALSE, 0); + + /* + * Screen information: TOP->MIDDLE - LEFT->RIGHT + * + * This displays basic X Screen information, including + * the X Screen number, the display connection used to + * talk to the X Screen, dimensions, resolution, depth (planes) + * the list of GPUs driving the X Screen and the list of + * display devices displaying the X Screen. + */ + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_screen), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("X Screen Information"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); + + table = gtk_table_new(16, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + add_table_row(table, 0, 0, 0.5, "Screen Number:", 0, 0.5, screen_number); + add_table_row(table, 1, 0, 0.5, "Display Name:", 0, 0.5, display_name); + /* spacing */ + ctk_screen->dimensions = + add_table_row(table, 5, 0, 0.5, "Dimensions:", 0, 0.5, dimensions); + add_table_row(table, 6, 0, 0.5, "Resolution:", 0, 0.5, resolution); + add_table_row(table, 7, 0, 0.5, "Depth:", 0, 0.5, depth); + /* spacing */ + add_table_row(table, 11, 0, 0, "GPUs:", 0, 0, gpus); + /* spacing */ + ctk_screen->displays = + add_table_row(table, 15, 0, 0, "Displays:", 0, 0, displays); + + g_free(screen_number); + free(display_name); + g_free(dimensions); + g_free(resolution); + g_free(depth); + g_free(gpus); + g_free(displays); + + /* Handle updates to the list of associated display devices */ + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_ASSOCIATED_DISPLAY_DEVICES), + G_CALLBACK(associated_displays_received), + (gpointer) ctk_screen); + + /* Setup widget to handle XRRScreenChangeNotify events */ + g_signal_connect(G_OBJECT(ctk_event), "CTK_EVENT_RRScreenChangeNotify", + G_CALLBACK(ctk_screen_event_handler), + (gpointer) ctk_screen); + + gtk_widget_show_all(GTK_WIDGET(object)); + + return GTK_WIDGET(object); +} + + +GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *table, + const gchar *screen_name) +{ + GtkTextIter i; + GtkTextBuffer *b; + + b = gtk_text_buffer_new(table); + + gtk_text_buffer_get_iter_at_offset(b, &i, 0); + + ctk_help_title(b, &i, "X Screen Information Help"); + + ctk_help_para(b, &i, "This page in the NVIDIA " + "X Server Control Panel describes basic " + "information about the X Screen '%s'.", + screen_name); + + ctk_help_heading(b, &i, "Screen Number"); + ctk_help_para(b, &i, "This is the X Screen number."); + + ctk_help_heading(b, &i, "Display Name"); + ctk_help_para(b, &i, "This is the display connection string used to " + "communicate with the X Screen on the X Server."); + + ctk_help_heading(b, &i, "Dimensions"); + ctk_help_para(b, &i, "This displays the X Screen's horizontal and " + "vertical dimensions in pixels and millimeters."); + + ctk_help_heading(b, &i, "Resolution"); + ctk_help_para(b, &i, "This is the resolution (in dots per inch) of the " + "X Screen."); + + ctk_help_heading(b, &i, "Depth"); + ctk_help_para(b, &i, "This is the number of planes (depth) the X Screen " + "has available."); + + ctk_help_heading(b, &i, "GPUs"); + ctk_help_para(b, &i, "This is the list of GPUs that drive this X Screen."); + + ctk_help_heading(b, &i, "Display Devices"); + ctk_help_para(b, &i, "This is the list of Display Devices (CRTs, TVs etc) " + "enabled on this X Screen."); + + ctk_help_finish(b); + + return b; +} + + + +/* + * When XConfigureRequest events happens outside of the control panel, + * they are trapped by this function so the gui can be updated + * with the new screen information. + */ +void ctk_screen_event_handler(GtkWidget *widget, + XRRScreenChangeNotifyEvent *ev, + gpointer data) +{ + CtkScreen *ctk_screen = (CtkScreen *) data; + + gchar *dimensions = g_strdup_printf("%dx%d pixels (%dx%d millimeters)", + ev->width, ev->height, + ev->mwidth, ev->mheight); + + gtk_label_set_text(GTK_LABEL(ctk_screen->dimensions), + dimensions); + + g_free(dimensions); + +} /* ctk_screen_event_handler() */ + + + +/* + * When the list of associated displays on this screen changes, we should + * update the display device list shown on the page. + */ +static void associated_displays_received(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + CtkEventStruct *event_struct = (CtkEventStruct *) arg1; + CtkScreen *ctk_object = CTK_SCREEN(user_data); + unsigned int associated_displays = event_struct->value; + gchar *str; + + str = make_display_device_list(ctk_object->handle, associated_displays); + + gtk_label_set_text(GTK_LABEL(ctk_object->displays), str); + + g_free(str); + +} /* associated_displays_received() */ diff --git a/src/gtk+-2.x/ctkscreen.h b/src/gtk+-2.x/ctkscreen.h new file mode 100644 index 0000000..75f8422 --- /dev/null +++ b/src/gtk+-2.x/ctkscreen.h @@ -0,0 +1,80 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_SCREEN_H__ +#define __CTK_SCREEN_H__ + +#include <gtk/gtk.h> + +#include "NvCtrlAttributes.h" +#include "ctkevent.h" + +G_BEGIN_DECLS + +#define CTK_TYPE_SCREEN (ctk_screen_get_type()) + +#define CTK_SCREEN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_SCREEN, CtkScreen)) + +#define CTK_SCREEN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_SCREEN, CtkScreenClass)) + +#define CTK_IS_SCREEN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_SCREEN)) + +#define CTK_IS_SCREEN_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_SCREEN)) + +#define CTK_SCREEN_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_SCREEN, CtkScreenClass)) + + +typedef struct _CtkScreen CtkScreen; +typedef struct _CtkScreenClass CtkScreenClass; + +struct _CtkScreen +{ + GtkVBox parent; + + NvCtrlAttributeHandle *handle; + + GtkWidget *dimensions; + GtkWidget *displays; +}; + +struct _CtkScreenClass +{ + GtkVBoxClass parent_class; +}; + +GType ctk_screen_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_screen_new (NvCtrlAttributeHandle *handle, + CtkEvent *ctk_event); + +GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *, const gchar *); + +G_END_DECLS + +#endif /* __CTK_SCREEN_H__ */ + diff --git a/src/gtk+-2.x/ctkserver.c b/src/gtk+-2.x/ctkserver.c new file mode 100644 index 0000000..32eba03 --- /dev/null +++ b/src/gtk+-2.x/ctkserver.c @@ -0,0 +1,496 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <stdlib.h> /* malloc */ +#include <stdio.h> /* snprintf */ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <X11/Xlib.h> + +#include "big_banner_penguin.h" +#include "big_banner_bsd.h" +#include "big_banner_sun.h" +#include "ctkimage.h" + +#include "ctkserver.h" +#include "ctkevent.h" +#include "ctkhelp.h" +#include "ctkutils.h" + + +GType ctk_server_get_type(void) +{ + static GType ctk_server_type = 0; + + if (!ctk_server_type) { + static const GTypeInfo ctk_server_info = { + sizeof (CtkServerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(CtkServer), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_server_type = g_type_register_static + (GTK_TYPE_VBOX, "CtkServer", &ctk_server_info, 0); + } + + return ctk_server_type; +} + + + +/* + * Code taken and modified from xdpyinfo.c + * + * Copyright Information for xdpyinfo: + * + *********************************************************************** + * + * xdpyinfo - print information about X display connecton + * + * +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 THE +OPEN GROUP 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 The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Jim Fulton, MIT X Consortium + * + *********************************************************************** + * + */ +static gchar * get_server_vendor_version(NvCtrlAttributeHandle *handle) +{ + int vendrel = NvCtrlGetVendorRelease(handle); + char *vendstr = NvCtrlGetServerVendor(handle); + gchar *version = NULL; + gchar *tmp; + + if (vendrel < 0 || !vendstr) return NULL; + + /* XFree86 */ + + if (g_strrstr(vendstr, "XFree86")) { + + if (vendrel < 336) { + /* + * vendrel was set incorrectly for 3.3.4 and 3.3.5, so handle + * those cases here. + */ + version = g_strdup_printf("%d.%d.%d", + vendrel / 100, + (vendrel / 10) % 10, + vendrel % 10); + } else if (vendrel < 3900) { + /* 3.3.x versions, other than the exceptions handled above */ + if (((vendrel / 10) % 10) || (vendrel % 10)) { + if (vendrel % 10) { + version = g_strdup_printf("%d.%d.%d.%d", + vendrel / 1000, + (vendrel / 100) % 10, + (vendrel / 10) % 10, + vendrel % 10); + } else { + version = g_strdup_printf("%d.%d.%d", + vendrel / 1000, + (vendrel / 100) % 10, + (vendrel / 10) % 10); + } + } else { + version = g_strdup_printf("%d.%d", + vendrel / 1000, + (vendrel / 100) % 10); + } + } else if (vendrel < 40000000) { + /* 4.0.x versions */ + if (vendrel % 10) { + version = g_strdup_printf("%d.%d.%d", + vendrel / 1000, + (vendrel / 10) % 10, + vendrel % 10); + } else { + version = g_strdup_printf("%d.%d", + vendrel / 1000, + (vendrel / 10) % 10); + } + } else { + /* post-4.0.x */ + if (vendrel % 1000) { + version = g_strdup_printf("%d.%d.%d.%d", + vendrel / 10000000, + (vendrel / 100000) % 100, + (vendrel / 1000) % 100, + vendrel % 1000); + } else { + version = g_strdup_printf("%d.%d.%d", + vendrel / 10000000, + (vendrel / 100000) % 100, + (vendrel / 1000) % 100); + } + } + } + + /* X.Org */ + + if (g_strrstr(vendstr, "X.Org")) { + tmp = g_strdup_printf("%d.%d.%d", + vendrel / 10000000, + (vendrel / 100000) % 100, + (vendrel / 1000) % 100); + if (vendrel % 1000) { + version = g_strdup_printf("%s.%d", tmp, vendrel % 1000); + } else { + version = g_strdup(tmp); + } + + g_free(tmp); + } + + /* DMX */ + + if (g_strrstr(vendstr, "DMX")) { + int major, minor, year, month, day; + + major = vendrel / 100000000; + vendrel -= major * 100000000; + minor = vendrel / 1000000; + vendrel -= minor * 1000000; + year = vendrel / 10000; + vendrel -= year * 10000; + month = vendrel / 100; + vendrel -= month * 100; + day = vendrel; + + /* Add other epoch tests here */ + if (major > 0 && minor > 0) year += 2000; + + /* Do some sanity tests in case there is + * another server with the same vendor + * string. That server could easily use + * values < 100000000, which would have + * the effect of keeping our major + * number 0. */ + if (major > 0 && major <= 20 + && minor >= 0 && minor <= 99 + && year >= 2000 + && month >= 1 && month <= 12 + && day >= 1 && day <= 31) + version = g_strdup_printf("%d.%d.%04d%02d%02d\n", + major, minor, year, month, day); + } + + /* Add the vendor release number */ + + if (version) { + tmp = g_strdup_printf("%s (%d)", version, vendrel); + } else { + tmp = g_strdup_printf("%d", vendrel); + } + g_free(version); + version = tmp; + + return version; +} + + + +/* + * CTK Server widget creation + * + */ +GtkWidget* ctk_server_new(NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config) +{ + GObject *object; + CtkServer *ctk_object; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *banner; + GtkWidget *hseparator; + GtkWidget *table; + + gchar *os; + gchar *arch; + gchar *driver_version; + + gchar *dname = NvCtrlGetDisplayName(handle); + gchar *display_name; + gchar *server_version; + gchar *vendor_str; + gchar *vendor_ver; + gchar *num_screens; + + ReturnStatus ret; + int tmp, os_val; + int xinerama_enabled; + + /* + * get the data that we will display below + * + */ + + /* NV_CTRL_XINERAMA */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA, &xinerama_enabled); + if (ret != NvCtrlSuccess) { + xinerama_enabled = FALSE; + } + + /* NV_CTRL_OPERATING_SYSTEM */ + + os_val = NV_CTRL_OPERATING_SYSTEM_LINUX; + ret = NvCtrlGetAttribute(handle, NV_CTRL_OPERATING_SYSTEM, &os_val); + os = NULL; + if (ret == NvCtrlSuccess) { + if (os_val == NV_CTRL_OPERATING_SYSTEM_LINUX) os = "Linux"; + else if (os_val == NV_CTRL_OPERATING_SYSTEM_FREEBSD) os = "FreeBSD"; + else if (os_val == NV_CTRL_OPERATING_SYSTEM_SUNOS) os = "SunOS"; + } + if (!os) os = "Unknown"; + + /* NV_CTRL_ARCHITECTURE */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_ARCHITECTURE, &tmp); + arch = NULL; + if (ret == NvCtrlSuccess) { + if (tmp == NV_CTRL_ARCHITECTURE_X86) arch = "x86"; + else if (tmp == NV_CTRL_ARCHITECTURE_X86_64) arch = "x86_64"; + else if (tmp == NV_CTRL_ARCHITECTURE_IA64) arch = "ia64"; + } + if (!arch) arch = "Unknown"; + os = g_strdup_printf("%s-%s", os, arch); + + /* NV_CTRL_STRING_NVIDIA_DRIVER_VERSION */ + + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, + &driver_version); + if (ret != NvCtrlSuccess) driver_version = NULL; + + /* Display Name */ + + display_name = nv_standardize_screen_name(dname, -2); + + /* X Server Version */ + + server_version = g_strdup_printf("%d.%d", + NvCtrlGetProtocolVersion(handle), + NvCtrlGetProtocolRevision(handle)); + + /* Server Vendor String */ + + vendor_str = g_strdup(NvCtrlGetServerVendor(handle)); + + /* Server Vendor Version */ + + vendor_ver = get_server_vendor_version(handle); + + /* # Logical X Screens */ + + if (xinerama_enabled) { + num_screens = g_strdup_printf("%d (Xinerama)", + NvCtrlGetScreenCount(handle)); + } else { + num_screens = g_strdup_printf("%d", NvCtrlGetScreenCount(handle)); + } + + + /* now, create the object */ + + object = g_object_new(CTK_TYPE_SERVER, NULL); + ctk_object = CTK_SERVER(object); + + /* cache the attribute handle */ + + ctk_object->handle = handle; + + /* set container properties of the object */ + + gtk_box_set_spacing(GTK_BOX(ctk_object), 10); + + /* banner */ + + if (os_val == NV_CTRL_OPERATING_SYSTEM_LINUX) { + banner = ctk_banner_image_new(&big_banner_penguin_image); + } else if (os_val == NV_CTRL_OPERATING_SYSTEM_FREEBSD) { + banner = ctk_banner_image_new(&big_banner_bsd_image); + } else if (os_val == NV_CTRL_OPERATING_SYSTEM_SUNOS) { + banner = ctk_banner_image_new(&big_banner_sun_image); + } else { + banner = ctk_banner_image_new(&big_banner_penguin_image); + } + gtk_box_pack_start(GTK_BOX(ctk_object), banner, FALSE, FALSE, 0); + + /* + * This displays basic System information, including + * display name, Operating system type and the NVIDIA driver version. + */ + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_object), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("System Information"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); + + table = gtk_table_new(2, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + add_table_row(table, 0, + 0, 0.5, "Operating System:", 0, 0.5, os); + add_table_row(table, 1, + 0, 0.5, "NVIDIA Driver Version:", 0, 0.5, driver_version); + + /* + * This displays basic X Server information, including + * version number, vendor information and the number of + * X Screens. + */ + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("X Server Information"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); + + table = gtk_table_new(11, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + add_table_row(table, 0, + 0, 0.5, "Display Name:", 0, 0.5, display_name); + /* separator */ + add_table_row(table, 4, + 0, 0.5, "Server Version Number:", 0, 0.5, server_version); + add_table_row(table, 5, + 0, 0.5, "Server Vendor String:", 0, 0.5, vendor_str); + add_table_row(table, 6, + 0, 0.5, "Server Vendor Version:", 0, 0.5, vendor_ver); + /* separator */ + add_table_row(table, 10, + 0, 0, "X Screens:", 0, 0, num_screens); + + g_free(display_name); + g_free(os); + XFree(driver_version); + + g_free(server_version); + g_free(vendor_str); + g_free(vendor_ver); + g_free(num_screens); + + gtk_widget_show_all(GTK_WIDGET(object)); + + return GTK_WIDGET(object); +} + + + +/* + * Server Information help screen + */ +GtkTextBuffer *ctk_server_create_help(GtkTextTagTable *table, + CtkServer *ctk_object) +{ + GtkTextIter i; + GtkTextBuffer *b; + + b = gtk_text_buffer_new(table); + + gtk_text_buffer_get_iter_at_offset(b, &i, 0); + + ctk_help_title(b, &i, "X Server Information Help"); + + ctk_help_heading(b, &i, "Operating System"); + ctk_help_para(b, &i, "This is the operating system on which the NVIDIA " + "X driver is running; possible values are " + "'Linux', 'FreeBSD', and 'SunOS'. This also specifies the " + "platform on which the operating system is running, such " + "as x86, x86_64, or ia64"); + + ctk_help_heading(b, &i, "NVIDIA Driver Version"); + ctk_help_para(b, &i, "This is the version of the NVIDIA Accelerated " + "Graphics Driver currently in use."); + + ctk_help_heading(b, &i, "Display Name"); + ctk_help_para(b, &i, "This is the display connection string used to " + "communicate with the X Server."); + + ctk_help_heading(b, &i, "X Server Version"); + ctk_help_para(b, &i, "This is the version number of the X Server."); + + ctk_help_heading(b, &i, "X Server Vendor String"); + ctk_help_para(b, &i, "This is the X Server vendor information string."); + + ctk_help_heading(b, &i, "X Server Vendor Version"); + ctk_help_para(b, &i, "This is the vertsion number of the X Server " + "vendor."); + + ctk_help_heading(b, &i, "X Screens"); + ctk_help_para(b, &i, "This is the number of X Screens on the " + "display. (When Xinerama is enabled this is always 1)."); + + ctk_help_finish(b); + + return b; +} diff --git a/src/gtk+-2.x/ctkserver.h b/src/gtk+-2.x/ctkserver.h new file mode 100644 index 0000000..fff97e9 --- /dev/null +++ b/src/gtk+-2.x/ctkserver.h @@ -0,0 +1,77 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2004 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_SERVER_H__ +#define __CTK_SERVER_H__ + +#include "ctkevent.h" +#include "ctkconfig.h" + +G_BEGIN_DECLS + +#define CTK_TYPE_SERVER (ctk_server_get_type()) + +#define CTK_SERVER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_SERVER, \ + CtkServer)) + +#define CTK_SERVER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_SERVER, \ + CtkServerClass)) + +#define CTK_IS_SERVER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_SERVER)) + +#define CTK_IS_SERVER_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_SERVER)) + +#define CTK_SERVER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_SERVER, \ + CtkServerClass)) + + +typedef struct _CtkServer +{ + GtkVBox parent; + + CtkConfig *ctk_config; + NvCtrlAttributeHandle *handle; + +} CtkServer; + +typedef struct _CtkServerClass +{ + GtkVBoxClass parent_class; +} CtkServerClass; + + +GType ctk_server_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_server_new (NvCtrlAttributeHandle *, CtkConfig *); + +GtkTextBuffer *ctk_server_create_help(GtkTextTagTable *, + CtkServer *); + +G_END_DECLS + +#endif /* __CTK_SERVER_H__ */ diff --git a/src/gtk+-2.x/ctkthermal.c b/src/gtk+-2.x/ctkthermal.c index 6f9b327..b7ca619 100644 --- a/src/gtk+-2.x/ctkthermal.c +++ b/src/gtk+-2.x/ctkthermal.c @@ -291,11 +291,15 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle, /* Register a timer callback to update the temperatures */ + s = g_strdup_printf("Thermal Monitor (GPU %d)", + NvCtrlGetTargetId(handle)); + ctk_config_add_timer(ctk_thermal->ctk_config, DEFAULT_UPDATE_THERMAL_INFO_TIME_INTERVAL, - "Thermal Monitor", + s, (GSourceFunc) update_thermal_info, (gpointer) ctk_thermal); + g_free(s); update_thermal_info(ctk_thermal); gtk_widget_show_all(GTK_WIDGET(ctk_thermal)); @@ -341,7 +345,8 @@ void ctk_thermal_start_timer(GtkWidget *widget) /* Start the thermal timer */ ctk_config_start_timer(ctk_thermal->ctk_config, - (GSourceFunc) update_thermal_info); + (GSourceFunc) update_thermal_info, + (gpointer) ctk_thermal); } void ctk_thermal_stop_timer(GtkWidget *widget) @@ -351,5 +356,6 @@ void ctk_thermal_stop_timer(GtkWidget *widget) /* Stop the thermal timer */ ctk_config_stop_timer(ctk_thermal->ctk_config, - (GSourceFunc) update_thermal_info); + (GSourceFunc) update_thermal_info, + (gpointer) ctk_thermal); } diff --git a/src/gtk+-2.x/ctkui.c b/src/gtk+-2.x/ctkui.c index 456875e..5ee98fe 100644 --- a/src/gtk+-2.x/ctkui.c +++ b/src/gtk+-2.x/ctkui.c @@ -42,9 +42,14 @@ char *ctk_get_display(void) return gdk_get_display(); } -void ctk_main(NvCtrlAttributeHandle **attribute_handles, - int num_screens, ParsedAttribute *p, ConfigProperties *conf) +void ctk_main(NvCtrlAttributeHandle **screen_handles, int num_screen_handles, + NvCtrlAttributeHandle **gpu_handles, int num_gpu_handles, + NvCtrlAttributeHandle **vcsc_handles, int num_vcsc_handles, + ParsedAttribute *p, ConfigProperties *conf) { - ctk_window_new(attribute_handles, num_screens, p, conf); + ctk_window_new(screen_handles, num_screen_handles, + gpu_handles, num_gpu_handles, + vcsc_handles, num_vcsc_handles, + p, conf); gtk_main(); } diff --git a/src/gtk+-2.x/ctkui.h b/src/gtk+-2.x/ctkui.h index c186ead..2993565 100644 --- a/src/gtk+-2.x/ctkui.h +++ b/src/gtk+-2.x/ctkui.h @@ -33,7 +33,10 @@ void ctk_init(int *argc, char **argv[]); char *ctk_get_display(void); -void ctk_main(NvCtrlAttributeHandle **, int, ParsedAttribute*, +void ctk_main(NvCtrlAttributeHandle **, int, + NvCtrlAttributeHandle **, int, + NvCtrlAttributeHandle **, int, + ParsedAttribute*, ConfigProperties*); #endif /* __CTK_UI_H__ */ diff --git a/src/gtk+-2.x/ctkutils.c b/src/gtk+-2.x/ctkutils.c index 10900d7..28a8f85 100644 --- a/src/gtk+-2.x/ctkutils.c +++ b/src/gtk+-2.x/ctkutils.c @@ -29,14 +29,18 @@ GtkWidget *add_table_row(GtkWidget *table, const gint row, - const gint value_alignment, + const gfloat name_xalign, // 0 = left, 1 = right + const gfloat name_yalign, // 0 = top, 1 = bottom const gchar *name, + const gfloat value_xalign, + const gfloat value_yalign, const gchar *value) { GtkWidget *label; label = gtk_label_new(name); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), name_xalign, name_yalign); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -44,7 +48,8 @@ GtkWidget *add_table_row(GtkWidget *table, label = gtk_label_new("Unknown"); else label = gtk_label_new(value); - gtk_misc_set_alignment(GTK_MISC(label), value_alignment, 0.5); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), value_xalign, value_yalign); gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row + 1, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); diff --git a/src/gtk+-2.x/ctkutils.h b/src/gtk+-2.x/ctkutils.h index 586cc8b..0cc28cf 100644 --- a/src/gtk+-2.x/ctkutils.h +++ b/src/gtk+-2.x/ctkutils.h @@ -30,8 +30,9 @@ G_BEGIN_DECLS -GtkWidget *add_table_row(GtkWidget *, const gint, const gint, const gchar *, - const gchar *); +GtkWidget *add_table_row(GtkWidget *, const gint, + const gfloat, const gfloat, const gchar *, + const gfloat, const gfloat, const gchar *); G_END_DECLS diff --git a/src/gtk+-2.x/ctkvcsc.c b/src/gtk+-2.x/ctkvcsc.c new file mode 100644 index 0000000..60daf6e --- /dev/null +++ b/src/gtk+-2.x/ctkvcsc.c @@ -0,0 +1,255 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2006 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#include <stdlib.h> /* malloc */ +#include <stdio.h> /* snprintf */ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <X11/Xlib.h> + +#include "ctkimage.h" +#include "frame_lock_banner.h" + +#include "ctkvcsc.h" +#include "ctkevent.h" +#include "ctkhelp.h" +#include "ctkutils.h" + + +GType ctk_vcsc_get_type(void) +{ + static GType ctk_vcsc_type = 0; + + if (!ctk_vcsc_type) { + static const GTypeInfo ctk_vcsc_info = { + sizeof (CtkVcscClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof(CtkVcsc), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_vcsc_type = g_type_register_static + (GTK_TYPE_VBOX, "CtkVcsc", &ctk_vcsc_info, 0); + } + + return ctk_vcsc_type; +} + + + +/* + * CTK VCSC (Visual Computing System Controller) widget creation + * + */ +GtkWidget* ctk_vcsc_new(NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config) +{ + GObject *object; + CtkVcsc *ctk_object; + GtkWidget *label; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *banner; + GtkWidget *hseparator; + GtkWidget *table; + + gchar *product_name; + gchar *serial_number; + gchar *build_date; + gchar *product_id; + gchar *firmware_version; + gchar *hardware_version; + + ReturnStatus ret; + + /* + * get the static string data that we will display below + */ + + /* Product Name */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_PRODUCT_NAME, + &product_name); + if (ret != NvCtrlSuccess) { + product_name = g_strdup("Unable to determine"); + } + + /* Serial Number */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_SERIAL_NUMBER, + &serial_number); + if (ret != NvCtrlSuccess) { + serial_number = g_strdup("Unable to determine"); + } + + /* Build Date */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_BUILD_DATE, + &build_date); + if (ret != NvCtrlSuccess) { + build_date = g_strdup("Unable to determine"); + } + + /* Product ID */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_PRODUCT_ID, + &product_id); + if (ret != NvCtrlSuccess) { + product_id = g_strdup("Unable to determine"); + } + + /* Firmware Version */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_FIRMWARE_VERSION, + &firmware_version); + if (ret != NvCtrlSuccess) { + firmware_version = g_strdup("Unable to determine"); + } + + /* Hardware Version */ + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_VCSC_HARDWARE_VERSION, + &hardware_version); + if (ret != NvCtrlSuccess) { + hardware_version = g_strdup("Unable to determine"); + } + + + /* now, create the object */ + + object = g_object_new(CTK_TYPE_VCSC, NULL); + ctk_object = CTK_VCSC(object); + + /* cache the attribute handle */ + + ctk_object->handle = handle; + + /* set container properties of the object */ + + gtk_box_set_spacing(GTK_BOX(ctk_object), 10); + + /* banner */ + + banner = ctk_banner_image_new(&frame_lock_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_object), banner, FALSE, FALSE, 0); + + /* + * This displays basic System information, including + * display name, Operating system type and the NVIDIA driver version. + */ + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(ctk_object), vbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new("VCSC Information"); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5); + + table = gtk_table_new(5, 2, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 15); + + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + + add_table_row(table, 0, + 0, 0.5, "Product Name:", 0, 0.5, product_name); + add_table_row(table, 1, + 0, 0.5, "Serial Number:", 0, 0.5, serial_number); + add_table_row(table, 2, + 0, 0.5, "Build Date:", 0, 0.5, build_date); + add_table_row(table, 3, + 0, 0.5, "Product ID:", 0, 0.5, product_id); + add_table_row(table, 4, + 0, 0.5, "Firmware version:", 0, 0.5, firmware_version); + add_table_row(table, 5, + 0, 0.5, "Hardware version:", 0, 0.5, hardware_version); + + g_free(product_name); + g_free(serial_number); + g_free(build_date); + g_free(product_id); + g_free(firmware_version); + g_free(hardware_version); + + gtk_widget_show_all(GTK_WIDGET(object)); + + return GTK_WIDGET(object); +} + + + +/* + * VCSC help screen + */ +GtkTextBuffer *ctk_vcsc_create_help(GtkTextTagTable *table, + CtkVcsc *ctk_object) +{ + GtkTextIter i; + GtkTextBuffer *b; + + b = gtk_text_buffer_new(table); + + gtk_text_buffer_get_iter_at_offset(b, &i, 0); + + ctk_help_title(b, &i, "VCSC (Visual Computing System Controller) Help"); + + ctk_help_heading(b, &i, "Product Name"); + ctk_help_para(b, &i, "This is the product name of the VCSC system."); + + ctk_help_heading(b, &i, "Serial Number"); + ctk_help_para(b, &i, "This is the unique serial number of the VCSC " + "system."); + + ctk_help_heading(b, &i, "Build Date"); + ctk_help_para(b, &i, "This is the date the VCSC system was build, " + "shown in a 'week.year' format"); + + ctk_help_heading(b, &i, "Product ID"); + ctk_help_para(b, &i, "This identifies the VCSC configuration."); + + ctk_help_heading(b, &i, "Firmware Version"); + ctk_help_para(b, &i, "This is the firmware version currently running on " + "the VCSC system."); + + ctk_help_heading(b, &i, "Hardware Version"); + ctk_help_para(b, &i, "This is the hardware version of the VCSC system."); + + ctk_help_finish(b); + + return b; +} + diff --git a/src/gtk+-2.x/ctkvcsc.h b/src/gtk+-2.x/ctkvcsc.h new file mode 100644 index 0000000..b05a985 --- /dev/null +++ b/src/gtk+-2.x/ctkvcsc.h @@ -0,0 +1,77 @@ +/* + * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix + * and Linux systems. + * + * Copyright (C) 2006 NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of Version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2 + * of the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307, USA + * + */ + +#ifndef __CTK_VCSC_H__ +#define __CTK_VCSC_H__ + +#include "ctkevent.h" +#include "ctkconfig.h" + +G_BEGIN_DECLS + +#define CTK_TYPE_VCSC (ctk_vcsc_get_type()) + +#define CTK_VCSC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_VCSC, \ + CtkVcsc)) + +#define CTK_VCSC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_VCSC, \ + CtkVcscClass)) + +#define CTK_IS_VCSC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_VCSC)) + +#define CTK_IS_VCSC_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_VCSC)) + +#define CTK_VCSC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_VCSC, \ + CtkVcscClass)) + + +typedef struct _CtkVcsc +{ + GtkVBox parent; + + CtkConfig *ctk_config; + NvCtrlAttributeHandle *handle; + +} CtkVcsc; + +typedef struct _CtkVcscClass +{ + GtkVBoxClass parent_class; +} CtkVcscClass; + + +GType ctk_vcsc_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_vcsc_new (NvCtrlAttributeHandle *, CtkConfig *); + +GtkTextBuffer *ctk_vcsc_create_help(GtkTextTagTable *, + CtkVcsc *); + +G_END_DECLS + +#endif /* __CTK_VCSC_H__ */ diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c index 7ce9bfc..b1cf971 100644 --- a/src/gtk+-2.x/ctkwindow.c +++ b/src/gtk+-2.x/ctkwindow.c @@ -32,6 +32,7 @@ #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> #include <stdio.h> +#include <stdlib.h> #include "ctkwindow.h" @@ -40,7 +41,8 @@ #include "ctkgvo-csc.h" #include "ctkconfig.h" -#include "ctkdevice.h" +#include "ctkscreen.h" +#include "ctkgpu.h" #include "ctkcolorcorrection.h" #include "ctkxvideo.h" #include "ctkrandr.h" @@ -50,12 +52,15 @@ #include "ctkmultisample.h" #include "ctkthermal.h" #include "ctkclocks.h" +#include "ctkvcsc.h" -#include "ctkdisplaydevice.h" #include "ctkdisplaydevice-crt.h" #include "ctkdisplaydevice-tv.h" #include "ctkdisplaydevice-dfp.h" +#include "ctkdisplayconfig.h" +#include "ctkserver.h" + #include "ctkhelp.h" #include "ctkevent.h" #include "ctkconstants.h" @@ -73,6 +78,20 @@ enum { }; +typedef struct { + CtkWindow *window; + CtkEvent *event; + NvCtrlAttributeHandle *gpu_handle; + GtkTextTagTable *tag_table; + + GtkTreeIter parent_iter; + + GtkTreeIter *display_iters; + int num_displays; + +} UpdateDisplaysData; + + typedef void (*config_file_attributes_func_t)(GtkWidget *, ParsedAttribute *); typedef void (*select_widget_func_t)(GtkWidget *); typedef void (*unselect_widget_func_t)(GtkWidget *); @@ -94,11 +113,14 @@ static void save_settings_and_exit(CtkWindow *); static void add_special_config_file_attributes(CtkWindow *ctk_window); -static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help, - CtkWindow *ctk_window, GtkTreeIter *iter, +static void add_display_devices(CtkWindow *ctk_window, GtkTreeIter *iter, NvCtrlAttributeHandle *handle, CtkEvent *ctk_event, - GtkTextTagTable *tag_table); + GtkTextTagTable *tag_table, + UpdateDisplaysData *data); + +static void update_display_devices(GtkObject *object, gpointer arg1, + gpointer user_data); static GObjectClass *parent_class; @@ -173,7 +195,7 @@ static void ctk_window_real_destroy(GtkObject *object) /* - * close_button_clicked() - called when the + * close_button_clicked() - called when the "Quit" button is clicked. */ static void close_button_clicked(GtkButton *button, gpointer user_data) @@ -262,11 +284,11 @@ static void tree_selection_changed(GtkTreeSelection *selection, /* Call the unselect func for the existing widget, if any */ - if ( ctk_window->widget ) { + if (ctk_window->widget) { gtk_tree_model_get(model, &(ctk_window->iter), CTK_WINDOW_UNSELECT_WIDGET_FUNC_COLUMN, &unselect_func, -1); - if ( unselect_func ) { + if (unselect_func) { (*unselect_func)(ctk_window->widget); } } @@ -345,7 +367,12 @@ static gboolean tree_view_key_event(GtkWidget *tree_view, GdkEvent *event, * ctk_window_new() - create a new CtkWindow widget */ -GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, +GtkWidget *ctk_window_new(NvCtrlAttributeHandle **screen_handles, + gint num_screen_handles, + NvCtrlAttributeHandle **gpu_handles, + gint num_gpu_handles, + NvCtrlAttributeHandle **vcsc_handles, + gint num_vcsc_handles, ParsedAttribute *p, ConfigProperties *conf) { GObject *object; @@ -380,8 +407,6 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, ctk_window = CTK_WINDOW(object); gtk_container_set_border_width(GTK_CONTAINER(ctk_window), CTK_WINDOW_PAD); - ctk_window->handles = handles; - ctk_window->num_handles = num_handles; ctk_window->attribute_list = p; /* create the config object */ @@ -523,21 +548,70 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, ctk_window->page_viewer = hbox; ctk_window->page = NULL; + + /* X Server info & configuration */ + + if (num_screen_handles) { + + NvCtrlAttributeHandle *screen_handle = NULL; + GtkWidget *child; + int i; + + /* + * XXX For now, just use the first handle in the list + * to communicate with the X server for these two + * pages. + */ + + for (i = 0 ; i < num_screen_handles; i++) { + if (screen_handles[i]) { + screen_handle = screen_handles[i]; + break; + } + } + if (screen_handle) { + + /* X Server information */ + + child = ctk_server_new(screen_handle, ctk_config); + add_page(child, + ctk_server_create_help(tag_table, + CTK_SERVER(child)), + ctk_window, NULL, NULL, "X Server Information", + NULL, NULL, NULL); + + /* X Server Display Configuration */ + + child = ctk_display_config_new(screen_handle, ctk_config); + if (child) { + add_page(child, + ctk_display_config_create_help(tag_table, + CTK_DISPLAY_CONFIG(child)), + ctk_window, NULL, NULL, + "X Server Display Configuration", + NULL, NULL, NULL); + } + } + } + + /* add the per-screen entries into the tree model */ - for (i = 0; i < num_handles; i++) { + for (i = 0; i < num_screen_handles; i++) { GtkTreeIter iter; gchar *screen_name; GtkWidget *child; + NvCtrlAttributeHandle *screen_handle = screen_handles[i]; - if (!handles[i]) continue; + if (!screen_handle) continue; /* create the object for receiving NV-CONTROL events */ - ctk_event = CTK_EVENT(ctk_event_new(handles[i])); + ctk_event = CTK_EVENT(ctk_event_new(screen_handle)); - screen_name = NvCtrlGetDisplayName(handles[i]); + screen_name = g_strdup_printf("X Screen %d", + NvCtrlGetTargetId(screen_handle)); /* create the screen entry */ @@ -545,22 +619,24 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_LABEL_COLUMN, screen_name, -1); - /* device information */ + /* Screen information */ + + screen_name = NvCtrlGetDisplayName(screen_handle); - child = ctk_device_new(handles[i]); + child = ctk_screen_new(screen_handle, ctk_event); gtk_object_ref(GTK_OBJECT(child)); gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_WIDGET_COLUMN, child, -1); gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_HELP_COLUMN, - ctk_device_create_help(tag_table, screen_name), -1); + ctk_screen_create_help(tag_table, screen_name), -1); gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN, NULL, -1); /* color correction */ - child = ctk_color_correction_new(handles[i], ctk_config, + child = ctk_color_correction_new(screen_handle, ctk_config, ctk_window->attribute_list, ctk_event); if (child) { @@ -571,7 +647,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* xvideo settings */ - child = ctk_xvideo_new(handles[i], ctk_config, ctk_event); + child = ctk_xvideo_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_xvideo_create_help(tag_table, CTK_XVIDEO(child)); add_page(child, help, ctk_window, &iter, NULL, @@ -580,7 +656,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* randr settings */ - child = ctk_randr_new(handles[i], ctk_config, ctk_event); + child = ctk_randr_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_randr_create_help(tag_table, CTK_RANDR(child)); add_page(child, help, ctk_window, &iter, NULL, @@ -589,7 +665,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* cursor shadow */ - child = ctk_cursor_shadow_new(handles[i], ctk_config, ctk_event); + child = ctk_cursor_shadow_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_cursor_shadow_create_help(tag_table, CTK_CURSOR_SHADOW(child)); @@ -599,7 +675,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* opengl settings */ - child = ctk_opengl_new(handles[i], ctk_config, ctk_event); + child = ctk_opengl_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_opengl_create_help(tag_table, CTK_OPENGL(child)); add_page(child, help, ctk_window, &iter, NULL, "OpenGL Settings", @@ -609,7 +685,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* GLX Information */ - child = ctk_glx_new(handles[i], ctk_config, ctk_event); + child = ctk_glx_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_glx_create_help(tag_table, CTK_GLX(child)); add_page(child, help, ctk_window, &iter, NULL, @@ -619,7 +695,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* multisample settings */ - child = ctk_multisample_new(handles[i], ctk_config, ctk_event); + child = ctk_multisample_new(screen_handle, ctk_config, ctk_event); if (child) { help = ctk_multisample_create_help(tag_table, CTK_MULTISAMPLE(child)); @@ -627,20 +703,12 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, "Antialiasing Settings", NULL, NULL, NULL); } - /* thermal information */ - - child = ctk_thermal_new(handles[i], ctk_config); - if (child) { - help = ctk_thermal_create_help(tag_table, CTK_THERMAL(child)); - add_page(child, help, ctk_window, &iter, NULL, "Thermal Monitor", - NULL, ctk_thermal_start_timer, ctk_thermal_stop_timer); - } - /* gvo (Graphics To Video Out) */ - child = ctk_gvo_new(handles[i], GTK_WIDGET(ctk_window), + child = ctk_gvo_new(screen_handle, GTK_WIDGET(ctk_window), ctk_config, ctk_event); if (child) { + GtkWidget *gvo_parent = child; GtkTreeIter child_iter; help = ctk_gvo_create_help(tag_table); add_page(child, help, ctk_window, &iter, &child_iter, @@ -649,17 +717,78 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, /* add GVO sub-pages */ - child = ctk_gvo_csc_new(handles[i], - ctk_config, ctk_event); + child = ctk_gvo_csc_new(screen_handle, ctk_config, ctk_event, + CTK_GVO(gvo_parent)); if (child) { add_page(child, NULL, ctk_window, &child_iter, NULL, - "Color Space Conversion", NULL, NULL, NULL); + "Color Space Conversion", NULL, + ctk_gvo_csc_select, ctk_gvo_csc_unselect); } } + } + + /* add the per-gpu entries into the tree model */ + + for (i = 0; i < num_gpu_handles; i++) { + + GtkTreeIter iter; + gchar *gpu_product_name; + gchar *gpu_name; + GtkWidget *child; + ReturnStatus ret; + NvCtrlAttributeHandle *gpu_handle = gpu_handles[i]; + UpdateDisplaysData *data; + + + if (!gpu_handle) continue; + + /* create the gpu entry name */ + ret = NvCtrlGetStringDisplayAttribute(gpu_handle, 0, + NV_CTRL_STRING_PRODUCT_NAME, + &gpu_product_name); + if (ret == NvCtrlSuccess && gpu_product_name) { + gpu_name = g_strdup_printf("GPU %d - (%s)", + NvCtrlGetTargetId(gpu_handle), + gpu_product_name); + } else { + gpu_name = g_strdup_printf("GPU %d - (Unknown)", + NvCtrlGetTargetId(gpu_handle)); + } + if (!gpu_name) continue; + + /* create the object for receiving NV-CONTROL events */ + + ctk_event = CTK_EVENT(ctk_event_new(gpu_handle)); + + /* create the gpu entry */ + + gtk_tree_store_append(ctk_window->tree_store, &iter, NULL); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_LABEL_COLUMN, gpu_name, -1); + child = ctk_gpu_new(gpu_handle, screen_handles, ctk_event); + gtk_object_ref(GTK_OBJECT(child)); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_WIDGET_COLUMN, child, -1); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_HELP_COLUMN, + ctk_gpu_create_help(tag_table), -1); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN, + NULL, -1); + + /* thermal information */ + + child = ctk_thermal_new(gpu_handle, ctk_config); + if (child) { + help = ctk_thermal_create_help(tag_table, CTK_THERMAL(child)); + add_page(child, help, ctk_window, &iter, NULL, "Thermal Monitor", + NULL, ctk_thermal_start_timer, ctk_thermal_stop_timer); + } + /* clocks (GPU overclocking) */ - child = ctk_clocks_new(handles[i], ctk_config, ctk_event); + child = ctk_clocks_new(gpu_handle, ctk_config, ctk_event); if (child) { help = ctk_clocks_create_help(tag_table, CTK_CLOCKS(child)); add_page(child, help, ctk_window, &iter, NULL, "Clock Frequencies", @@ -667,14 +796,69 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, } /* display devices */ + data = (UpdateDisplaysData *)calloc(1, sizeof(UpdateDisplaysData)); + data->window = ctk_window; + data->event = ctk_event; + data->gpu_handle = gpu_handle; + data->parent_iter = iter; + data->tag_table = tag_table; - child = ctk_display_device_new(handles[i], ctk_config, ctk_event); - if (child) { - help = ctk_display_device_create_help(tag_table, - CTK_DISPLAY_DEVICE(child)); - add_display_devices(child, help, ctk_window, - &iter, handles[i], ctk_event, tag_table); + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_PROBE_DISPLAYS), + G_CALLBACK(update_display_devices), + (gpointer) data); + + add_display_devices(ctk_window, &iter, gpu_handle, ctk_event, + tag_table, data); + } + + /* add the per-vcsc (e.g. Quadro Plex) entries into the tree model */ + + for (i = 0; i < num_vcsc_handles; i++) { + + GtkTreeIter iter; + gchar *vcsc_product_name; + gchar *vcsc_name; + GtkWidget *child; + ReturnStatus ret; + NvCtrlAttributeHandle *vcsc_handle = vcsc_handles[i]; + + if (!vcsc_handle) continue; + + /* create the vcsc entry name */ + + ret = NvCtrlGetStringDisplayAttribute(vcsc_handle, 0, + NV_CTRL_STRING_VCSC_PRODUCT_NAME, + &vcsc_product_name); + if (ret == NvCtrlSuccess && vcsc_product_name) { + vcsc_name = g_strdup_printf("VCSC %d - (%s)", + NvCtrlGetTargetId(vcsc_handle), + vcsc_product_name); + } else { + vcsc_name = g_strdup_printf("VCSC %d - (Unknown)", + NvCtrlGetTargetId(vcsc_handle)); } + if (!vcsc_name) continue; + + /* create the object for receiving NV-CONTROL events */ + + ctk_event = CTK_EVENT(ctk_event_new(vcsc_handle)); + + /* create the vcsc entry */ + + gtk_tree_store_append(ctk_window->tree_store, &iter, NULL); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_LABEL_COLUMN, vcsc_name, -1); + child = ctk_vcsc_new(vcsc_handle, ctk_config); + gtk_object_ref(GTK_OBJECT(child)); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_WIDGET_COLUMN, child, -1); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_HELP_COLUMN, + ctk_gpu_create_help(tag_table), -1); + gtk_tree_store_set(ctk_window->tree_store, &iter, + CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN, + NULL, -1); } /* @@ -682,10 +866,13 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, * frame lock */ - for (i = 0; i < num_handles; i++) { - if (!handles[i]) continue; + for (i = 0; i < num_screen_handles; i++) { + + NvCtrlAttributeHandle *screen_handle = screen_handles[i]; + + if (!screen_handle) continue; - widget = ctk_framelock_new(handles[i], GTK_WIDGET(ctk_window), + widget = ctk_framelock_new(screen_handle, GTK_WIDGET(ctk_window), ctk_config, ctk_window->attribute_list); if (!widget) continue; @@ -905,52 +1092,56 @@ static void add_special_config_file_attributes(CtkWindow *ctk_window) * add_display_devices() - add the display device pages */ -static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help, - CtkWindow *ctk_window, GtkTreeIter *iter, +static void add_display_devices(CtkWindow *ctk_window, GtkTreeIter *iter, NvCtrlAttributeHandle *handle, CtkEvent *ctk_event, - GtkTextTagTable *tag_table) + GtkTextTagTable *tag_table, + UpdateDisplaysData *data) { - GtkTreeIter child_iter; + GtkWidget *widget; + GtkTextBuffer *help; ReturnStatus ret; - int i, enabled, n, mask; + int i, connected, n, mask; char *name; + char *type; + gchar *title; - if (!widget) { - return; - } - /* retrieve the enabled display device mask */ + /* retrieve the connected display device mask */ - ret = NvCtrlGetAttribute(handle, NV_CTRL_ENABLED_DISPLAYS, &enabled); + ret = NvCtrlGetAttribute(handle, NV_CTRL_CONNECTED_DISPLAYS, &connected); if (ret != NvCtrlSuccess) { return; } - /* count how many display devices are enabled */ + /* count how many display devices are connected */ for (i = 0, n = 0; i < 24; i++) { - if (enabled & (1 << i)) n++; + if (connected & (1 << i)) n++; } if (n == 0) { return; - } else if (n == 1) { - name = "Display Device"; - } else { - name = "Display Devices"; } - add_page(widget, help, ctk_window, iter, &child_iter, name, - NULL, NULL, NULL); + + if (data->display_iters) { + free(data->display_iters); + } + data->display_iters = + (GtkTreeIter *)calloc(1, n * sizeof(GtkTreeIter)); + data->num_displays = 0; + if (!data->display_iters) return; + /* - * create pages for each of the display devices driven by this X - * screen. + * create pages for each of the display devices driven by this handle. */ for (i = 0; i < 24; i++) { mask = (1 << i); - if (!(mask & enabled)) continue; + if (!(mask & connected)) continue; + + type = display_device_mask_to_display_device_name(mask); ret = NvCtrlGetStringDisplayAttribute(handle, mask, @@ -958,13 +1149,17 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help, &name); if ((ret != NvCtrlSuccess) || (!name)) { - name = "Unknown"; + title = g_strdup_printf("%s - (Unknown)", type); + } else { + title = g_strdup_printf("%s - (%s)", type, name); + XFree(name); } + free(type); if (mask & CTK_DISPLAY_DEVICE_CRT_MASK) { widget = ctk_display_device_crt_new - (handle, ctk_window->ctk_config, ctk_event, mask, name); + (handle, ctk_window->ctk_config, ctk_event, mask, title); help = ctk_display_device_crt_create_help (tag_table, CTK_DISPLAY_DEVICE_CRT(widget)); @@ -972,7 +1167,7 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help, } else if (mask & CTK_DISPLAY_DEVICE_TV_MASK) { widget = ctk_display_device_tv_new - (handle, ctk_window->ctk_config, ctk_event, mask, name); + (handle, ctk_window->ctk_config, ctk_event, mask, title); help = ctk_display_device_tv_create_help (tag_table, CTK_DISPLAY_DEVICE_TV(widget)); @@ -980,18 +1175,88 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help, } else if (mask & CTK_DISPLAY_DEVICE_DFP_MASK) { widget = ctk_display_device_dfp_new - (handle, ctk_window->ctk_config, ctk_event, mask, name); + (handle, ctk_window->ctk_config, ctk_event, mask, title); help = ctk_display_device_dfp_create_help (tag_table, CTK_DISPLAY_DEVICE_DFP(widget)); } else { + g_free(title); continue; } - add_page(widget, help, ctk_window, &child_iter, - NULL, name, NULL, NULL, NULL); + add_page(widget, help, ctk_window, iter, + &(data->display_iters[data->num_displays]), title, + NULL, NULL, NULL); + g_free(title); + data->num_displays++; } } /* add_display_devices() */ - + + +/* + * update_display_devices() - Callback handler for the NV_CTRL_PROBE_DISPLAYS + * NV-CONTROL event. Updates the list of display devices connected to the + * GPU for which the event happened. + * + */ + +static void update_display_devices(GtkObject *object, gpointer arg1, + gpointer user_data) +{ + UpdateDisplaysData *data = (UpdateDisplaysData *) user_data; + + CtkWindow *ctk_window = data->window; + CtkEvent *ctk_event = data->event; + NvCtrlAttributeHandle *gpu_handle = data->gpu_handle; + GtkTreeIter parent_iter = data->parent_iter; + GtkTextTagTable *tag_table = data->tag_table; + GtkTreePath* parent_path; + gboolean parent_expanded; + GtkTreeSelection *tree_selection = + gtk_tree_view_get_selection(ctk_window->treeview); + + + /* Keep track if the parent row is expanded */ + parent_path = + gtk_tree_model_get_path(GTK_TREE_MODEL(ctk_window->tree_store), + &parent_iter); + parent_expanded = + gtk_tree_view_row_expanded(ctk_window->treeview, parent_path); + + + /* Remove previous display devices */ + while (data->num_displays) { + + GtkTreeIter *iter = &(data->display_iters[data->num_displays -1]); + GtkWidget *widget; + + /* Select the parent (GPU) iter if we're removing the selected page */ + if (gtk_tree_selection_iter_is_selected(tree_selection, iter)) { + gtk_tree_selection_select_iter(tree_selection, &parent_iter); + } + + /* unref the page so we don't leak memory */ + gtk_tree_model_get(GTK_TREE_MODEL(ctk_window->tree_store), iter, + CTK_WINDOW_WIDGET_COLUMN, &widget, -1); + g_object_unref(widget); + + /* XXX Call a widget-specific cleanup function? */ + + /* Remove the entry */ + gtk_tree_store_remove(ctk_window->tree_store, iter); + + data->num_displays--; + } + + /* Add back all the connected display devices */ + add_display_devices(ctk_window, &parent_iter, gpu_handle, ctk_event, + tag_table, data); + + /* Expand the GPU entry if it used to be */ + if (parent_expanded) { + gtk_tree_view_expand_row(ctk_window->treeview, parent_path, TRUE); + } + +} /* update_display_devices() */ diff --git a/src/gtk+-2.x/ctkwindow.h b/src/gtk+-2.x/ctkwindow.h index c88c23d..3f5749a 100644 --- a/src/gtk+-2.x/ctkwindow.h +++ b/src/gtk+-2.x/ctkwindow.h @@ -53,6 +53,11 @@ G_BEGIN_DECLS (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_WINDOW, CtkWindowClass)) +#define CTK_DISPLAY_DEVICE_CRT_MASK 0x000000FF +#define CTK_DISPLAY_DEVICE_TV_MASK 0x0000FF00 +#define CTK_DISPLAY_DEVICE_DFP_MASK 0x00FF0000 + + typedef struct _CtkWindow CtkWindow; typedef struct _CtkWindowClass CtkWindowClass; @@ -60,9 +65,6 @@ struct _CtkWindow { GtkWindow parent; - NvCtrlAttributeHandle **handles; - gint num_handles; - GtkTreeStore *tree_store; GtkTreeView *treeview; @@ -90,6 +92,8 @@ struct _CtkWindowClass GType ctk_window_get_type (void) G_GNUC_CONST; GtkWidget* ctk_window_new (NvCtrlAttributeHandle**, gint, + NvCtrlAttributeHandle**, gint, + NvCtrlAttributeHandle**, gint, ParsedAttribute *, ConfigProperties *conf); G_END_DECLS diff --git a/src/gtk+-2.x/ctkxvideo.c b/src/gtk+-2.x/ctkxvideo.c index d423625..6bb7d2b 100644 --- a/src/gtk+-2.x/ctkxvideo.c +++ b/src/gtk+-2.x/ctkxvideo.c @@ -22,6 +22,7 @@ * */ +#include <stdlib.h> #include <gtk/gtk.h> #include "NvCtrlAttributes.h" @@ -473,6 +474,8 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, GtkWidget *radio[24], *prev_radio; int i, n, current = -1, mask; char *name; + char *type; + gchar *name_str; frame = gtk_frame_new("Sync to this display device"); gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0); @@ -487,7 +490,7 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, mask = 1 << i; if (!(enabled & mask)) continue; - + /* get the name of the display device */ ret = NvCtrlGetStringDisplayAttribute(handle, mask, @@ -497,6 +500,14 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, if ((ret != NvCtrlSuccess) || (!name)) { name = g_strdup("Unknown"); } + + /* get the display device type */ + + type = display_device_mask_to_display_device_name(mask); + + name_str = g_strdup_printf("%s (%s)", name, type); + XFree(name); + free(type); if (n==0) { prev_radio = NULL; @@ -504,7 +515,8 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, prev_radio = radio[n-1]; } radio[n] = xv_sync_to_display_radio_button_add(ctk_xvideo, vbox, - prev_radio, name, mask, n); + prev_radio, name_str, mask, n); + g_free(name_str); ctk_config_set_tooltip(ctk_config, radio[n], __xv_sync_to_display_help); diff --git a/src/image_data/Makefile.inc b/src/image_data/Makefile.inc index 6606291..f0800e3 100644 --- a/src/image_data/Makefile.inc +++ b/src/image_data/Makefile.inc @@ -30,6 +30,7 @@ SRC += \ image.c EXTRA_DIST += \ + Makefile.inc \ HOWTO-ADD-IMAGES \ antialiasing_banner.h \ big_banner_bsd.h \ @@ -86,4 +87,8 @@ EXTRA_DIST += \ led_grey.h \ rj45_input.h \ rj45_output.h \ - rj45_unused.h + rj45_unused.h \ + blank_banner.h + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/image_data/antialiasing_banner.h b/src/image_data/antialiasing_banner.h index 7ad99fc..8a65a84 100644 --- a/src/image_data/antialiasing_banner.h +++ b/src/image_data/antialiasing_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t antialiasing_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\1IX\31\203_y\24\1k\211\26\377\200\221\33\312\200\221\33\202\225\235e\4\200" "\201\203stt\213\213\215\227\227\230\202\234\236\235\1\243\243\244\202\234" "\236\235\2\221\221\223\213\213\215\203\221\221\223\1\213\213\215\202\200" diff --git a/src/image_data/big_banner_bsd.h b/src/image_data/big_banner_bsd.h index 4095aff..83c3f53 100644 --- a/src/image_data/big_banner_bsd.h +++ b/src/image_data/big_banner_bsd.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t big_banner_bsd_image = { - 360, 110, 3, + 360, 110, 3, 180, "\11R\\+Wb._k2gt6o~;w\205>|\213B\177\217C\200\217D\377\200\220D\321\200\220" "D\24\207\225V\222\233t\205\211vpppxxy\200\200\200\205\205\206\207\207\211" "\212\212\213\213\213\214\215\215\217\220\220\223\224\224\226\230\230\231" diff --git a/src/image_data/big_banner_penguin.h b/src/image_data/big_banner_penguin.h index 8678103..c4613ef 100644 --- a/src/image_data/big_banner_penguin.h +++ b/src/image_data/big_banner_penguin.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t big_banner_penguin_image = { - 360, 110, 3, + 360, 110, 3, 180, "\11R\\+Wb._k2gt6o~;w\205>|\213B\177\217C\200\217D\377\200\220D\321\200\220" "D\24\207\225V\222\233t\205\211vpppxxy\200\200\200\205\205\206\207\207\211" "\212\212\213\213\213\214\215\215\217\220\220\223\224\224\226\230\230\231" diff --git a/src/image_data/big_banner_sun.h b/src/image_data/big_banner_sun.h index 158d0d3..9193ee2 100644 --- a/src/image_data/big_banner_sun.h +++ b/src/image_data/big_banner_sun.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t big_banner_sun_image = { - 360, 110, 3, + 360, 110, 3, 180, "\377\376\376\376\333\376\376\376\5\231\236v\177\177\177jjkvvw\177\177\177" "\202\205\205\206\202\212\212\214\7\220\220\217\217\216\224\223\223\224\227" "\227\231\223\223\224\212\212\214\205\205\206\202\212\212\214\203\205\205" diff --git a/src/image_data/blank_banner.h b/src/image_data/blank_banner.h new file mode 100644 index 0000000..e2f25e0 --- /dev/null +++ b/src/image_data/blank_banner.h @@ -0,0 +1,1485 @@ +/* GIMP RGB C-Source image dump 1-byte-run-length-encoded */
+
+#include "image.h"
+
+static const nv_image_t blank_banner_image = {
+ 360, 60, 3, 180,
+ "\10S]\21Xc\22`k\23hv\25p\177\27x\205\30}\213\32\200\217\33\377\200\220\33"
+ "\306\200\220\33\35\201\221\40\217\231S\222\233e\202\204|zz{\212\212\213\224"
+ "\224\225\232\232\233\236\236\240\240\240\241\236\236\240\233\233\235\217"
+ "\217\221\211\211\215\215\215\217\221\221\222\220\220\222\211\211\213\202"
+ "\202\205\203\203\207\215\215\217\220\220\223\217\217\221\220\220\222\221"
+ "\221\223\214\214\217\201\201\205\200\200\203\217\217\221\203\230\230\230"
+ "\5\224\224\225\200\200\204{{\200\204\204\207\216\216\221\202\217\217\222"
+ "\5\220\220\223\210\210\213yy\177{{\200\220\220\222\205\230\230\230\5\212"
+ "\212\215ttzyy\177\212\212\217\227\227\230\202\230\230\230\5\221\221\224\177"
+ "\177\203rryzz\200\217\217\221\202\230\230\230\1\227\227\227\202\225\225\227"
+ "\13\227\227\227\230\230\230\224\224\225\211\211\214\200\200\202zz\200{{\200"
+ "\177\177\202\204\204\210\211\211\214\215\215\217\202\216\216\220\12\214\214"
+ "\217\212\212\215\211\211\213\206\206\212\205\205\211\205\205\210\204\204"
+ "\210\204\204\207\205\205\210\204\204\210\205\205\205\211\2\206\206\211\206"
+ "\206\212\203\207\207\212\202\206\206\212\7\204\204\207\202\202\205\200\200"
+ "\203\177\177\201\200\200\204\212\212\214\224\224\225\202\230\230\230\13\227"
+ "\227\227\221\221\223\211\211\215\205\205\212\213\213\217\222\222\225\227"
+ "\227\230\230\230\230\226\226\227\216\216\221\205\205\212\202\204\204\211"
+ "\16\206\206\213\213\213\220\224\224\226\227\227\227\225\225\230\212\212\217"
+ "{{\200ssyttzuu{\177\177\202\214\214\220\221\221\224\226\226\226\204\230\230"
+ "\230\1\226\226\227\202\217\217\221\2\211\211\214\203\203\207\202\202\202"
+ "\206\17\204\204\210\211\211\214\207\207\210\177\177\200||}xxxnnn`k\25iu\26"
+ "s\200\31\177\213\33\210\230\35\221\241\37\226\250\40\231\254!\202\233\255"
+ "!\377\234\256!\304\234\256!\27\241\262;\260\272u\243\251\200yyz\207\207\210"
+ "\226\226\230\242\242\242\247\247\252\256\256\256\257\257\260\261\261\262"
+ "\251\251\253\235\235\240\232\232\235\241\241\242\244\244\244\235\235\237"
+ "\223\223\227\216\216\222\226\226\231\237\237\242\240\240\243\240\240\242"
+ "\202\240\240\243\4\226\226\231\215\215\222\227\226\232\250\250\251\203\252"
+ "\252\252\4\233\233\236\210\210\215\214\214\222\231\231\235\202\237\237\243"
+ "\5\240\240\244\232\232\237\211\211\217\202\202\212\232\232\235\205\252\252"
+ "\252!\240\240\242\204\204\213\200\200\210\230\230\234\246\246\251\252\252"
+ "\252\251\251\252\241\241\244\213\213\222\177\177\205\213\213\220\241\241"
+ "\244\252\252\252\252\252\251\251\251\251\247\247\251\251\251\251\252\252"
+ "\252\251\251\252\241\241\244\221\221\225\206\206\215\207\207\214\214\214"
+ "\222\224\224\231\233\233\236\237\237\242\240\240\242\235\235\241\233\233"
+ "\236\227\227\233\225\225\231\223\223\230\202\223\223\227\5\223\223\230\225"
+ "\225\231\225\225\232\227\227\233\231\231\233\204\231\231\234\4\231\231\233"
+ "\227\227\232\226\226\232\226\226\231\203\225\225\231\203\226\226\232$\225"
+ "\225\231\223\223\230\220\220\225\215\215\222\214\214\221\223\223\230\236"
+ "\236\241\251\251\251\252\252\252\251\251\252\243\243\245\227\227\234\221"
+ "\221\226\224\224\231\237\237\242\251\251\251\252\252\252\251\251\252\241"
+ "\241\243\225\225\232\222\222\231\224\224\231\226\226\233\235\235\242\247"
+ "\247\250\251\251\252\244\244\250\225\225\233\201\201\211\200\200\205\200"
+ "\200\206\201\201\210\217\217\224\235\235\242\242\242\245\251\251\251\204"
+ "\252\252\252\26\244\244\245\236\236\242\234\234\240\223\223\230\217\217\224"
+ "\221\221\225\220\220\224\223\223\227\225\225\227\215\215\220\202\202\204"
+ "\200\200\200wwyly\27u\202\32\200\217\34\216\237\37\232\253\"\243\267$\253"
+ "\277%\256\303&\257\304&\377\260\305&\305\260\305&\11\275\314Z\307\321\202"
+ "\241\245\211~~\200\221\221\222\242\242\244\253\253\255\266\266\267\275\275"
+ "\276\202\277\277\301\21\265\265\270\252\252\257\255\255\260\265\265\266\263"
+ "\263\263\252\251\255\235\235\242\236\236\242\251\251\255\260\260\263\260"
+ "\260\262\260\260\264\261\261\264\254\254\261\236\236\244\236\236\243\262"
+ "\262\264\203\273\273\273\5\270\270\271\237\237\245\225\225\234\241\241\247"
+ "\254\254\261\202\257\257\264\5\256\256\262\237\237\245\216\216\226\237\237"
+ "\244\271\271\272\202\273\273\273\7\272\272\272\273\273\273\266\266\270\230"
+ "\230\237\212\212\223\236\236\244\264\264\267\202\272\272\273\7\264\264\267"
+ "\235\235\243\212\212\222\230\230\237\266\266\267\273\273\273\273\273\272"
+ "\203\272\272\272\26\273\273\273\272\272\273\260\260\264\235\235\242\223\223"
+ "\232\227\227\236\240\240\246\252\252\256\261\261\264\262\262\265\257\257"
+ "\263\252\252\256\247\247\252\243\243\250\241\241\247\243\243\247\245\245"
+ "\251\250\250\253\254\254\256\257\257\262\261\261\264\264\264\266\202\266"
+ "\266\270\203\267\267\270\10\266\266\270\265\265\267\263\263\265\261\261\263"
+ "\256\256\260\253\253\256\251\251\254\250\250\252\203\246\246\251\202\246"
+ "\246\252\"\244\244\251\241\241\246\236\236\243\233\233\241\236\236\243\255"
+ "\255\260\272\272\272\273\273\273\272\272\273\264\264\266\244\244\251\235"
+ "\235\241\237\237\245\256\256\262\272\272\272\273\273\273\272\272\272\257"
+ "\257\263\244\244\252\241\241\250\243\243\251\247\247\254\262\261\265\272"
+ "\272\272\271\271\273\264\264\267\233\232\241\212\212\223\214\214\223\214"
+ "\214\224\222\222\231\245\245\252\261\261\265\266\266\270\204\273\273\273"
+ "\6\271\271\272\260\260\264\256\256\263\245\245\252\235\235\243\237\237\243"
+ "\202\235\235\242\16\237\237\243\235\235\240\216\216\221\205\205\210\177\177"
+ "\200u\200\32\200\214\35\215\234\40\234\255$\252\274'\264\310)\272\317*\276"
+ "\324+\277\324,\377\300\325,\304\300\325,\25\301\325/\323\337{\325\336\215"
+ "\221\223\210\205\205\207\233\233\234\251\251\253\265\265\267\301\301\303"
+ "\306\306\311\314\314\317\313\313\315\277\277\302\272\272\276\302\302\303"
+ "\305\305\305\277\277\300\263\263\265\251\251\255\257\257\262\273\273\276"
+ "\202\275\275\300\202\300\300\303\4\266\266\273\250\250\257\263\263\270\311"
+ "\311\311\203\313\313\313\13\276\276\302\244\244\253\246\246\255\265\265\272"
+ "\275\275\301\276\276\303\275\275\302\266\266\272\240\240\250\243\243\252"
+ "\303\303\304\205\313\313\313\13\265\265\272\225\225\237\240\240\247\273\273"
+ "\301\310\310\312\311\311\313\304\304\307\254\254\263\225\225\240\242\242"
+ "\251\301\301\304\202\313\313\313\203\312\312\312\24\313\313\313\312\312\312"
+ "\273\273\300\250\250\260\242\242\250\251\251\257\264\264\271\275\275\302"
+ "\302\302\304\300\300\303\273\273\300\265\265\271\261\261\266\261\261\265"
+ "\264\264\267\270\270\273\277\277\301\303\303\305\306\306\310\310\310\311"
+ "\207\311\311\311\205\311\311\312\10\311\311\311\307\307\311\304\305\306\301"
+ "\301\303\274\274\300\267\267\273\265\265\271\264\264\271\202\264\264\267"
+ "\"\263\263\266\261\261\265\256\256\263\250\250\260\253\253\262\271\271\276"
+ "\311\311\311\313\313\313\312\312\313\301\301\304\260\260\266\247\247\256"
+ "\252\252\262\272\272\277\311\311\311\313\313\313\311\311\311\300\300\303"
+ "\262\262\270\260\260\266\262\262\270\267\267\276\305\305\307\312\312\313"
+ "\310\310\313\267\267\275\234\234\244\226\226\237\230\230\241\231\231\242"
+ "\244\244\253\267\267\275\303\303\306\311\311\312\204\313\313\313\25\304\304"
+ "\306\276\276\302\267\267\274\254\254\261\253\253\261\253\253\260\250\250"
+ "\255\247\247\253\250\250\253\234\234\236\214\213\216\203\203\206|\206\34"
+ "\207\225\37\226\245\"\247\270&\265\307)\300\322,\306\332-\311\335-\312\336"
+ ".\377\313\337.\304\313\337.\25\321\342H\342\353\222\306\317\224\177\177\200"
+ "\216\216\220\243\243\244\261\261\262\275\275\276\312\312\314\317\317\322"
+ "\330\330\332\321\321\325\310\310\314\314\314\317\322\322\323\321\321\321"
+ "\312\312\313\273\273\277\264\264\271\277\277\302\311\311\315\202\312\312"
+ "\315\5\315\315\321\307\307\314\272\272\300\266\266\274\315\315\321\203\331"
+ "\331\331\13\326\326\327\274\274\302\253\253\263\271\271\277\306\306\313\311"
+ "\311\317\312\312\317\304\304\311\263\263\272\246\246\257\304\304\310\203"
+ "\331\331\331\15\330\330\330\331\331\331\320\320\322\250\250\261\242\242\254"
+ "\275\275\303\322\322\326\325\325\331\322\322\327\275\275\303\241\241\253"
+ "\253\253\262\315\315\320\202\331\331\331\203\330\330\330\21\331\331\331\327"
+ "\327\330\307\307\312\260\260\270\256\256\265\272\272\277\307\307\313\317"
+ "\317\322\320\320\322\311\311\316\302\302\307\276\276\302\275\275\302\302"
+ "\302\305\310\310\314\321\321\323\326\326\327\202\327\327\330\2\326\326\327"
+ "\324\324\326\204\322\322\325\4\323\323\325\324\324\326\325\325\327\326\326"
+ "\327\202\327\327\327\3\327\327\330\327\327\331\330\330\331\202\331\331\331"
+ "\7\330\330\331\327\327\327\322\322\324\315\315\320\306\306\312\303\303\306"
+ "\300\300\304\202\276\276\303\2\275\275\301\272\272\276\202\264\264\273\34"
+ "\301\301\306\324\324\325\331\331\331\330\330\331\315\315\321\271\271\277"
+ "\256\256\267\262\262\272\304\304\311\327\327\327\331\331\331\327\327\330"
+ "\312\312\320\275\275\303\273\273\303\276\276\304\310\310\317\327\327\327"
+ "\330\330\331\322\322\326\265\265\275\241\241\253\242\242\253\243\243\254"
+ "\245\245\256\265\265\274\312\312\320\322\322\326\204\331\331\331\23\327\327"
+ "\327\314\314\321\310\310\315\271\271\300\265\265\274\266\266\273\263\263"
+ "\270\256\256\262\256\256\261\247\247\253\224\224\230\207\207\211\200\213"
+ "\35\213\231\40\235\254$\255\276'\274\317*\306\331-\314\340.\202\317\343/"
+ "\377\320\344/\304\320\344/\34\333\352b\346\360\224\261\267\223\201\201\202"
+ "\225\225\226\250\250\251\267\267\270\304\304\306\317\317\321\330\330\332"
+ "\334\334\336\326\326\332\322\322\326\332\332\333\337\337\337\334\334\334"
+ "\320\320\323\300\300\305\301\301\305\316\316\321\324\324\327\323\323\327"
+ "\325\325\330\330\330\333\314\314\321\276\276\304\310\310\316\341\341\342"
+ "\203\344\344\344\13\327\327\332\272\272\302\267\267\277\312\312\320\323\323"
+ "\331\324\324\331\322\322\330\303\303\312\260\260\271\272\272\302\340\340"
+ "\340\202\344\344\344\15\343\343\343\344\344\344\343\343\343\302\302\311\250"
+ "\250\262\273\273\303\323\323\331\335\335\342\333\333\340\314\314\323\256"
+ "\256\267\260\260\272\326\326\331\202\344\344\344\203\343\343\343\25\344\344"
+ "\344\343\343\344\322\322\327\272\272\301\270\270\300\306\306\313\324\324"
+ "\331\332\332\336\331\331\335\322\322\325\311\311\316\306\306\314\313\313"
+ "\320\325\325\331\337\337\340\343\343\344\342\342\343\340\340\340\332\332"
+ "\334\326\326\330\323\323\326\202\322\322\324\202\322\322\325\7\323\323\325"
+ "\324\324\326\325\325\326\326\326\327\326\326\330\327\327\331\330\330\331"
+ "\202\331\331\331\3\331\331\332\331\331\333\332\332\333\203\333\333\333!\332"
+ "\332\332\327\327\330\321\321\322\311\311\314\302\302\306\300\300\304\301"
+ "\301\305\301\301\306\300\300\306\274\274\303\273\273\302\311\311\316\337"
+ "\337\340\344\344\344\343\343\343\323\323\330\274\274\304\264\264\275\271"
+ "\271\301\317\317\324\342\342\342\344\344\344\341\341\343\322\322\330\304"
+ "\304\315\304\304\314\312\312\322\331\331\335\343\343\343\342\342\344\322"
+ "\322\330\262\262\273\252\251\263\202\254\254\265\4\261\261\272\311\311\320"
+ "\332\331\336\340\340\341\204\344\344\344\3\333\333\336\325\324\331\311\310"
+ "\316\202\276\276\304\16\275\276\303\266\266\273\260\257\264\256\256\261\236"
+ "\236\241\213\213\215\201\214\37\220\234\"\241\257&\263\303+\301\321.\312"
+ "\3330\320\3411\321\3432\377\323\3452\305\323\3452\33\342\355z\350\361\227"
+ "\236\241\217\206\206\210\234\234\235\256\256\257\273\273\275\310\310\313"
+ "\324\324\326\336\336\337\342\342\344\331\331\334\334\334\340\346\346\347"
+ "\347\347\347\343\343\344\326\326\331\307\307\314\314\314\321\332\332\335"
+ "\333\333\337\332\332\337\335\335\341\335\335\342\316\316\324\305\305\314"
+ "\334\334\340\203\355\355\355\13\354\354\355\321\321\330\273\273\303\303\303"
+ "\313\327\327\333\334\334\342\333\333\341\324\324\333\277\277\307\265\265"
+ "\276\325\325\332\203\355\355\355\3\354\354\354\355\355\355\341\341\344\202"
+ "\266\266\300\7\322\322\331\340\340\347\343\343\350\331\331\340\276\276\307"
+ "\260\260\272\324\324\332\202\355\355\355\203\354\354\354Q\355\355\355\354"
+ "\354\355\337\337\343\304\304\314\277\277\307\317\316\325\335\335\342\344"
+ "\344\347\340\340\344\330\330\335\320\320\326\321\321\326\333\332\335\345"
+ "\345\346\353\353\354\354\354\355\352\352\352\346\346\347\341\341\343\324"
+ "\333\212\343\346\177\343\345~\343\345}\344\345{\344\346z\345\346v\345\347"
+ "s\345\347o\342\347k\340\347f\332\345`\324\344Z\322\345W\320\346U\316\344"
+ "T\313\343R\311\342O\306\341M\303\336K\302\335I\300\333G\277\332F\276\331"
+ "F\276\330F\276\327G\275\325G\273\324E\300\324W\276\276\303\304\304\311\306"
+ "\306\314\304\304\313\303\303\313\326\326\332\352\352\353\355\355\355\351"
+ "\351\352\323\323\332\275\275\306\270\270\302\302\302\311\334\334\341\354"
+ "\354\354\355\355\355\347\347\350\323\323\333\313\313\324\316\316\325\331"
+ "\331\337\347\347\351\355\355\355\346\346\351\306\307\317\261\260\273\262"
+ "\262\273\264\263\275\262\262\274\302\302\312\335\335\343\345\345\350\353"
+ "\353\354\203\355\355\355\23\347\347\351\336\336\343\326\326\333\306\306\315"
+ "\304\304\311\305\305\312\276\276\302\264\264\271\256\256\263\245\245\250"
+ "\217\217\221\202\215\37\222\236#\244\262'\266\305+\305\325.\315\3360\322"
+ "\3431\323\3452\377\324\3462\304\324\3462\25\326\347>\347\360\215\333\343"
+ "\227\207\210\205\216\216\217\242\242\243\262\262\264\301\301\303\317\317"
+ "\321\331\331\333\342\342\344\342\342\345\337\337\342\347\347\352\356\356"
+ "\357\357\357\357\350\350\352\331\331\334\317\317\323\327\327\333\342\342"
+ "\346\202\341\341\345\5\346\346\351\336\336\343\313\313\323\321\321\327\354"
+ "\354\356\203\363\363\363\13\352\352\355\311\311\321\300\300\311\321\321\330"
+ "\340\340\345\342\342\350\337\337\345\317\317\326\272\272\303\305\305\316"
+ "\355\355\357\202\363\363\363\16\362\362\362\363\363\363\360\360\361\316\316"
+ "\325\262\262\275\311\311\322\337\337\347\346\346\354\341\341\347\310\310"
+ "\322\264\264\300\314\314\323\360\360\361\363\363\363\203\362\362\362\202"
+ "\363\363\363>\347\347\351\312\312\322\305\305\315\325\325\333\344\344\351"
+ "\351\351\355\345\345\350\332\332\337\325\325\332\332\332\336\347\347\351"
+ "\360\360\361\363\363\363\361\361\361\353\353\355\350\350\351\346\346\351"
+ "\342\342\344\317\324\200\367\362\217\350\350\206\351\347\203\351\347\200"
+ "\352\350}\351\351z\351\351y\353\351v\345\351r\343\351n\340\351n\340\354n"
+ "\334\351i\327\351f\325\352a\317\352]\315\353X\312\352W\307\347T\303\342O"
+ "\300\336K\274\335I\272\330G\270\326B\263\324@\262\320=\253\3163\266\320E"
+ "\265\265\270\303\303\310\315\315\323\315\315\325\310\310\317\311\311\321"
+ "\336\336\343\360\360\362\363\363\363\351\351\354\320\320\327\300\300\311"
+ "\274\274\306\310\310\322\343\343\350\202\363\363\363\20\351\351\354\326\326"
+ "\336\321\321\330\325\325\335\343\343\351\362\362\362\362\362\363\340\340"
+ "\346\275\275\306\264\264\300\273\272\304\271\271\302\273\273\305\325\325"
+ "\333\351\351\355\356\356\361\203\363\363\363\23\361\361\361\347\347\353\341"
+ "\341\346\317\317\326\307\307\316\312\312\317\304\304\312\270\270\274\256"
+ "\256\262\247\247\253\224\224\230\200\213\40\220\234$\243\260)\265\304.\303"
+ "\3231\312\3332\316\3374\322\3445\377\333\3557\304\333\3557\34\340\360V\354"
+ "\365\231\306\315\230\200\200\201\223\223\224\246\246\247\266\266\270\305"
+ "\305\307\322\322\324\336\336\337\344\344\345\342\342\346\343\343\345\357"
+ "\357\361\364\364\364\363\363\363\353\353\355\332\332\336\325\325\332\342"
+ "\342\346\350\350\353\344\344\350\346\346\351\351\351\355\334\334\342\316"
+ "\316\325\340\340\344\367\367\367\203\370\370\370\12\344\344\350\306\306\317"
+ "\311\311\321\334\334\343\346\346\353\345\345\353\335\335\343\307\307\320"
+ "\300\300\311\342\342\346\203\370\370\370\3\370\370\367\370\370\370\346\346"
+ "\351\202\275\275\310\10\332\332\341\345\345\355\346\346\354\323\323\334\271"
+ "\271\304\304\304\316\357\357\361\370\370\370\204\367\367\3679\370\370\370"
+ "\357\357\361\322\322\332\310\310\320\330\330\336\350\350\354\355\355\361"
+ "\350\350\353\336\336\343\333\333\340\343\343\346\360\360\362\370\370\370"
+ "\367\367\370\363\363\364\355\355\360\353\353\355\352\352\354\353\353\355"
+ "\344\344\347\306\315z\373\373\224\375\375\212\375\375\213\375\375\205\370"
+ "\367{\357\357y\352\347u\347\347r\343\350n\337\351k\337\351h\333\351e\330"
+ "\351b\324\351]\321\351[\320\351X\313\352U\310\350T\305\345P\304\340K\300"
+ "\337J\275\333I\273\331D\271\327E\271\325C\265\323@\261\3218\265\317F\264"
+ "\264\267\303\303\311\317\317\325\323\323\332\317\317\326\313\313\322\317"
+ "\317\326\343\343\351\202\367\367\370\30\351\351\355\315\315\326\300\300\312"
+ "\277\277\312\316\316\327\355\355\361\370\370\370\367\367\370\350\350\356"
+ "\327\327\337\325\325\335\336\336\344\360\360\363\370\370\370\363\363\366"
+ "\321\321\332\270\270\303\275\275\307\300\300\312\273\273\306\310\310\321"
+ "\345\345\353\360\357\364\366\366\370\203\370\370\370\22\356\356\362\350\347"
+ "\354\331\331\337\311\311\321\312\312\320\311\311\317\273\273\301\254\254"
+ "\261\245\245\250\227\227\232\200\213\40\222\236%\246\263*\270\307.\306\326"
+ "2\314\3353\317\3404\325\3466\377\333\3557\304\333\3557\23\344\361j\354\365"
+ "\231\262\267\225\203\203\205\230\230\231\253\253\254\273\273\275\313\313"
+ "\314\326\326\330\340\340\342\347\347\350\341\341\345\350\350\353\364\364"
+ "\365\367\367\367\366\366\366\354\354\356\332\332\337\334\334\341\202\351"
+ "\351\354\6\350\350\354\353\353\357\352\352\357\327\327\336\326\326\333\356"
+ "\356\361\203\372\372\372\13\370\370\371\333\333\340\306\306\317\322\322\331"
+ "\343\343\351\350\350\355\345\345\353\327\327\336\300\300\312\317\317\327"
+ "\364\364\365\202\372\372\372\16\371\371\371\372\372\372\371\371\371\317\316"
+ "\327\265\265\300\310\310\323\341\341\350\346\346\355\336\336\346\303\303"
+ "\316\274\273\307\342\342\350\372\372\372\372\372\371\203\371\371\371O\372"
+ "\372\372\371\371\371\337\337\344\312\312\323\325\325\333\346\346\354\356"
+ "\356\363\351\351\355\337\337\344\333\333\340\347\347\353\365\365\367\372"
+ "\372\372\370\370\371\363\363\365\356\356\361\353\353\356\351\351\354\351"
+ "\351\353\345\345\347\330\330\327\217\227h\233\236h\231\235g\240\246e\301"
+ "\307r\356\366\202\375\375|\375\375w\375\375s\352\357n\335\347i\333\350h\333"
+ "\351c\326\351`\321\351]\321\351Z\315\352W\312\351T\307\345P\304\342O\302"
+ "\337L\277\335I\274\334G\272\330E\272\326C\267\324A\265\323?\262\3219\264"
+ "\316F\273\273\273\316\316\321\322\322\330\326\326\333\324\323\332\317\317"
+ "\327\313\313\323\322\322\332\360\360\362\372\372\372\371\371\371\340\340"
+ "\346\306\306\321\300\277\312\301\300\313\331\331\340\366\366\367\372\372"
+ "\372\366\366\370\340\340\350\326\326\336\331\331\340\351\351\357\371\371"
+ "\372\372\372\372\344\344\352\276\276\311\274\274\307\303\303\315\202\300"
+ "\300\312\3\331\331\337\356\356\364\366\366\370\203\372\372\372\22\365\365"
+ "\367\353\353\357\340\340\346\314\314\323\313\313\321\312\312\320\300\300"
+ "\305\255\255\262\242\242\246\230\230\233\203\215!\225\241&\252\270+\274\313"
+ "/\310\3303\317\3374\320\3415\331\3537\377\334\3568\304\334\3568\16\350\363"
+ "}\355\366\232\235\240\217\211\211\213\235\235\236\256\256\257\277\277\300"
+ "\316\316\317\331\331\332\343\343\345\346\346\347\343\343\347\355\355\357"
+ "\370\370\371\202\370\370\370\13\354\354\357\334\334\341\343\343\347\356\356"
+ "\361\354\354\360\352\352\356\356\355\361\350\350\355\325\325\334\336\336"
+ "\344\367\367\370\203\373\373\373\12\365\365\367\322\322\332\307\307\320\330"
+ "\330\337\346\346\355\350\350\356\341\341\347\315\315\326\276\276\311\342"
+ "\342\347\203\373\373\373\15\372\372\372\373\373\373\356\355\361\300\277\311"
+ "\273\273\305\323\323\334\343\342\351\342\342\351\321\321\331\271\271\305"
+ "\324\324\335\370\370\370\373\373\373\203\372\372\372\202\373\373\373B\353"
+ "\353\357\317\317\326\321\321\330\344\344\350\355\355\361\352\352\357\340"
+ "\340\345\336\336\342\351\351\354\367\367\371\373\373\373\371\371\372\362"
+ "\362\365\354\354\356\345\345\346\312\312\315\246\246\250ttvHHIVUYIF[22?1"
+ "0A**8..9<>D_bW\221\227m\303\316h\355\367a\366\375c\344\363g\324\346a\324"
+ "\351^\321\351\\\316\351Y\313\350T\312\347S\306\346R\305\341N\301\340K\276"
+ "\334I\274\332F\270\327D\270\325D\267\322?\267\324?\264\323<\264\315D\274"
+ "\274\274\331\331\332\340\340\343\332\332\337\325\325\333\321\321\330\316"
+ "\315\325\312\312\322\335\335\343\370\370\372\373\373\373\362\362\364\322"
+ "\322\333\303\303\314\300\277\312\306\306\320\346\346\354\202\373\373\373"
+ "\20\356\356\362\331\331\341\326\326\337\341\341\351\366\366\370\373\373\373"
+ "\363\363\366\312\312\323\273\273\305\304\304\316\306\305\317\276\276\311"
+ "\311\311\322\351\351\357\365\365\370\372\372\373\202\373\373\373\22\371\371"
+ "\372\357\357\364\346\346\353\320\320\326\312\312\320\311\311\317\302\302"
+ "\310\257\257\265\237\237\243\227\227\230\205\217\"\230\243'\255\273,\300"
+ "\3160\313\3323\320\3404\322\3425\334\3558\377\335\3568\303\335\3568\34\336"
+ "\356=\353\365\215\347\356\231\214\215\210\216\216\220\240\240\241\262\262"
+ "\264\304\304\304\321\321\322\334\334\335\345\345\347\344\344\347\347\347"
+ "\351\361\361\364\372\372\372\373\373\373\370\370\371\352\352\356\340\340"
+ "\344\351\351\355\360\360\364\354\354\360\355\355\361\360\360\364\343\343"
+ "\350\325\325\334\353\353\357\373\373\374\203\374\374\374\12\355\355\361\314"
+ "\314\324\316\316\326\337\337\346\352\352\357\347\347\355\332\332\341\304"
+ "\303\316\312\312\324\364\364\366\204\374\374\374\14\373\373\374\332\332\341"
+ "\267\266\302\304\304\317\333\333\343\341\341\351\330\330\340\301\301\313"
+ "\303\303\315\357\357\362\374\374\374\374\374\373\203\373\373\373=\374\374"
+ "\374\362\362\365\325\325\335\316\316\326\340\340\346\354\354\361\354\354"
+ "\360\342\342\347\336\336\343\351\351\355\371\371\372\374\374\374\372\372"
+ "\372\361\361\363\333\333\335\241\242\244SST\25\25\26\14\14\14\13\13\13''"
+ "'((4\220\222w\262\263\232\256\260\224\255\256\233\251\252\241\224\224\217"
+ "rqrQQ`klx\203\207\200\244\256e\327\353O\355\375]\325\354^\317\347\\\315\352"
+ "Y\312\351V\307\347T\305\343P\303\340M\302\336K\276\334J\275\333F\271\327"
+ "D\270\325D\265\323?\267\322?\264\324<\262\313C\275\275\275\335\335\335\357"
+ "\357\360\352\352\356\332\332\340\324\323\333\320\317\327\314\314\324\316"
+ "\316\326\351\351\355\202\374\374\374\27\345\345\354\312\312\323\304\304\316"
+ "\300\300\314\320\320\331\362\362\365\374\374\374\371\371\373\346\346\355"
+ "\327\327\340\333\333\343\356\356\363\374\374\374\373\373\373\335\335\344"
+ "\274\274\307\302\301\314\314\314\325\304\304\316\300\300\312\333\333\343"
+ "\363\363\371\371\371\373\203\374\374\374\20\363\363\366\353\352\357\325\325"
+ "\333\310\310\317\310\310\315\306\306\312\263\263\270\236\236\242\222\222"
+ "\226\205\217\"\231\244'\260\275,\302\3211\314\3343\320\3405\324\3456\377"
+ "\335\3568\304\335\3568\16\341\360N\355\366\232\321\331\231\200\200\202\223"
+ "\223\224\245\245\246\265\265\267\307\307\310\324\324\325\337\337\340\346"
+ "\346\350\345\345\350\353\353\356\366\366\367\202\373\373\373\13\367\367\371"
+ "\351\351\355\342\342\347\356\356\361\361\361\365\355\355\361\360\360\363"
+ "\357\357\363\336\336\344\332\332\340\366\366\367\204\375\375\375\11\343\343"
+ "\350\311\311\322\324\324\334\346\346\353\353\353\361\345\345\354\321\321"
+ "\332\300\300\313\335\335\343\203\375\375\375\13\374\374\374\375\375\375\367"
+ "\367\370\307\307\322\272\272\305\315\315\327\336\336\345\335\335\344\312"
+ "\312\324\271\271\305\334\334\343\202\375\375\375\203\374\374\374.\375\375"
+ "\375\374\374\375\337\337\345\314\314\324\331\331\337\351\351\356\355\355"
+ "\361\345\345\351\337\337\344\353\353\357\371\371\373\374\374\374\370\370"
+ "\370\330\330\333\215\214\217**+\1\1\1\5\5\5>>>\213\213\214\211\211\210oo"
+ "qXY\\\310\316o\374\374\200\365\371w\361\370t\350\356\200\330\335\221\275"
+ "\275\256\266\266\270\252\252\252\225\225\232\230\226\243\221\222\213\243"
+ "\262T\342\375N\334\373W\310\345U\310\346Q\304\344Q\304\341P\303\335L\277"
+ "\335J\273\333H\273\332G\202\271\326D(\266\323A\265\322?\264\322<\261\312"
+ "B\274\274\275\336\336\336\363\363\363\373\373\373\352\352\356\327\327\336"
+ "\322\322\331\320\320\327\312\312\323\326\326\336\365\365\367\375\375\375"
+ "\366\366\370\327\327\336\310\310\322\304\304\316\303\303\316\336\336\344"
+ "\372\372\373\375\375\375\363\363\367\337\337\347\330\330\340\346\346\355"
+ "\371\371\373\375\375\375\357\357\363\304\304\317\276\276\311\317\317\330"
+ "\314\314\325\300\300\312\315\315\326\356\356\364\370\370\374\374\374\375"
+ "\202\375\375\375\20\366\366\370\355\355\362\332\332\337\306\306\315\306\306"
+ "\314\310\310\313\267\267\274\240\240\244\217\217\223\205\220\"\234\250'\262"
+ "\300-\304\3221\315\3354\320\3405\326\3466\377\335\3568\304\335\3568\16\343"
+ "\361^\355\366\232\277\305\227\204\204\205\226\226\227\247\247\250\272\272"
+ "\273\311\311\313\327\327\330\340\340\341\346\346\350\346\346\351\356\356"
+ "\361\371\371\371\202\373\373\373\3\367\367\370\347\347\353\346\346\352\202"
+ "\362\362\366\6\356\356\362\361\361\365\355\355\361\332\332\340\341\341\347"
+ "\372\372\373\203\375\375\375\12\373\373\374\333\333\342\311\311\322\332\332"
+ "\341\350\350\356\353\353\361\340\340\347\311\311\323\304\304\316\353\353"
+ "\357\203\375\375\375\14\374\374\374\375\375\375\351\351\356\275\275\310\277"
+ "\277\312\323\323\334\335\335\345\324\324\336\275\275\310\300\300\314\356"
+ "\356\362\375\375\375\204\374\374\374X\375\375\375\362\362\366\320\320\331"
+ "\320\320\330\342\342\347\353\353\357\346\346\353\336\336\344\345\345\351"
+ "\370\370\371\373\373\373\350\350\353\222\222\224%%&\0\0\0\1\1\1ihk\301\300"
+ "\301\311\311\310\250\250\250\231\231\232\234\234\236\247\247\251\305\312"
+ "~\370\370\207\372\372\206\371\371\177\370\370v\356\360l\352\361m\342\351"
+ "\200\312\314\253\275\275\277\271\271\271\264\263\272\246\245\260\213\217"
+ "s\312\344K\340\375P\302\341N\304\342O\304\336M\300\337K\276\334I\274\332"
+ "G\272\327C\270\323C\267\324B\270\325C\266\323@\266\324>\260\310A\273\273"
+ "\274\334\334\335\363\363\363\375\375\375\370\370\372\343\343\350\323\323"
+ "\333\320\320\327\314\314\324\315\315\325\343\343\352\373\373\374\375\375"
+ "\375\345\345\353\313\313\325\310\310\321\304\304\316\312\312\324\356\356"
+ "\362\375\375\375\373\373\374\351\351\357\330\330\341\337\337\347\363\363"
+ "\370\375\375\375\371\371\373\320\320\331\275\275\310\316\316\326\323\323"
+ "\333\305\305\317\304\304\316\345\345\353\367\367\373\373\373\374\202\375"
+ "\375\375\20\371\371\372\357\357\363\336\336\344\307\307\317\304\304\313\307"
+ "\307\313\272\272\277\241\241\247\215\215\221\206\220\"\234\250'\264\303."
+ "\305\3242\317\3374\320\3405\330\3507\377\335\3568\304\335\3568\32\346\362"
+ "n\355\366\232\256\263\225\207\207\211\231\231\233\253\253\254\274\274\276"
+ "\315\315\316\330\330\332\342\342\344\347\347\350\351\351\353\362\362\364"
+ "\371\371\372\373\373\373\374\374\374\365\365\367\346\346\352\351\351\355"
+ "\364\364\367\362\362\365\360\360\363\363\363\367\350\350\355\332\332\341"
+ "\354\354\357\204\375\375\375\12\364\364\367\323\323\333\314\314\324\340\340"
+ "\346\353\353\360\351\351\357\330\330\340\302\302\314\316\316\327\370\370"
+ "\371\202\375\375\375\1\374\374\374\202\375\375\375\12\332\332\341\267\267"
+ "\303\306\306\321\327\327\337\331\331\342\310\310\323\266\266\302\326\326"
+ "\337\373\373\374\375\375\375\203\374\374\374\15\375\375\375\374\374\374\337"
+ "\337\346\314\314\324\331\331\340\350\350\354\347\347\354\337\337\344\341"
+ "\341\346\363\363\365\366\366\366\267\267\27288;\202\0\0\0)665\277\277\300"
+ "\333\333\333\310\310\310\261\261\262\262\262\264\266\266\267\265\265\266"
+ "\244\244\244~\200oZ]TY]Px{d\222\230f\320\326l\362\367c\352\366e\335\352e"
+ "\340\346\220\311\311\306\306\306\307\277\277\301\260\257\271\205\204\205"
+ "\265\307X\343\375N\301\337J\301\335M\277\335J\275\335J\273\331G\271\330E"
+ "\266\323C\267\324B\270\325C\266\323@\266\324=\256\307@\273\273\274\332\332"
+ "\333\361\361\362\202\375\375\375\37\363\363\367\335\335\343\321\321\330\315"
+ "\315\325\312\312\323\322\322\332\361\361\365\375\375\375\364\364\367\327"
+ "\327\336\312\312\324\310\310\323\302\302\315\332\332\342\373\373\374\375"
+ "\375\375\364\364\370\336\336\346\331\331\342\353\353\361\373\373\374\375"
+ "\375\375\337\337\346\277\277\312\311\311\323\330\330\340\315\315\326\301"
+ "\301\314\330\330\340\364\364\371\371\371\374\202\374\374\375\20\372\372\373"
+ "\361\361\365\343\343\350\312\312\322\301\301\310\307\307\312\276\276\302"
+ "\246\246\252\214\214\221\206\221#\236\253(\266\304.\306\3262\316\3374\320"
+ "\3415\331\3527\377\334\3568\304\334\3568\25\347\363|\355\366\232\236\241"
+ "\222\214\214\215\234\234\236\255\255\260\300\300\301\320\320\321\332\332"
+ "\334\343\343\344\346\346\350\352\352\355\366\366\367\373\373\373\374\374"
+ "\374\374\374\375\363\363\366\347\347\354\355\355\361\366\366\371\363\363"
+ "\366\202\362\362\366\3\344\344\351\335\335\343\362\362\365\204\375\375\375"
+ "\11\354\354\360\316\316\326\321\321\331\346\346\354\354\354\362\347\347\355"
+ "\320\320\331\277\277\312\335\335\344\203\375\375\375\14\374\374\374\375\375"
+ "\375\371\371\372\312\312\324\271\271\304\314\314\326\330\330\340\322\322"
+ "\332\276\276\310\276\276\311\354\354\360\375\375\375\204\374\374\374\14\375"
+ "\375\375\363\363\366\322\322\331\321\321\331\340\340\346\347\347\354\337"
+ "\337\345\334\334\342\354\354\357\345\345\350qqt\12\12\12\202\0\0\0#\200\200"
+ "\200\331\331\331\310\310\310\264\264\264\272\272\273\267\267\272\210\210"
+ "\211BBE\34\34\35""88;{y\202\210\210\207zz{WV^aah\207\211\214\221\226{\311"
+ "\325]\371\374h\322\346R\334\350x\330\331\304\323\323\324\316\316\317\256"
+ "\256\263wu}\253\271g\346\375N\274\334A\274\334J\274\331H\273\332H\271\326"
+ "E\267\324C\267\324B\202\266\323B\6\271\326?\254\306@\273\273\274\332\332"
+ "\333\356\356\360\373\373\374\202\375\375\375\6\355\355\361\327\327\336\316"
+ "\316\327\312\312\323\310\310\321\342\342\350\202\374\374\374\26\346\346\355"
+ "\315\315\327\316\316\326\310\310\321\313\313\325\360\360\364\375\375\375"
+ "\373\373\374\347\347\357\330\330\341\342\342\352\370\370\372\375\375\375"
+ "\355\355\362\306\306\320\304\304\316\331\331\341\327\327\337\304\304\317"
+ "\314\314\325\357\357\365\371\371\374\202\374\374\375\20\373\373\373\363\363"
+ "\366\347\347\354\317\317\326\276\276\306\304\304\311\300\300\303\252\252"
+ "\256\216\216\223\206\221\"\237\254(\270\307.\306\3272\316\3364\317\3404\331"
+ "\3537\377\333\3557\304\333\3557\16\351\364\210\354\365\231\220\222\213\217"
+ "\217\220\237\237\240\261\261\262\303\303\304\321\321\323\334\334\335\345"
+ "\345\346\350\350\352\355\355\360\367\367\370\373\373\373\202\374\374\374"
+ "\12\361\361\364\350\350\354\360\360\363\366\366\371\363\363\366\364\364\367"
+ "\362\362\366\340\340\346\341\341\347\370\370\372\204\375\375\375\11\347\347"
+ "\354\314\314\325\326\326\335\351\351\356\354\354\362\343\343\351\312\312"
+ "\323\302\302\315\354\354\360\203\375\375\375\14\374\374\374\375\375\375\354"
+ "\354\360\276\276\312\274\274\307\317\317\331\325\325\337\311\311\323\267"
+ "\267\303\320\320\331\371\371\371\375\375\375\203\374\374\374\202\375\375"
+ "\375\11\345\345\352\314\314\324\330\330\336\343\343\351\342\342\350\332\332"
+ "\340\341\341\346\305\305\310??@\203\0\0\0\16\227\227\230\334\334\334\267"
+ "\267\267\274\274\274\274\274\300xyz\34\34\35\1\1\1\10\10\11mmnc`p\230\233"
+ "w\272\272\263\300\300\300\202\306\306\306M\263\263\263\262\262\271\207\207"
+ "\213\261\270k\367\375k\312\344K\325\347m\334\336\300\327\327\327\326\326"
+ "\327\255\255\257ZVc\255\266q\336\375P\271\331C\274\332I\274\330F\271\326"
+ "D\267\324C\267\325B\266\323B\266\323A\272\327?\253\304>\273\273\274\332\332"
+ "\333\356\356\360\367\367\372\374\374\374\375\375\375\371\371\373\345\345"
+ "\351\321\321\330\313\313\324\307\307\320\325\325\334\366\366\370\375\375"
+ "\375\363\363\366\323\323\334\320\320\330\317\317\330\304\304\320\341\341"
+ "\347\374\374\375\375\375\375\361\361\365\333\333\344\335\335\346\363\363"
+ "\367\375\375\375\367\367\370\320\320\330\301\301\314\332\332\342\340\340"
+ "\347\314\314\325\304\304\316\345\345\353\370\370\375\373\373\375\375\375"
+ "\375\373\373\373\365\365\370\353\353\357\323\323\331\275\275\305\301\301"
+ "\307\302\301\304\256\256\261\221\221\225\207\223\"\242\257)\272\311.\310"
+ "\3303\316\3374\320\3414\377\333\3557\304\333\3557\33\334\356@\353\365\225"
+ "\341\352\231\204\204\204\221\221\223\241\241\243\263\263\264\305\305\306"
+ "\323\323\324\336\336\337\344\344\346\351\351\353\360\360\362\370\370\370"
+ "\373\373\373\374\374\374\373\373\374\360\360\364\351\351\355\362\362\366"
+ "\366\366\371\363\363\367\365\365\370\360\360\364\336\336\344\346\346\353"
+ "\373\373\374\203\375\375\375\4\373\373\374\341\341\350\314\314\325\333\333"
+ "\342\202\353\353\361\4\336\336\345\305\305\317\313\313\325\364\364\366\202"
+ "\375\375\375\6\374\374\374\375\375\374\375\375\375\337\337\345\272\271\304"
+ "\300\300\314\202\321\321\332\3\300\300\314\272\272\306\343\343\350\202\375"
+ "\375\375\203\374\374\374\12\375\375\375\371\371\371\327\327\336\315\315\326"
+ "\334\334\343\343\343\351\335\335\343\333\333\342\237\237\241\25\25\26\202"
+ "\0\0\0/\12\12\13bbb\267\267\266\262\262\262\301\301\301\244\243\250..0\0"
+ "\0\0\1\1\1||}\320\320\320\261\261\262}}~\261\271[\357\365o\344\352\211\322"
+ "\322\310\324\324\326\322\322\324\313\313\314\263\262\266QP`\253\260s\352"
+ "\375d\315\355K\327\353e\302\302\265\330\330\332\332\332\333\256\255\256M"
+ "KW\265\276r\316\361D\271\331G\273\331G\270\327D\267\324C\270\323B\266\323"
+ "B\266\323A\271\330A\251\303>\274\274\274\333\333\334\357\357\360\370\370"
+ "\372\371\371\373\202\375\375\375.\363\363\366\331\331\340\313\313\323\310"
+ "\310\321\313\313\324\353\353\357\375\375\375\371\371\373\335\335\345\320"
+ "\320\331\325\325\337\312\312\324\322\322\333\366\366\370\375\375\375\367"
+ "\367\372\341\341\351\332\332\343\354\354\362\374\374\375\373\373\374\334"
+ "\334\343\277\277\313\327\327\337\345\345\354\325\325\335\302\302\315\333"
+ "\333\342\367\366\372\372\372\375\375\375\375\373\373\373\367\367\370\355"
+ "\355\361\330\330\335\275\275\305\277\276\305\302\302\305\261\261\264\224"
+ "\224\227\207\223!\242\260(\271\313.\307\3311\314\3372\320\3443\377\331\355"
+ "5\304\331\3555\32\335\357J\353\365\230\322\333\231\203\203\204\224\224\225"
+ "\242\242\244\264\264\267\310\310\311\325\325\326\336\336\340\344\344\346"
+ "\352\352\354\361\361\363\371\371\372\373\373\373\374\374\374\372\372\374"
+ "\360\360\363\354\354\360\365\365\370\366\366\371\365\365\371\366\366\372"
+ "\354\354\361\337\337\345\355\355\361\204\375\375\375\12\370\370\371\333\333"
+ "\342\316\316\326\340\340\347\355\355\363\352\352\360\327\327\337\302\302"
+ "\315\332\332\342\373\373\374\202\375\375\375\14\374\374\374\375\375\375\370"
+ "\370\372\320\320\332\267\267\302\305\305\320\321\320\333\314\314\325\271"
+ "\271\305\306\306\320\365\364\370\375\375\375\204\374\374\374k\375\375\375"
+ "\355\355\361\317\317\326\321\321\332\337\337\344\340\340\345\331\331\340"
+ "\343\343\347mmm\4\4\5\0\0\1\0\0\0jjkcbc\261\261\262\306\306\306\220\220\222"
+ "\13\13\13\0\0\0\26\27\30\237\236\237\331\330\331\265\265\266\264\264\265"
+ "\277\277\277\264\272n\371\372}\335\344a\335\347\200\320\320\315\331\331\333"
+ "\333\333\335\322\322\323\237\252p\277\317d\343\375d\364\375[t\2065}}}\324"
+ "\324\325\340\340\342\333\333\335\273\304\177\263\314H\277\340H\271\327F\267"
+ "\326E\271\323D\267\325C\266\323B\266\323C\267\323A\271\327A\246\300=\274"
+ "\274\274\333\333\335\357\357\361\370\370\372\367\367\372\372\372\374\375"
+ "\375\375\373\373\374\347\347\355\317\317\326\311\311\321\307\307\320\337"
+ "\337\346\373\373\374\375\375\375\350\350\356\322\321\333\330\330\340\323"
+ "\323\334\311\311\324\352\352\360\375\375\375\374\374\374\352\352\360\332"
+ "\332\343\347\347\356\372\372\374\375\375\375\351\351\357\301\301\314\323"
+ "\323\334\351\351\360\337\337\347\306\306\320\317\317\330\361\361\366\373"
+ "\373\375\374\374\375\373\373\373\367\367\370\357\357\363\335\335\342\276"
+ "\276\305\273\273\302\301\301\304\263\263\266\227\227\232\207\224\40\242\262"
+ "'\272\312-\307\3310\313\3362\317\3432\377\330\3544\304\330\3544\25\336\357"
+ "U\353\365\230\306\315\227\205\205\207\226\226\227\245\245\247\267\267\271"
+ "\311\311\312\327\327\330\336\336\340\346\346\347\352\352\355\362\362\365"
+ "\371\371\372\373\373\373\374\374\374\371\371\373\356\356\363\355\355\361"
+ "\366\365\371\367\367\372\202\366\366\372\3\351\351\356\341\341\347\364\364"
+ "\366\204\375\375\375\11\365\365\367\327\327\336\321\321\331\344\344\352\355"
+ "\355\363\350\350\356\322\322\332\305\305\317\347\347\353\203\375\375\375"
+ "\12\374\374\374\375\375\375\362\362\365\305\305\320\270\270\304\310\310\322"
+ "\317\317\331\306\306\317\267\267\304\326\326\335\202\375\375\375\203\374"
+ "\374\374\13\375\375\375\374\373\374\340\340\346\313\313\323\326\326\336\335"
+ "\335\344\332\332\341\334\334\342\356\356\361\246\246\246RRS\202\0\0\0_''"
+ "(\247\247\247\277\277\277\327\327\327xxx###\0\0\0...\256\256\257\250\250"
+ "\251\275\275\276\322\322\323\332\332\332\260\266l\367\372v\340\351n\326\343"
+ "_\331\337\222\321\321\323\335\335\330\332\344\207\334\364b\346\375c\366\375"
+ "[x\211833:\246\245\250\322\322\323\342\342\344\335\347\225\314\351N\274\336"
+ "B\275\333I\302\342A\267\324C\266\321D\266\323C\267\324A\265\322@\264\322"
+ "@\271\326@\244\277<\274\274\274\334\334\335\360\360\361\371\371\373\370\370"
+ "\372\367\367\372\374\374\375\375\375\375\364\364\367\330\330\336\312\312"
+ "\323\306\306\317\322\322\333\365\365\370\375\375\375\362\362\366\326\326"
+ "\337\331\331\342\332\332\344\313\313\325\335\335\344\372\372\373\375\375"
+ "\375\362\362\367\335\335\345\342\342\352\367\367\372\375\375\375\361\361"
+ "\364\307\306\321\316\316\330\353\353\361\350\350\357\314\314\326\307\307"
+ "\321\350\350\356\373\373\375\374\374\375\373\373\373\370\370\371\360\360"
+ "\364\340\340\345\300\300\307\272\272\300\300\300\303\266\266\270\232\232"
+ "\236\207\224\40\242\262'\271\313-\306\331/\311\3351\320\3442\377\326\353"
+ "3\304\326\3533\24\336\357^\352\364\227\272\277\226\210\210\211\231\231\232"
+ "\247\247\250\271\271\273\312\312\313\327\327\330\337\337\341\346\346\350"
+ "\354\354\357\364\364\366\372\372\373\373\373\373\374\374\374\370\370\373"
+ "\357\357\363\356\356\362\367\366\371\202\367\367\372\4\366\366\371\350\350"
+ "\355\344\344\351\370\370\371\204\375\375\375\11\363\363\366\324\324\334\323"
+ "\323\333\347\347\355\356\356\363\345\345\354\315\315\326\312\312\324\357"
+ "\357\363\203\375\375\375\14\374\374\374\375\375\375\355\355\360\276\275\311"
+ "\271\271\305\311\310\323\314\314\326\277\277\312\271\271\305\346\345\353"
+ "\375\375\375\375\374\374\203\374\374\374:\375\375\375\367\366\370\326\326"
+ "\335\315\315\325\330\327\337\334\334\342\330\330\337\343\343\350\366\366"
+ "\367\350\350\350rqr\27\26\27\0\0\0\1\1\1\200\200\201\305\305\305\333\333"
+ "\334\257\257\261mnn\0\0\0\2\2\2\200\200\202\263\263\265\323\323\323\350\350"
+ "\350\350\350\351\266\274q\360\372o\334\347h\335\354h\312\341R\325\331\235"
+ "\340\350\177\320\347_\346\375g\346\375Nt\204:!!*\215\215\217\276\276\277"
+ "\323\323\325\336\346\222\272\327F\262\323B\316\356M\310\351@\251\301G\305"
+ "\3515\277\337;\264\320?\263\320A\263\322?\261\317?\266\327?\242\274<\274"
+ "\274\275\334\334\335\360\360\361\202\371\371\3730\367\367\372\371\371\374"
+ "\375\375\375\373\373\373\344\344\352\314\314\325\307\307\317\315\315\326"
+ "\355\355\362\375\375\375\370\370\372\333\333\343\331\331\341\340\340\351"
+ "\320\320\333\322\322\334\364\364\367\375\375\375\367\367\372\342\342\352"
+ "\340\340\350\364\364\370\375\375\375\366\366\370\315\315\327\313\313\325"
+ "\352\352\360\356\356\364\324\324\334\303\303\316\340\341\347\373\373\375"
+ "\374\374\375\372\372\373\370\370\371\361\361\364\343\343\350\303\303\312"
+ "\267\267\276\300\300\302\266\266\270\237\237\240\206\224!\242\264'\272\316"
+ ".\305\3331\310\3362\317\3452\377\324\3533\304\324\3533\23\337\360h\351\364"
+ "\227\254\262\225\212\212\213\231\231\232\250\250\251\272\272\274\313\313"
+ "\315\326\326\330\336\336\340\350\350\352\355\355\360\365\365\367\372\372"
+ "\373\373\373\374\375\375\375\370\370\372\357\357\363\360\360\364\202\367"
+ "\367\372\5\367\367\373\365\365\370\346\346\354\350\350\356\371\371\373\204"
+ "\375\375\375\11\360\360\365\323\323\333\327\327\337\352\352\360\356\356\364"
+ "\343\343\352\311\311\322\322\322\333\371\370\373\202\375\375\375\14\375\374"
+ "\375\374\374\374\375\375\375\345\345\353\271\271\304\274\274\307\312\311"
+ "\325\310\310\321\272\272\306\301\301\314\363\363\364\375\375\375\204\374"
+ "\374\374\5\375\375\375\360\360\363\316\316\326\320\320\327\332\332\340\202"
+ "\331\331\337\5\355\355\361\373\373\373\363\363\363\240\240\240qpq\202\0\0"
+ "\0""4\26\26\27\272\272\273\323\323\325\324\324\326pppRRS\0\0\0\25\25\25\252"
+ "\252\254\327\327\327\353\353\354\350\350\352\276\307|\346\366d\327\350b\327"
+ "\351e\322\350`\317\346U\325\360^\356\375`\266\335+frD21>\220\217\220\274"
+ "\274\274\321\322\307\327\342\200\264\325>\275\333H\333\375M\255\321*U^8\200"
+ "\200\207\224\232r\255\3136\304\352.\270\3329\262\315?\261\317?\266\327>\237"
+ "\271:\274\274\274\334\334\335\360\360\361\371\371\373\372\372\374\370\370"
+ "\372\367\367\372\373\373\374\375\375\375\357\357\363\324\324\333\202\310"
+ "\310\321\1\344\344\351\202\373\373\374%\344\344\351\331\331\341\344\344\353"
+ "\332\332\343\315\315\327\350\350\356\375\375\375\372\372\374\352\352\361"
+ "\340\340\350\361\361\365\375\375\375\373\373\374\326\326\337\310\310\322"
+ "\350\350\357\364\364\371\336\336\346\304\304\316\327\327\337\371\371\374"
+ "\375\375\375\372\372\373\371\371\371\362\362\365\347\347\353\306\306\314"
+ "\266\266\274\277\277\302\270\270\270\241\241\242\206\224\40\242\264&\272"
+ "\317,\303\331.\307\3350\316\344/\377\322\3510\304\322\3510\23\337\357o\350"
+ "\363\226\243\246\222\214\214\215\234\234\235\250\250\252\273\273\275\314"
+ "\314\316\326\326\331\337\337\341\351\351\353\356\356\360\365\365\367\371"
+ "\371\373\373\373\374\374\374\375\367\367\372\357\357\363\361\361\365\202"
+ "\367\367\372\7\367\367\373\363\363\367\346\346\353\355\355\362\373\373\374"
+ "\374\374\375\373\373\375\202\375\375\375\10\355\355\362\323\323\333\332\332"
+ "\342\354\354\362\356\356\363\337\337\346\310\310\322\334\334\342\202\375"
+ "\375\375\203\375\374\375\12\374\374\375\335\335\344\266\266\302\277\277\313"
+ "\312\312\325\304\304\316\270\270\304\314\314\326\370\370\371\375\375\375"
+ "\203\374\374\374\202\374\374\375\14\347\347\354\313\313\323\321\321\331\330"
+ "\330\337\326\326\335\335\335\343\365\365\367\375\375\375\370\370\370\351"
+ "\351\352zz{WWX\202\0\0\0,[Z\\\306\306\310\321\321\323\257\257\260\201\202"
+ "\202'%'\0\0\0BBB\305\305\306\335\335\336\337\337\341\273\306y\342\367^\320"
+ "\346_\322\352_\330\363a\344\375_\321\370;}\226\23x}oljz\250\250\246\300\300"
+ "\301\336\336\271\321\342n\260\324;\313\353P\326\373=\204\241(MPEUT[\232\231"
+ "\233\233\231\240\211\210\212\220\232a\263\3241\266\335,\254\3129\266\326"
+ ">\234\267:\272\272\273\334\334\335\360\360\361\371\371\373\202\372\372\374"
+ "\20\367\367\371\371\371\373\375\375\375\367\367\372\337\337\346\313\313\324"
+ "\310\310\320\333\333\343\370\370\372\375\375\375\352\352\361\332\332\343"
+ "\345\345\355\343\343\354\320\320\332\337\337\345\202\374\374\375\35\361\361"
+ "\365\341\341\351\356\356\363\374\374\375\375\375\375\336\336\344\307\307"
+ "\321\347\347\356\370\370\375\351\351\360\310\310\322\316\316\330\364\364"
+ "\370\375\375\375\372\372\373\371\371\371\363\363\365\351\351\356\311\311"
+ "\317\264\264\273\275\275\301\270\270\270\242\242\243\204\224\37\242\266&"
+ "\271\320+\303\333.\305\335/\315\345.\377\320\351/\304\320\351/\24\340\360"
+ "w\347\363\225\230\233\216\216\216\217\234\234\236\252\252\254\273\273\275"
+ "\314\314\316\325\325\327\337\337\342\351\351\353\357\357\361\364\364\367"
+ "\371\371\373\372\372\374\373\373\375\366\366\371\360\360\364\362\362\365"
+ "\366\366\371\202\367\367\372\20\361\361\365\347\347\354\361\361\365\374\374"
+ "\375\373\373\375\370\370\374\374\374\375\375\374\375\353\353\360\324\324"
+ "\334\334\334\343\355\355\363\355\355\362\334\334\343\311\311\323\342\342"
+ "\351\202\375\375\375\13\375\374\375\374\374\374\374\374\375\373\373\374\325"
+ "\325\336\265\265\302\300\300\313\313\313\324\301\301\314\266\266\302\327"
+ "\327\337\202\374\374\375\203\374\374\374m\374\374\375\373\373\374\337\337"
+ "\345\313\313\324\322\322\332\327\327\336\326\326\334\343\343\350\374\374"
+ "\375\375\375\375\373\373\373\361\361\363\312\312\314}|}334\0\0\0\1\1\2\202"
+ "\203\204\311\311\314\320\320\322\222\222\223\201\200\201+*-\0\0\0""111\267"
+ "\266\274\315\315\317\271\305y\361\373X\342\375V\332\375I\305\3467\224\261"
+ ",v\200U\254\253\267\261\261\271\256\256\257\277\277\274\341\351\216\277\330"
+ "N\265\331=\326\372L\255\320\34fu2__atty\263\263\264\276\276\276\301\301\302"
+ "\252\251\260\216\214\235tr\220\246\256o\275\335;\262\3238\231\2638\271\271"
+ "\271\334\334\335\360\360\361\371\371\373\372\372\374\373\373\375\370\370"
+ "\372\367\367\371\374\374\375\373\373\374\352\352\357\320\320\330\307\307"
+ "\321\327\327\336\363\363\370\375\375\375\361\361\366\333\333\344\346\346"
+ "\356\351\351\361\326\326\337\332\332\342\371\371\373\375\375\375\365\365"
+ "\370\343\343\353\353\353\362\373\373\375\375\375\375\342\342\350\307\307"
+ "\321\344\344\354\371\371\375\360\360\365\315\315\326\312\312\323\360\360"
+ "\363\375\375\375\372\372\373\370\370\371\363\363\365\353\353\357\312\312"
+ "\321\262\262\272\274\274\301\267\267\267\243\243\243\203\223\36\242\266%"
+ "\270\316+\302\332,\303\333-\314\344,\377\316\347-\304\316\347-'\340\357}"
+ "\346\362\224\223\225\214\217\217\220\236\236\237\252\252\254\274\274\276"
+ "\314\314\316\326\326\330\340\340\343\352\352\355\357\357\361\364\364\367"
+ "\370\370\372\371\371\373\372\372\375\366\366\371\360\360\364\362\362\366"
+ "\365\365\371\366\366\372\367\367\372\360\360\364\350\350\355\365\365\367"
+ "\375\375\375\370\370\373\366\366\373\372\372\375\374\374\375\351\351\356"
+ "\325\325\335\337\337\346\356\356\364\354\354\362\330\330\340\312\312\324"
+ "\351\351\356\375\375\375\202\374\374\375\13\374\374\374\375\375\375\372\372"
+ "\373\322\322\333\266\266\303\301\301\314\310\310\322\276\276\312\270\270"
+ "\305\341\341\346\375\375\375\204\374\374\374\10\375\375\375\372\372\373\332"
+ "\332\341\314\314\324\324\324\334\326\326\335\330\330\336\352\352\356\202"
+ "\375\375\375c\374\375\375\367\367\367\355\355\356\255\255\256\203\203\204"
+ "\32\32\32\0\0\0\6\6\6\237\237\242\307\307\312\320\320\320\207\207\207ccd"
+ "LLM\0\0\0\14\14\15jjo\214\216\200\200\213Y\222\235e\236\252}\244\247\241"
+ "\261\257\277\306\305\312\260\260\255\257\257\261\325\330\227\323\344f\265"
+ "\325B\310\355H\302\345-t\216\12rwb\201\200\207\227\227\232\266\266\267\312"
+ "\312\314\333\333\333\335\335\337\326\326\330\313\313\315\274\277\216\273"
+ "\310o\257\3166\263\3206\225\2606\267\267\271\334\334\335\360\360\361\370"
+ "\370\372\372\372\373\374\374\375\372\372\374\367\367\372\372\372\374\374"
+ "\374\375\361\361\365\327\327\336\311\311\322\323\323\333\360\360\364\375"
+ "\375\375\365\365\367\336\336\347\346\346\356\355\355\363\335\335\346\327"
+ "\327\341\363\363\367\375\375\375\370\370\373\347\347\357\352\352\361\372"
+ "\372\374\375\375\375\347\347\354\310\310\322\342\342\352\372\372\375\365"
+ "\365\371\324\324\335\310\310\322\354\354\360\375\375\375\372\372\373\370"
+ "\370\371\363\363\365\354\354\357\315\315\323\262\262\272\273\273\277\267"
+ "\267\267\243\243\243\201\222\35\241\266%\270\317*\301\332+\303\333,\312\344"
+ ",\377\314\346,\304\314\346,'\340\357\201\345\362\224\215\216\210\220\220"
+ "\221\236\236\240\252\252\254\273\273\276\312\312\315\324\324\327\340\340"
+ "\343\354\354\356\357\357\362\363\363\366\367\367\371\370\370\373\371\371"
+ "\374\365\365\371\361\361\365\362\362\366\365\365\370\366\366\372\366\366"
+ "\371\356\356\363\352\352\357\366\366\371\374\374\375\365\365\371\364\364"
+ "\370\371\371\374\374\374\375\350\350\355\326\326\335\341\341\350\357\357"
+ "\365\352\352\360\325\325\336\316\316\327\360\360\365\375\375\375\202\374"
+ "\374\375\13\374\374\374\375\375\375\371\371\372\316\316\327\267\267\303\304"
+ "\304\315\307\307\322\273\273\306\274\274\310\350\350\354\375\375\375\204"
+ "\374\374\374\10\375\375\375\371\371\372\326\326\335\315\315\325\323\323\333"
+ "\325\325\334\333\333\342\362\362\365\202\375\375\375c\374\374\375\371\371"
+ "\373\365\365\366\353\353\353\236\236\236\201\201\201\37\37\37\0\0\0\7\7\7"
+ "\231\231\233\314\314\316\324\324\324\235\235\235\207\207\207\200\200\201"
+ ",,+\24\24\26cbl}|\200\213\211\221\262\257\264\305\305\256\265\265\251\266"
+ "\266\250\320\325\207\322\342^\274\332G\273\340;\300\345-\203\243\6mz?\236"
+ "\236\240\250\247\260\264\264\264\301\301\302\317\317\320\337\337\340\354"
+ "\354\355\355\355\356\350\350\307\335\346v\275\3318\244\307#\247\3044\265"
+ "\3228\222\2532\266\266\267\333\333\334\360\360\361\370\370\372\371\371\373"
+ "\374\374\375\373\373\375\367\367\372\371\371\373\373\373\375\367\367\372"
+ "\340\340\346\313\313\325\322\322\333\354\354\361\375\375\375\367\367\371"
+ "\344\344\353\346\346\356\357\357\364\343\343\353\330\330\340\357\357\363"
+ "\375\375\375\373\373\374\354\354\362\352\352\361\371\371\373\375\375\375"
+ "\353\353\360\312\312\324\341\341\351\372\372\374\371\371\374\333\333\344"
+ "\307\307\321\347\347\355\375\375\375\373\373\373\370\370\371\364\364\365"
+ "\356\356\360\321\321\326\262\262\272\272\272\276\267\267\267\243\243\243"
+ "\200\221\35\242\271%\266\320)\277\331*\300\332+\310\344+\377\311\345+\304"
+ "\311\345+'\340\360\206\343\361\223\210\211\205\221\221\222\236\236\240\253"
+ "\253\255\273\273\276\312\312\315\324\324\327\340\340\343\354\354\356\356"
+ "\356\361\363\363\366\366\366\371\367\367\372\371\371\373\365\365\370\362"
+ "\362\365\362\362\366\364\364\367\365\365\371\365\365\370\356\356\362\354"
+ "\354\361\370\370\372\373\373\374\363\363\367\362\362\366\370\370\373\374"
+ "\374\375\351\351\356\327\327\337\343\343\352\357\357\365\351\351\357\324"
+ "\324\334\322\322\333\366\366\370\375\375\375\202\374\374\375\13\374\374\374"
+ "\375\375\375\370\370\372\314\314\325\271\271\304\304\304\317\307\307\321"
+ "\271\271\306\301\301\315\357\357\362\375\375\375\204\374\374\374\10\375\375"
+ "\375\365\365\370\323\323\333\316\316\326\324\323\333\326\326\334\340\340"
+ "\345\370\370\371\202\375\375\3751\374\374\375\373\373\374\372\372\372\365"
+ "\365\365\347\347\347\230\230\231sst;;=\0\0\0\3\3\3qqr\310\307\310\322\322"
+ "\322\306\306\307\254\254\254\212\212\212^^d\231\240d\304\311\217\304\310"
+ "\225\311\315\226\324\334w\321\341V\305\334J\270\330:\262\332.\253\320\33"
+ "\213\251\27s\200>\236\237\234\304\301\317\260\257\263\270\270\271\315\315"
+ "\316\335\335\335\343\343\344\347\347\351\354\354\306\334\344}\273\320G\236"
+ "\275-\236\276,\250\3044\247\3035\257\3214\215\2460\265\265\267\333\333\333"
+ "\360\360\362\202\370\370\372\202\374\374\375.\371\370\374\367\367\371\373"
+ "\373\374\371\371\374\347\347\354\321\321\331\322\322\333\352\352\357\375"
+ "\375\375\370\370\373\350\350\356\350\350\357\357\357\365\350\350\360\332"
+ "\332\343\354\354\361\375\375\375\374\374\375\357\357\365\352\352\362\371"
+ "\371\373\375\375\375\357\357\364\315\315\326\340\340\350\372\372\374\374"
+ "\374\375\343\343\352\311\311\322\342\342\351\374\375\375\373\373\373\370"
+ "\370\371\365\365\365\357\357\361\322\322\330\262\262\271\272\272\275\267"
+ "\267\267\243\243\243\200\221\34\241\271$\270\322)\277\332+\300\333+\307\344"
+ "*\377\310\345*\304\310\345*\24\341\360\213\343\361\223\203\204\202\222\222"
+ "\224\237\237\241\252\252\255\274\274\276\312\312\315\323\323\327\342\342"
+ "\345\354\354\356\356\356\361\364\364\366\365\365\370\367\367\371\370\370"
+ "\373\365\365\370\363\363\366\362\362\366\363\363\367\202\364\364\367\202"
+ "\356\356\363\2\371\371\373\372\372\374\202\360\360\365\13\367\367\372\374"
+ "\374\375\351\351\356\331\331\340\344\344\352\360\360\365\350\350\356\323"
+ "\323\334\325\325\335\367\367\371\375\375\375\202\374\374\375\13\374\374\374"
+ "\375\375\375\370\370\371\313\313\325\272\272\306\306\306\317\305\305\321"
+ "\272\272\305\307\307\322\365\365\370\375\375\375\204\374\374\374\10\375\375"
+ "\375\362\362\365\323\323\332\320\320\327\324\324\333\326\326\335\344\344"
+ "\351\371\371\372\202\375\375\375\11\374\374\375\373\373\374\374\374\375\373"
+ "\373\373\364\364\364\341\341\342\224\224\224cddYY[\202\0\0\0\36../\232\232"
+ "\234\304\304\305\305\305\307\276\276\300\257\257\260\251\267[\316\354=\301"
+ "\337=\271\3324\262\3260\252\320)\242\310\40\232\270,\217\241D\221\231s\252"
+ "\252\255\305\305\320\272\272\275\261\261\264\277\277\300\316\316\317\337"
+ "\337\340\352\354\334\345\351\246\325\340m\265\315C\233\275+\231\275'\244"
+ "\3021\202\244\3023\6\243\3020\256\3154\211\243.\265\265\266\332\332\333\361"
+ "\361\362\202\370\370\372/\374\373\374\374\374\375\372\372\374\367\367\371"
+ "\371\371\374\373\373\375\353\353\360\324\324\335\324\323\334\350\350\356"
+ "\374\374\375\371\371\373\352\352\361\352\352\360\360\360\365\354\354\363"
+ "\336\336\346\353\353\360\375\375\375\374\374\375\361\361\366\353\353\362"
+ "\370\370\372\375\375\375\362\362\366\320\320\331\340\340\350\372\372\374"
+ "\375\375\375\351\351\356\313\313\325\337\337\346\373\374\375\373\373\373"
+ "\370\370\371\365\365\365\360\360\361\324\324\330\263\263\272\272\272\276"
+ "\267\267\267\243\243\243\177\220\33\242\271$\266\321(\274\330*\277\334+\377"
+ "\305\343)\305\305\343)\32\340\357\215\341\360\222\201\201\201\222\222\224"
+ "\240\240\241\253\253\255\274\274\276\310\310\313\322\322\326\341\341\344"
+ "\353\353\355\355\355\360\363\363\366\365\365\367\366\366\371\367\367\372"
+ "\364\364\367\363\363\367\362\362\366\362\362\365\363\363\367\362\362\366"
+ "\356\356\362\357\357\364\372\372\374\367\367\373\202\355\355\362\13\365\365"
+ "\370\374\374\375\352\352\357\332\332\342\345\345\354\360\360\365\347\347"
+ "\355\323\323\334\332\332\341\370\370\372\375\375\375\202\374\374\375\13\374"
+ "\374\374\375\375\375\370\367\371\313\313\325\274\273\307\306\306\321\306"
+ "\305\320\273\273\306\316\316\327\372\372\374\375\375\375\204\374\374\374"
+ "\10\375\375\375\361\361\365\323\323\332\321\321\330\324\324\334\327\327\336"
+ "\347\347\354\372\372\374\202\375\375\375\203\374\374\375\10\375\375\375\372"
+ "\372\372\357\357\357\332\332\334\255\255\257rrsxxz/.0\202\0\0\0""8++,jjk"
+ "\244\244\247\267\270\271\226\236s\207\230E\213\235O\220\240Y\223\237c\244"
+ "\253\210\252\256\245\265\266\274\302\277\317\310\307\321\273\273\272\274"
+ "\274\274\304\304\304\312\312\313\325\325\305\335\342\237\327\341v\277\322"
+ "K\251\3055\227\271'\230\272&\243\3011\245\3023\244\3022\244\3000\244\301"
+ "0\243\2760\256\3142\207\237,\265\265\266\332\332\333\361\361\362\370\370"
+ "\372\367\367\371\373\373\374\374\374\375\373\373\374\366\366\371\367\367"
+ "\373\372\372\375\360\360\364\331\331\341\325\325\335\351\351\356\374\374"
+ "\375\372\372\373\355\355\363\353\353\362\357\357\366\356\356\364\342\342"
+ "\352\352\352\357\202\374\374\375\33\363\363\371\354\354\363\370\370\372\375"
+ "\375\375\364\364\370\322\322\334\341\341\351\372\372\374\375\375\375\356"
+ "\356\363\316\316\330\333\333\343\372\372\374\372\372\373\370\370\371\365"
+ "\365\365\360\360\361\325\325\331\263\263\273\273\273\277\267\267\267\242"
+ "\242\243~\220\32\241\271\"\265\321&\274\331)\275\333)\377\303\342&\305\303"
+ "\342&\20\337\357\216\340\360\221\200\200\200\222\222\224\241\241\242\252"
+ "\253\255\273\273\276\307\307\312\321\321\325\341\341\344\353\354\356\354"
+ "\354\357\362\362\365\363\363\366\365\365\370\366\366\371\202\364\364\367"
+ "\25\362\362\365\360\360\364\361\361\365\362\362\366\356\356\363\361\361\365"
+ "\372\372\374\365\365\370\353\353\360\353\352\360\363\363\367\374\374\375"
+ "\353\353\360\334\334\343\346\346\354\360\360\365\346\346\355\324\324\334"
+ "\336\336\345\372\372\373\375\375\375\202\374\374\375\11\374\374\374\375\375"
+ "\375\370\370\371\316\316\326\274\274\311\307\307\322\306\306\317\274\274"
+ "\307\322\322\332\202\374\374\375\204\374\374\374\10\375\375\375\361\361\364"
+ "\323\323\333\322\322\331\325\325\334\331\331\337\353\353\357\374\374\374"
+ "\202\375\375\375\203\374\374\375\202\375\375\375!\366\366\367\350\350\353"
+ "\335\335\337\316\316\320\236\236\237\227\230\227\177}\177BBD\3\3\3\2\2\3"
+ "\7\7\7//0nj|}|\206\215\214\230\236\235\252\256\254\274\277\277\276\303\303"
+ "\270\274\274\267\267\267\270\272\272\273\303\305\275\322\325\247\333\342"
+ "\214\317\334f\274\316I\247\3022\227\270&\224\264$\233\272)\241\275-\241\275"
+ "/\204\240\275.\7\237\275.\240\274.\256\314/\205\234+\266\266\266\332\332"
+ "\333\361\361\362\202\367\367\371\16\374\373\374\374\374\375\373\373\375\367"
+ "\367\372\366\366\371\371\371\374\363\363\370\336\336\345\330\330\337\351"
+ "\351\357\373\373\375\372\372\374\357\357\364\356\356\364\202\356\356\365"
+ "\40\346\346\356\350\350\357\373\372\374\374\374\375\365\365\372\356\356\365"
+ "\370\370\372\375\375\375\365\365\370\325\325\336\343\343\353\372\372\374"
+ "\375\375\375\361\361\366\322\322\333\332\332\342\372\372\373\372\373\373"
+ "\370\370\371\364\364\365\360\360\361\326\326\331\263\263\273\273\273\277"
+ "\267\267\267\242\242\243|\216\31\236\271!\263\321%\272\330(\274\332)\300"
+ "\340%\377\300\340$\304\300\340$\12\336\356\217\337\357\220\177\177\200\223"
+ "\223\224\240\240\242\252\251\254\272\272\275\306\306\311\321\321\324\342"
+ "\342\344\202\353\353\356\33\362\362\365\363\363\366\365\365\370\365\365\371"
+ "\363\363\367\364\364\370\362\362\366\357\357\364\360\360\364\360\360\365"
+ "\357\357\363\362\362\366\372\372\374\364\364\367\350\350\356\351\351\356"
+ "\362\362\366\374\374\375\355\355\362\335\335\344\346\346\354\360\357\365"
+ "\346\346\354\325\325\335\340\340\347\372\372\374\375\375\375\202\374\374"
+ "\375\11\374\374\374\375\375\375\371\371\372\320\320\330\276\276\311\307\307"
+ "\321\305\305\317\274\274\311\325\325\334\202\374\374\375\204\374\374\374"
+ "\10\375\375\375\362\362\365\325\325\334\323\323\333\327\327\335\331\331\340"
+ "\356\356\361\374\374\375\202\375\375\375\202\374\374\375\203\375\375\375"
+ "\37\370\370\371\356\356\361\352\352\354\342\342\345\335\335\335\313\313\313"
+ "\260\260\260\227\227\230\177\177\177jjkQQP32=\215\217y\270\270\270\266\265"
+ "\267\264\264\262\271\273\261\303\303\257\316\320\245\322\327\220\317\331"
+ "r\313\330V\274\320E\253\3026\232\270(\223\262\40\217\262\37\230\265'\237"
+ "\272*\237\274.\236\271-\203\236\273,\203\237\273,\7\237\273+\236\271-\253"
+ "\312.\202\231*\265\265\267\332\332\333\361\361\362\202\367\367\371\1\374"
+ "\373\374\202\373\373\375\15\367\367\372\365\365\370\371\371\374\365\365\371"
+ "\341\341\350\334\334\342\354\354\361\373\373\375\372\372\373\361\361\365"
+ "\357\357\365\356\356\365\355\355\364\202\350\350\360\36\372\372\374\374\374"
+ "\375\366\366\373\360\360\366\370\370\373\375\375\375\364\364\370\326\326"
+ "\337\346\346\355\373\373\375\375\375\375\363\363\367\325\325\336\332\332"
+ "\341\372\372\373\373\373\373\370\370\371\364\364\365\360\360\361\325\325"
+ "\331\264\264\274\274\274\300\267\267\267\242\242\243{\217\32\235\271#\262"
+ "\321'\272\331*\272\332+\276\340&\377\276\340%\304\276\340%\32\335\356\220"
+ "\336\357\220\177\177\200\222\222\223\237\237\241\251\251\254\271\271\273"
+ "\305\305\310\320\320\324\342\342\344\352\352\354\353\353\356\361\361\364"
+ "\363\363\366\364\364\367\365\365\370\362\362\366\365\365\370\362\362\365"
+ "\357\357\362\357\357\363\360\357\364\357\357\364\362\362\366\372\372\374"
+ "\363\363\366\202\347\347\354\13\360\360\364\374\373\375\356\356\363\337\337"
+ "\346\346\346\354\357\357\364\345\345\354\326\326\336\342\342\351\372\372"
+ "\374\375\375\375\202\374\374\375\11\374\374\374\375\375\375\371\371\372\323"
+ "\323\332\300\300\312\310\310\321\305\305\320\276\276\313\327\327\336\202"
+ "\374\374\375\204\374\374\374\10\375\375\375\363\363\367\330\327\336\325\325"
+ "\333\330\330\337\333\333\341\357\357\362\374\374\375\202\375\375\375\2\374"
+ "\375\375\374\374\375\203\375\375\375^\370\370\371\360\360\362\357\357\361"
+ "\354\354\356\356\356\357\351\351\351\335\335\335\316\316\317\261\261\262"
+ "\215\215\214yxzont\247\260V\310\332G\300\322H\272\317?\265\3127\261\3068"
+ "\242\2740\230\266&\224\263#\214\255\36\214\256\36\220\262!\226\265'\233\267"
+ "(\233\267*\232\271)\233\267(\234\271)\236\271+\235\270,\235\272,\234\267"
+ "+\236\271-\235\272,\234\272,\236\272-\235\270-\252\311.\201\230+\266\266"
+ "\267\333\333\334\361\361\362\366\366\370\367\367\371\374\374\374\373\373"
+ "\374\374\374\375\367\367\372\365\365\367\370\370\373\366\366\372\345\345"
+ "\352\337\337\346\355\355\363\373\372\375\372\372\374\362\362\367\360\360"
+ "\366\356\355\363\356\356\364\352\352\362\352\352\361\372\372\373\374\374"
+ "\375\367\367\373\362\362\367\371\371\373\375\375\375\364\364\370\331\331"
+ "\341\351\351\357\373\373\375\375\375\375\364\364\371\326\326\340\332\332"
+ "\341\372\372\373\373\373\373\370\370\371\364\364\365\360\360\361\325\325"
+ "\331\264\264\274\276\276\301\267\267\267\242\242\243{\217\32\233\270#\260"
+ "\321(\267\331*\271\333+\275\337&\377\274\337$\304\274\337$\16\334\356\215"
+ "\335\356\220\200\200\200\221\221\223\237\237\240\250\250\252\270\270\272"
+ "\303\303\307\317\317\323\341\341\343\350\350\353\351\351\354\360\360\363"
+ "\362\362\365\202\364\364\367\3\362\362\365\365\365\370\362\362\365\202\355"
+ "\355\361\5\357\357\363\360\360\364\363\363\367\371\371\374\361\361\364\202"
+ "\345\345\353\12\355\355\362\373\373\375\360\360\364\340\340\347\346\346\354"
+ "\356\356\364\345\345\354\327\327\337\345\345\353\373\373\374\203\374\374"
+ "\375\11\374\374\374\375\375\375\372\371\373\326\326\335\303\303\315\310\310"
+ "\322\307\306\320\302\302\314\333\333\341\202\374\374\375\204\374\374\374"
+ "\7\375\375\375\366\366\370\332\332\340\327\327\335\332\332\340\335\335\342"
+ "\361\361\363\210\375\375\375\30\371\371\372\361\361\363\357\357\362\360\360"
+ "\362\366\366\367\367\367\367\362\362\362\346\346\347\333\333\334\322\322"
+ "\324\313\313\314\307\307\310\241\256[\200\246\5\200\242\13\204\245\17\206"
+ "\251\21\210\250\22\216\256\26\223\262\33\225\264\35\230\265\40\232\266!\231"
+ "\267\40\202\232\271\"\40\232\270!\231\271#\232\273$\234\272#\233\274%\235"
+ "\276%\241\300)\243\302+\246\306.\252\3100\254\3121\254\3113\254\3122\273"
+ "\3333\203\233+\267\267\270\333\333\334\360\360\361\366\366\367\367\367\371"
+ "\374\374\374\373\373\374\374\374\375\370\370\372\363\363\367\367\367\372"
+ "\370\370\373\350\350\356\344\344\351\361\361\365\373\373\375\371\371\373"
+ "\202\362\362\367\2\353\353\362\355\355\363\202\354\354\363\14\371\371\373"
+ "\374\374\375\370\370\373\364\364\371\371\371\374\375\375\375\364\364\370"
+ "\333\333\344\353\353\361\373\373\375\375\375\375\366\366\372\202\332\332"
+ "\342\20\372\372\373\373\373\373\370\370\371\364\364\365\360\360\361\325\325"
+ "\331\266\266\275\300\300\302\267\267\267\242\242\243{\220\33\233\267#\262"
+ "\322(\272\332+\273\334+\275\337&\377\274\337#\304\274\337#\15\333\355\212"
+ "\335\356\217\200\200\200\221\221\222\237\237\241\247\247\251\264\264\266"
+ "\301\301\304\316\316\321\341\341\343\346\346\351\347\347\352\357\357\362"
+ "\202\362\362\365#\364\364\367\361\361\364\365\365\370\362\362\366\354\354"
+ "\360\353\353\360\356\356\363\361\361\365\363\363\367\370\370\373\357\357"
+ "\364\344\344\352\343\343\351\352\352\360\372\372\374\362\362\366\342\342"
+ "\351\346\346\354\355\355\363\345\345\353\331\331\341\347\347\355\373\373"
+ "\374\372\372\375\373\373\375\374\374\375\374\374\374\374\374\375\372\372"
+ "\373\332\332\341\304\304\316\311\311\323\307\307\321\304\304\316\334\334"
+ "\343\202\374\374\375\204\374\374\374\7\375\375\375\370\370\372\336\336\344"
+ "\330\330\336\333\333\341\336\336\344\361\361\364\210\375\375\375\17\372\372"
+ "\373\362\362\364\357\357\362\360\360\362\370\370\371\375\375\375\373\373"
+ "\373\366\366\367\356\356\357\350\350\351\343\343\344\336\336\337\251\264"
+ "i\225\263\14\226\262\31\202\224\262\26M\222\262\27\222\260\25\222\257\23"
+ "\220\257\23\220\256\21\214\257\20\220\260\22\215\254\17\214\254\16\213\252"
+ "\17\216\254\17\216\256\17\215\256\16\216\256\17\213\253\14\207\250\11\203"
+ "\242\7\201\240\4~\234\4}\233\4{\231\4{\230\4\203\245\3o\202\40\271\271\271"
+ "\334\334\335\357\357\360\365\365\366\370\370\371\374\374\374\373\373\374"
+ "\374\374\375\367\367\371\363\363\366\367\367\372\370\370\373\354\354\360"
+ "\350\350\355\363\363\367\372\372\375\367\367\372\363\363\367\362\362\367"
+ "\352\352\361\354\354\362\356\356\365\356\356\364\372\372\373\374\374\375"
+ "\371\370\374\365\365\372\372\372\374\375\375\375\363\363\367\335\335\345"
+ "\356\356\363\373\373\375\375\375\375\367\367\372\334\334\344\333\333\343"
+ "\372\372\373\373\373\373\370\370\371\364\364\365\357\357\361\323\323\330"
+ "\270\270\277\302\302\306\267\267\267\242\242\243{\220\35\232\266%\261\320"
+ "*\271\332+\273\334-\274\337'\377\273\337$\304\273\337$\15\332\355\207\334"
+ "\356\220\203\204\202\217\217\220\237\237\241\250\250\252\263\263\266\277"
+ "\277\301\314\314\317\337\337\342\346\346\351\346\346\352\357\357\362\202"
+ "\362\362\365\20\363\363\367\360\360\364\364\364\370\362\362\366\353\353\360"
+ "\352\352\357\355\355\362\361\361\365\363\363\367\367\367\373\356\356\363"
+ "\342\342\351\342\342\350\350\350\356\370\370\373\364\364\370\202\345\345"
+ "\353\21\354\354\362\345\345\354\332\332\342\350\350\356\373\373\374\370\370"
+ "\374\372\372\374\375\375\375\374\374\374\374\374\375\373\373\374\336\337"
+ "\345\306\306\320\311\311\323\310\310\322\306\306\317\335\335\344\202\374"
+ "\374\375\204\374\374\374\10\375\375\375\373\373\373\342\342\347\331\331\337"
+ "\335\335\342\340\337\345\361\361\364\374\374\375\207\375\375\375\5\373\373"
+ "\374\363\363\365\357\357\362\360\360\362\367\367\371\202\375\375\375\6\373"
+ "\373\373\365\365\367\364\364\365\361\361\362\352\352\354\230\231\215\202"
+ "\217\220\200\202\216\220\200=\214\217\177\214\217~\213\217~\213\217}\214"
+ "\220~\217\224\200\222\226\201\225\232\204\230\234\206\235\241\213\243\247"
+ "\220\246\253\224\250\254\226\247\253\226\244\250\222\240\244\216\234\240"
+ "\212\230\235\210\226\232\207\225\231\207\224\231\211\226\232\212\230\234"
+ "\214\235\241\223\301\301\303\341\341\341\360\360\362\364\364\366\370\370"
+ "\372\374\374\374\373\373\374\374\374\375\367\367\371\362\362\366\367\367"
+ "\372\371\371\374\356\356\363\355\355\361\366\366\372\371\371\374\366\366"
+ "\372\364\364\371\361\361\366\350\350\357\353\353\361\357\356\365\357\357"
+ "\366\372\372\374\374\374\374\371\371\374\367\367\374\372\372\374\374\374"
+ "\375\362\362\365\340\340\350\360\360\366\373\373\375\375\375\375\366\366"
+ "\372\336\336\344\336\335\345\202\372\372\373\16\370\370\371\364\364\365\357"
+ "\357\360\321\321\327\272\272\301\304\304\307\270\270\270\242\242\243|\220"
+ "\35\231\265%\262\320+\272\333-\274\335/\274\340(\377\273\337$\304\273\337"
+ "$*\330\354\202\334\356\220\205\206\201\216\216\220\236\236\237\246\246\250"
+ "\261\261\264\275\275\300\313\313\316\336\336\341\345\345\347\344\344\350"
+ "\355\355\361\361\361\364\362\362\365\363\363\367\357\357\363\364\364\370"
+ "\363\363\367\353\353\357\351\351\356\354\354\361\362\362\366\363\363\366"
+ "\366\366\372\356\356\363\341\341\350\341\341\347\346\346\354\367\367\372"
+ "\365\365\372\347\347\355\345\345\353\353\353\361\346\346\354\334\334\344"
+ "\350\351\356\372\372\374\366\366\373\372\372\374\375\375\375\374\374\374"
+ "\202\374\374\375\2\346\346\354\312\312\323\202\311\311\323\2\307\307\321"
+ "\337\337\344\202\374\374\375\204\374\374\374\10\375\375\375\373\373\373\346"
+ "\346\353\333\333\341\336\336\343\341\341\346\360\360\362\374\374\374\207"
+ "\375\375\375\25\374\374\374\365\365\366\357\357\362\360\360\362\366\366\367"
+ "\374\374\375\375\375\375\374\374\374\367\367\371\366\366\370\366\366\367"
+ "\360\360\362\350\350\351\327\327\327\307\307\307\275\275\276\270\270\271"
+ "\265\265\267\266\266\267\271\271\272\273\273\274\202\274\274\274G\272\272"
+ "\274\270\270\271\267\267\270\270\270\271\273\273\274\275\275\275\273\273"
+ "\274\265\265\266\264\264\266\272\272\273\274\274\275\273\273\274\266\266"
+ "\267\265\265\266\272\272\273\274\274\275\273\273\274\301\301\302\322\322"
+ "\322\350\350\351\361\361\363\363\363\366\372\372\373\374\374\374\373\373"
+ "\374\374\374\375\365\365\370\362\362\365\367\367\372\371\371\374\361\361"
+ "\364\361\361\365\370\370\373\367\367\373\364\364\371\365\365\372\360\360"
+ "\365\345\345\354\352\352\361\361\360\367\362\362\370\372\372\374\374\374"
+ "\374\371\371\374\370\370\374\373\373\374\374\374\375\360\360\364\342\342"
+ "\352\362\362\370\371\371\375\374\374\375\366\366\372\336\336\345\340\340"
+ "\347\372\372\374\372\372\373\370\370\371\365\365\365\356\356\360\317\317"
+ "\325\273\273\302\307\307\311\271\271\271\242\242\243}\221\35\233\265$\261"
+ "\320*\274\334-\275\336/\276\340(\377\274\337\"\304\274\337\"\26\327\353}"
+ "\335\356\217\210\212\203\213\213\215\235\235\236\245\245\247\257\257\262"
+ "\273\273\277\312\312\314\335\335\337\345\345\346\342\342\345\355\355\360"
+ "\361\361\364\361\361\365\362\362\366\356\356\362\363\363\366\364\364\367"
+ "\353\353\357\350\350\355\354\354\360\202\362\362\366\21\365\365\371\356\356"
+ "\363\341\341\347\337\337\346\343\343\351\364\364\370\367\367\373\351\351"
+ "\357\345\345\354\353\353\360\346\346\354\336\335\345\351\351\357\372\372"
+ "\374\364\364\372\370\370\373\375\375\375\202\373\373\374\7\375\375\375\355"
+ "\355\363\317\317\330\313\313\324\313\313\323\311\311\323\336\336\345\202"
+ "\374\374\375\204\374\374\374\10\374\374\375\374\374\374\355\355\361\335\335"
+ "\343\337\337\344\342\342\346\356\356\362\374\374\374\210\375\375\375\21\370"
+ "\370\371\361\361\363\357\357\362\363\363\366\373\373\374\375\375\375\374"
+ "\374\375\371\371\372\366\366\370\367\367\371\364\364\365\356\356\360\351"
+ "\351\352\343\343\343\337\337\337\334\334\335\331\331\332\202\326\326\330"
+ "\1\327\327\330\204\327\327\331\25\331\331\332\334\334\334\336\336\336\335"
+ "\335\335\327\327\331\323\323\324\327\327\331\334\334\335\335\335\336\332"
+ "\332\332\323\323\325\326\326\330\334\334\335\335\335\336\332\332\333\335"
+ "\335\336\347\347\350\361\361\362\362\362\364\364\364\366\373\373\373\203"
+ "\373\373\374\21\364\364\367\362\362\365\370\370\372\371\371\374\363\363\366"
+ "\365\365\370\371\371\373\365\365\371\363\363\367\366\366\373\356\356\364"
+ "\344\344\352\353\353\361\361\362\370\363\363\370\373\373\374\374\374\374"
+ "\202\371\371\374\32\373\373\374\374\374\375\357\357\362\346\346\354\363\363"
+ "\370\367\367\374\372\372\375\364\364\371\337\337\345\343\343\352\373\373"
+ "\375\372\372\373\370\370\371\365\365\365\356\356\357\315\315\324\276\276"
+ "\305\310\310\311\271\271\271\242\242\243\177\222\36\232\265&\261\320,\273"
+ "\334/\276\3371\277\341*\377\275\340\"\304\275\340\"\15\325\353v\335\357\217"
+ "\214\217\205\211\211\212\234\234\235\243\243\246\255\255\260\271\271\274"
+ "\306\306\312\332\332\334\344\344\346\342\342\345\354\354\357\202\361\361"
+ "\364\7\362\362\366\356\356\362\361\361\365\364\364\370\353\353\360\350\350"
+ "\354\353\353\360\202\362\362\366\34\364\364\370\356\356\363\340\340\347\337"
+ "\337\345\341\341\347\361\361\365\370\370\373\354\354\361\346\346\354\352"
+ "\352\360\347\347\355\337\337\347\351\351\356\372\372\374\364\364\370\365"
+ "\365\372\374\374\375\374\374\374\372\372\374\374\374\375\363\363\366\325"
+ "\325\335\315\315\325\314\314\325\313\313\324\335\335\344\372\372\374\374"
+ "\374\375\205\374\374\374\7\375\375\375\364\364\366\341\341\346\341\341\345"
+ "\343\343\347\355\355\360\373\373\374\210\375\375\375\5\373\373\373\363\363"
+ "\364\357\357\362\362\362\364\372\372\373\202\375\375\375\1\373\373\374\202"
+ "\367\367\371\4\366\366\367\362\362\364\361\361\363\364\364\364\202\363\363"
+ "\363\11\362\362\362\360\360\361\355\355\357\354\354\356\354\354\355\354\354"
+ "\356\356\355\357\360\360\361\362\362\362\202\363\363\363\23\356\356\357\347"
+ "\347\351\350\350\352\357\357\360\363\363\363\361\361\362\353\353\354\347"
+ "\347\350\355\355\356\363\363\363\362\362\362\356\356\360\362\362\363\366"
+ "\366\367\367\367\370\362\362\364\365\365\367\373\373\374\372\372\373\202"
+ "\373\373\374\5\364\364\366\363\363\365\371\371\372\372\372\374\364\364\367"
+ "\202\370\370\373\12\364\364\370\363\363\367\367\367\373\353\353\360\342\342"
+ "\351\354\354\362\363\363\371\364\364\370\373\373\375\373\373\374\202\372"
+ "\372\374\32\374\374\374\374\374\375\356\356\362\350\350\357\363\363\370\364"
+ "\364\372\367\367\375\363\363\370\340\340\346\347\347\355\374\374\375\372"
+ "\372\373\370\370\371\365\365\365\354\354\356\313\313\322\302\302\310\311"
+ "\311\312\271\271\271\243\243\244\177\222\40\231\263'\261\317.\275\3341\300"
+ "\3403\301\341,\377\276\340#\304\276\340#\15\324\352o\336\357\217\220\224"
+ "\210\206\206\210\231\231\233\243\243\245\253\253\256\270\270\273\306\306"
+ "\310\331\331\334\343\343\345\341\341\345\353\353\356\202\361\361\364\7\364"
+ "\364\367\355\355\361\360\360\364\365\365\371\355\355\361\347\347\354\352"
+ "\352\357\202\362\362\366\20\363\363\367\356\356\362\337\340\346\336\336\345"
+ "\337\337\346\356\356\363\370\370\373\356\356\363\347\347\355\351\351\357"
+ "\350\350\356\340\340\347\350\350\356\372\372\374\362\362\367\363\363\370"
+ "\202\374\374\375\12\371\371\374\372\372\374\366\366\370\333\333\342\317\317"
+ "\330\316\316\327\314\314\327\333\333\342\370\370\372\375\375\375\205\374"
+ "\374\374\7\375\375\375\370\370\371\345\345\352\342\342\347\344\344\351\354"
+ "\354\357\372\372\373\210\375\375\375\17\374\374\374\366\366\370\360\360\362"
+ "\360\360\363\370\370\371\374\374\375\375\375\375\374\374\374\371\371\372"
+ "\367\367\371\370\370\372\367\367\370\366\366\367\370\370\372\374\374\374"
+ "\203\375\375\375\202\374\374\374\202\373\373\374\1\374\374\374\202\375\375"
+ "\375\31\374\374\374\370\370\371\362\362\363\362\362\364\370\370\371\374\374"
+ "\374\374\374\375\367\367\371\361\361\363\362\362\364\372\372\373\375\375"
+ "\375\373\373\374\371\371\372\373\373\374\374\374\375\367\367\370\362\362"
+ "\364\370\370\371\374\374\374\371\371\373\373\373\374\372\372\373\362\362"
+ "\364\364\364\366\202\372\372\374\11\367\367\371\371\371\374\367\367\373\361"
+ "\361\366\363\363\367\366\366\371\347\347\355\341\341\350\355\355\363\202"
+ "\365\365\371\2\373\373\375\373\373\374\202\372\372\374\32\374\374\374\373"
+ "\373\375\356\356\363\354\354\362\362\361\366\363\363\370\365\365\373\361"
+ "\361\367\340\340\347\353\353\360\375\375\375\372\372\373\370\370\371\365"
+ "\365\365\354\354\356\312\312\320\307\307\314\313\313\313\271\271\271\244"
+ "\244\245\177\222\40\227\260'\257\314,\275\3330\300\3372\300\341-\377\276"
+ "\340!\304\276\340!\20\321\351d\336\357\216\224\231\211\204\204\205\230\230"
+ "\231\242\242\245\252\252\255\267\267\272\304\304\307\330\330\333\341\341"
+ "\344\340\340\344\353\353\356\361\361\364\360\360\364\363\363\366\202\355"
+ "\355\361\4\365\365\371\356\356\362\346\346\353\351\351\356\202\362\362\366"
+ "\10\361\361\366\356\356\363\340\340\346\336\336\344\335\335\344\351\351\357"
+ "\367\367\373\360\360\366\202\351\351\357\10\351\350\357\342\342\351\350\350"
+ "\357\372\372\374\362\362\366\361\361\365\374\374\375\375\375\375\202\371"
+ "\371\373\10\371\371\372\344\344\351\321\321\332\317\317\327\317\317\330\331"
+ "\331\340\364\364\367\375\375\375\205\374\374\374\3\375\375\375\373\373\374"
+ "\354\354\360\202\345\345\351\2\353\353\357\367\367\371\211\375\375\375\5"
+ "\373\373\373\363\363\365\360\360\362\364\364\366\373\373\374\202\375\375"
+ "\375\1\373\373\374\202\370\370\372\6\371\371\372\370\370\371\366\366\367"
+ "\367\367\370\372\372\373\374\374\374\206\375\375\375\16\374\374\374\372\372"
+ "\373\365\365\367\361\361\363\362\362\364\370\370\372\374\374\375\375\375"
+ "\375\372\372\373\362\362\364\360\360\362\366\366\370\374\374\375\375\375"
+ "\375\202\373\373\374\31\375\375\375\373\373\374\364\364\365\362\362\365\373"
+ "\373\373\373\373\374\371\371\373\374\374\374\370\370\372\362\362\364\365"
+ "\365\367\374\374\374\372\372\374\371\371\374\373\373\374\365\365\370\360"
+ "\360\364\366\366\371\364\364\367\344\344\352\342\342\350\357\357\364\365"
+ "\365\372\365\365\371\373\373\375\203\372\372\374\3\374\374\375\371\371\373"
+ "\356\356\363\202\356\356\364\25\360\360\365\362\362\370\357\357\365\340\340"
+ "\350\356\356\363\375\375\375\372\372\373\370\370\371\365\365\365\350\350"
+ "\354\311\311\320\314\314\321\313\313\313\271\271\272\244\244\245~\221\40"
+ "\226\256'\256\312.\273\3301\300\3374\300\3400\377\275\337\"\304\275\337\""
+ "4\316\347[\335\356\217\232\240\211\200\200\202\224\224\225\240\240\243\252"
+ "\252\255\265\265\270\302\302\306\326\326\331\342\342\344\340\340\344\352"
+ "\352\355\357\357\363\360\360\363\363\363\366\356\356\362\353\353\357\364"
+ "\364\370\360\360\364\347\347\353\350\350\355\361\361\365\362\362\366\360"
+ "\360\364\356\356\363\340\340\346\336\336\345\335\335\344\345\345\353\365"
+ "\365\372\362\362\367\353\353\361\352\351\357\352\352\357\344\344\353\350"
+ "\350\356\371\371\374\362\362\366\356\356\364\373\373\374\375\375\375\371"
+ "\371\373\366\366\372\372\372\374\354\354\361\326\326\335\321\321\331\320"
+ "\320\331\330\330\337\362\362\365\375\375\375\205\374\374\374\202\375\375"
+ "\375\5\364\364\367\347\347\354\347\347\352\352\352\356\365\365\367\212\375"
+ "\375\375\4\370\370\371\361\361\363\361\361\364\370\370\371\203\375\375\375"
+ "\12\373\373\373\370\370\371\371\371\372\372\372\373\370\370\372\366\366\370"
+ "\365\365\367\366\366\370\370\370\372\372\372\372\202\372\372\373,\371\371"
+ "\372\370\370\371\365\365\367\362\362\364\361\361\364\364\364\366\371\371"
+ "\372\374\374\375\375\375\375\373\373\374\364\364\366\360\360\362\363\363"
+ "\365\373\373\374\375\375\375\374\374\375\373\373\374\374\374\375\375\375"
+ "\375\370\370\371\361\361\364\365\365\367\374\374\374\371\371\373\372\372"
+ "\373\373\373\374\366\366\370\362\362\364\370\370\371\375\375\375\373\373"
+ "\374\373\373\375\371\371\374\362\362\366\357\357\363\367\367\373\357\357"
+ "\363\342\342\347\343\343\352\364\364\370\365\365\372\365\365\371\370\370"
+ "\375\371\371\374\202\372\372\374\32\374\374\375\370\370\371\356\356\363\356"
+ "\356\364\353\353\362\354\354\362\361\361\366\356\356\363\343\343\352\362"
+ "\362\366\375\375\375\372\372\373\370\370\371\365\365\365\344\344\350\312"
+ "\312\320\322\322\325\314\314\314\271\271\272\244\244\245}\221\40\223\255"
+ "'\252\307-\271\3302\277\3403\277\3402\377\273\337!\304\273\337!\24\311\345"
+ "P\334\356\216\243\252\215\200\200\200\223\223\224\240\240\242\251\251\254"
+ "\264\264\267\300\300\304\324\324\327\341\341\343\337\337\343\351\351\354"
+ "\361\361\364\360\360\363\362\362\366\357\357\363\351\351\356\363\363\367"
+ "\361\361\365\202\347\347\354\2\361\361\365\362\362\366\202\357\357\363\4"
+ "\341\341\347\336\336\345\335\335\344\342\342\350\202\363\363\370\24\355\355"
+ "\362\352\352\357\352\352\360\346\346\355\350\350\356\367\367\373\362\362"
+ "\366\353\353\362\371\371\374\375\375\375\372\372\374\364\364\371\372\372"
+ "\374\363\363\365\333\333\343\323\323\333\322\322\332\327\327\336\361\361"
+ "\363\375\375\375\205\374\374\374\202\375\375\375\7\367\367\370\347\347\353"
+ "\342\342\345\345\345\351\360\360\362\371\371\372\371\371\371\202\366\366"
+ "\366\1\371\371\371\202\372\372\372&\371\371\371\367\367\367\365\365\365\363"
+ "\363\364\356\356\360\354\354\357\361\361\363\367\367\370\367\367\367\366"
+ "\366\366\365\365\366\363\363\365\364\364\365\366\366\370\367\367\370\363"
+ "\363\365\361\361\362\356\356\360\355\355\360\357\357\361\360\360\362\361"
+ "\361\362\356\356\360\353\353\356\352\352\354\354\354\356\357\357\360\362"
+ "\362\363\364\364\364\366\366\366\366\366\367\362\362\364\357\357\361\362"
+ "\362\364\371\371\372\375\375\375\373\373\373\370\370\370\202\366\366\366"
+ "\25\363\363\364\355\355\357\354\354\356\367\367\370\372\372\373\371\371\372"
+ "\373\373\374\372\372\373\363\363\365\362\362\363\366\366\370\372\372\372"
+ "\372\372\373\373\373\374\367\367\371\357\357\363\361\361\364\367\367\372"
+ "\352\352\356\340\340\346\345\345\353\202\365\365\372\3\364\363\371\370\370"
+ "\374\371\371\374\202\372\372\374\33\374\374\375\366\366\371\357\357\364\355"
+ "\355\362\351\351\356\351\351\360\357\357\364\354\354\362\345\345\353\366"
+ "\366\371\375\375\375\372\372\373\370\370\371\365\365\365\340\340\345\313"
+ "\313\322\325\325\327\314\314\314\271\271\272\245\245\245|\220!\220\252'\247"
+ "\305-\265\3262\274\3353\275\3374\271\335\"\377\270\335\40\303\270\335\40"
+ "\33\303\342D\333\355\216\255\265\217||}\216\216\221\237\237\242\251\251\253"
+ "\264\264\267\300\300\303\323\323\326\341\341\343\335\335\341\347\347\352"
+ "\361\361\364\360\360\363\362\362\365\361\361\364\350\350\355\361\361\364"
+ "\363\363\367\351\351\356\347\347\354\360\360\364\363\362\367\355\355\362"
+ "\357\357\364\342\342\350\202\336\336\344\26\336\336\345\360\360\365\364\364"
+ "\371\356\356\363\353\353\361\352\352\360\347\347\356\350\350\356\364\364"
+ "\370\365\365\370\351\351\360\367\367\371\375\375\375\373\373\374\364\364"
+ "\371\370\370\372\371\371\373\343\343\352\325\325\335\324\324\334\327\327"
+ "\336\353\353\361\202\374\374\375\205\374\374\374P\371\371\371\303\303\305"
+ "kkl\237\237\241\331\331\334\343\343\346\313\313\314vvxhhj\325\325\327\354"
+ "\354\354\363\363\363\243\243\244\200\200\201yy{\200\200\200\205\205\207\246"
+ "\246\250\344\344\346\317\317\321\205\205\210~}\177xxz||~\276\276\277\353"
+ "\353\355\330\330\331\222\222\224{{}yy{{{~\222\222\224\330\330\331\354\354"
+ "\355\242\241\243\202\202\206vuycceyy{\202\202\205rrt\200\200\201\246\246"
+ "\251\323\323\324\343\343\345\352\352\355\366\366\367\373\373\374\374\374"
+ "\374\266\266\267\212\212\214\200\200\200wwzxx{\241\241\242\346\346\347\364"
+ "\364\365\367\367\371\371\371\373\374\374\374\366\366\370\360\360\362\260"
+ "\260\262\225\226\231\355\355\355\365\365\365\370\370\370\363\363\366\354"
+ "\354\361\364\364\367\365\365\370\345\345\352\337\337\345\352\352\357\367"
+ "\367\372\362\362\367\363\363\371\367\367\373\370\370\374\371\371\374\202"
+ "\372\372\374\32\363\363\370\360\360\365\351\351\357\345\345\353\350\350\356"
+ "\356\356\364\353\353\361\350\350\356\371\371\374\374\374\375\372\372\373"
+ "\370\370\371\365\365\366\334\334\341\320\320\327\330\330\332\314\314\315"
+ "\271\271\272\245\245\245y\216!\214\246&\242\301-\261\3241\271\3343\272\336"
+ "4\265\335#\377\264\334\37\303\264\334\37)\273\3376\331\355\215\271\304\223"
+ "zz{\214\214\216\240\240\241\251\251\253\261\261\266\277\277\302\322\322\325"
+ "\341\341\342\337\337\342\345\345\351\361\361\364\360\360\364\361\361\364"
+ "\362\362\366\350\350\355\355\355\362\364\364\370\353\353\360\347\347\355"
+ "\357\357\363\363\363\367\354\354\361\357\357\364\344\344\352\336\336\344"
+ "\337\337\345\335\335\343\353\353\361\364\364\371\357\357\364\354\354\362"
+ "\353\353\360\351\351\357\351\351\356\362\362\366\367\367\373\350\350\357"
+ "\363\363\367\202\375\375\375\12\365\365\371\363\363\370\373\373\375\353\353"
+ "\360\332\332\341\326\326\336\327\327\336\347\347\354\372\372\374\375\375"
+ "\375\204\374\374\374;\367\367\367\247\247\252//0\1\1\1""889\250\251\253\234"
+ "\234\237AAB\200\200\200\2\2\2NNP\267\267\267\346\346\346sssyyy\13\13\13\11"
+ "\11\12\236\234\235\222\221\221\333\333\334\252\252\252bbb]^]\5\5\5\207\211"
+ "\211\244\243\243\341\341\342\275\275\275kkkCCD\1\1\1\215\215\216\273\273"
+ "\272\277\277\277\347\347\347vvv\223\224\223\36\36\36\5\5\5\305\306\306\262"
+ "\262\262rrqRRR&&&../\242\242\244\340\340\341\361\361\361\371\371\371\372"
+ "\371\372}}|\231\231\230\27\27\30\5\5\5\267\267\266\252\252\252\335\335\336"
+ "\356\356\357\364\364\365\202\372\372\373\7\362\362\365\355\355\360aaa\"#"
+ "\"\277\277\300\350\350\350\360\360\362\202\355\355\361\11\367\367\371\357"
+ "\357\363\341\341\347\340\340\347\356\356\363\367\367\372\360\360\364\362"
+ "\362\370\366\366\373\202\370\370\374\12\371\371\374\370\370\373\363\363\367"
+ "\357\357\364\344\344\353\342\342\351\345\345\353\354\354\363\353\353\361"
+ "\356\356\362\202\374\374\375\20\372\372\373\370\370\371\363\363\364\332\332"
+ "\340\327\327\333\332\332\334\314\314\315\271\271\272\245\245\245v\213\40"
+ "\207\242%\235\274+\254\316/\264\3301\267\3343\262\332$\377\260\331\35\303"
+ "\260\331\35)\263\333'\325\352\210\306\324\225{{|\211\211\213\235\235\240"
+ "\250\250\252\263\263\265\276\276\301\321\321\323\340\340\342\335\335\341"
+ "\343\343\347\361\361\364\361\361\365\362\362\365\363\363\367\351\351\356"
+ "\353\353\357\365\365\370\356\356\362\350\350\355\356\356\362\364\364\370"
+ "\354\354\361\356\356\363\346\346\353\336\336\344\340\340\347\334\334\343"
+ "\346\346\354\363\363\370\360\360\365\355\355\363\354\354\361\352\352\360"
+ "\351\351\357\361\361\365\370\370\375\351\351\357\360\360\365\202\375\375"
+ "\375\12\367\367\372\361\361\365\373\373\374\364\364\367\337\337\347\330\330"
+ "\337\330\330\340\343\343\351\371\371\372\375\375\375\203\374\374\374\15\372"
+ "\372\372\230\230\232223\345\345\346\0\0\0\234\234\235\227\227\230\37\37\40"
+ "\336\336\336\313\313\314\4\4\4OOP\230\230\230\202\331\331\331B\250\250\250"
+ "RRS\4\4\5\247\247\252\277\277\277\325\325\326\336\336\337\261\261\261HHI"
+ "688\307\307\307\305\305\305\334\334\334\346\346\346\274\274\274TTU\6\6\6"
+ "\240\240\240\310\310\310\317\317\320\342\342\343\320\320\320\275\275\275"
+ "667\33\33\34\310\310\311\274\274\274\243\243\244\203\203\203}}{DDD\13\13"
+ "\14\225\224\227\336\336\336\360\357\360\367\366\367\336\335\336\245\245\246"
+ "\"\"#\25\25\25\311\311\311\301\301\301\332\332\332\353\353\354\364\364\366"
+ "\374\374\374\367\367\370\357\356\361\272\272\274[[]\5\5\5}}~\327\327\330"
+ "\345\345\347\350\350\354\357\357\363\370\370\373\351\351\356\340\340\345"
+ "\342\342\350\363\363\366\365\365\370\356\356\362\362\362\370\367\367\373"
+ "\370\370\374\202\367\367\374\6\365\365\372\363\363\370\354\354\361\340\340"
+ "\347\341\341\350\344\344\351\202\354\354\362\1\361\361\365\202\374\374\375"
+ "\20\372\372\373\371\371\371\357\357\361\331\331\340\334\334\337\333\333\334"
+ "\314\314\315\272\272\273\245\245\245r\211\36\203\241$\230\272*\247\316.\257"
+ "\3270\262\3331\257\332&\377\253\330\33\304\253\330\33\27\315\347z\317\342"
+ "\225\205\210\201\206\206\210\232\232\234\250\250\253\262\262\265\275\275"
+ "\300\320\320\322\340\340\342\337\337\342\342\342\345\360\360\363\362\362"
+ "\365\361\361\364\364\364\367\354\354\360\350\350\354\364\364\367\361\361"
+ "\365\350\350\355\355\355\362\364\364\370\202\354\354\361\33\350\350\355\336"
+ "\336\345\341\341\347\335\335\344\341\341\347\360\360\366\360\360\365\356"
+ "\356\364\355\355\363\353\353\361\353\353\360\357\357\364\370\370\373\352"
+ "\352\360\353\353\361\373\373\375\375\375\375\372\372\374\360\360\365\366"
+ "\366\370\371\371\373\346\346\354\332\332\342\331\331\340\341\341\347\365"
+ "\365\371\375\375\375\202\374\374\374T\373\373\373\315\315\315OOQ\352\352"
+ "\352\203\203\203\1\1\2\300\300\303\26\26\27\237\237\236\267\267\270mmn\2"
+ "\2\2\220\220\221\304\304\305\323\323\323\345\345\345\342\342\342sst\11\11"
+ "\11hhk\275\275\275\326\326\326\346\346\347\302\302\303!!!\233\233\233\266"
+ "\266\267\313\313\313\341\341\341\356\356\356\350\350\350YYZ\15\15\16|||\273"
+ "\273\275\321\321\323\344\344\345\347\347\351\313\313\315@@A\40\40!\256\256"
+ "\257\267\267\271\306\306\307\313\313\314\250\250\250kllDCE\24\24\25\260\260"
+ "\260\343\342\343\361\360\361\361\361\361\244\244\245445\33\33\33\250\250"
+ "\252\305\305\306\335\335\336\356\356\360\370\370\372\372\372\373\362\362"
+ "\364\355\355\360~}~zz}\\\\^--,\274\274\275\327\327\332\345\345\347\363\364"
+ "\367\364\364\367\345\345\351\340\340\345\347\347\354\367\367\372\361\361"
+ "\364\354\354\361\362\362\367\367\367\373\370\370\374\366\366\373\366\366"
+ "\372\202\363\363\370\7\345\345\354\335\335\344\336\336\345\343\343\351\355"
+ "\355\363\356\356\364\365\365\370\202\374\374\375\20\372\372\373\371\371\371"
+ "\353\353\356\333\333\341\337\337\344\333\333\334\314\314\315\271\271\272"
+ "\245\245\245o\207\36\200\234\"\222\265(\242\311-\253\324/\256\3270\253\330"
+ "'\377\246\325\31\304\246\325\31\30\304\343g\321\345\223\221\223\206\203\203"
+ "\205\231\231\232\250\250\252\261\261\264\274\274\277\315\315\320\337\337"
+ "\341\340\340\344\341\341\345\357\357\361\363\363\366\360\360\364\364\364"
+ "\367\357\357\363\346\346\353\360\360\364\363\363\367\353\353\360\354\354"
+ "\361\364\364\370\356\356\362\202\352\352\357\6\337\336\345\342\341\350\340"
+ "\340\346\335\335\344\354\354\362\360\360\365\202\356\356\364\22\354\354\363"
+ "\353\353\361\356\356\362\366\366\371\356\356\364\345\345\354\370\370\372"
+ "\375\375\375\374\374\374\361\361\366\357\357\364\372\372\373\357\357\364"
+ "\340\340\346\333\333\342\337\337\345\357\357\364\374\374\375\202\374\374"
+ "\374]\373\373\373\323\323\323\265\265\265\325\325\325\15\15\15TRUHHKnnm\224"
+ "\224\224\241\241\243\31\31\31\36\36\40\216\216\215\267\267\267\326\326\326"
+ "\353\353\353\356\356\356\247\247\247444\31\31\32\276\276\277\327\327\327"
+ "\350\350\350||}++,\305\305\305\277\277\301\326\326\327\355\354\355\367\367"
+ "\367\357\357\357^^`\14\14\14\200\200\200\306\306\307\336\336\337\356\356"
+ "\357\361\361\362\310\310\311DDD\40\40!\262\262\264\312\312\312\335\335\336"
+ "\347\347\347\340\340\340\231\231\231\203\203\204\6\6\7iik\324\323\324\353"
+ "\353\353\362\362\362\237\237\240;;;\32\32\32\245\245\246\314\314\315\343"
+ "\343\345\365\365\366\373\373\374\365\365\367\356\356\360\325\325\327__`Z"
+ "ZZ\206\206\207\14\14\14\213\213\214\311\311\314\341\342\345\366\366\370\356"
+ "\356\362\342\342\350\340\340\346\356\356\362\367\367\372\352\352\360\354"
+ "\354\361\363\363\370\367\367\374\366\366\373\365\365\370\363\363\367\363"
+ "\363\370\361\361\366\337\337\346\332\332\342\334\334\344\342\342\351\356"
+ "\356\364\360\360\364\371\371\373\202\374\374\375\20\372\372\373\370\370\371"
+ "\346\346\353\340\340\345\341\341\346\332\332\334\314\314\315\271\271\271"
+ "\245\245\245l\206\36|\232\"\216\262(\236\307,\247\322.\253\3260\252\327*"
+ "\377\243\324\30\304\243\324\30)\273\337W\320\350\217\234\243\214\201\201"
+ "\202\226\226\231\250\250\251\262\262\264\274\274\276\312\312\316\337\337"
+ "\340\342\342\344\337\337\343\356\356\361\363\363\366\361\361\364\364\364"
+ "\367\362\362\366\346\346\353\354\354\360\365\365\370\356\356\362\354\354"
+ "\361\364\364\370\357\357\364\350\350\355\354\354\361\340\340\347\341\341"
+ "\350\343\343\352\335\335\343\346\346\354\360\360\365\356\356\363\357\357"
+ "\364\356\356\363\354\354\362\355\355\362\364\363\370\363\362\367\343\343"
+ "\352\364\364\370\202\375\375\375\2\367\367\372\354\354\362\202\367\367\372"
+ "\1\345\345\353\202\336\336\345a\353\353\357\372\372\374\374\374\375\374\374"
+ "\374\373\373\373\365\365\365\337\337\337\214\214\215\11\11\12__b^^_xxx\250"
+ "\250\251nmo\3\3\3}}\177\214\214\214\303\303\303\337\337\337\362\362\362\367"
+ "\367\367\351\351\351eff\5\5\5\216\216\217\322\322\322\331\331\331557\201"
+ "\201\201\302\302\303\316\316\317\343\343\344\364\364\365\373\373\374\364"
+ "\364\364]]]\13\13\14\204\204\205\316\316\316\347\347\347\367\367\367\372"
+ "\372\373\323\323\324FFG\37\37\40\266\266\266\323\323\323\353\353\353\366"
+ "\366\366\363\362\363\345\344\345wvw\25\25\26<<=\305\305\305\342\342\342\354"
+ "\354\355\245\245\247<<>\30\30\30\250\250\250\317\317\320\350\350\351\371"
+ "\371\371\367\367\371\356\356\361\356\356\360\223\223\223hgj\241\242\243\210"
+ "\210\211''(NNP\273\273\276\340\341\342\360\360\362\347\347\354\341\341\346"
+ "\344\344\351\364\364\370\362\362\366\350\350\355\355\355\361\364\364\370"
+ "\367\367\373\364\364\370\362\362\366\360\360\364\366\366\372\353\353\357"
+ "\331\331\341\331\331\340\333\333\342\344\344\353\360\360\366\363\363\367"
+ "\372\372\374\202\374\374\375\21\372\372\373\366\366\367\343\343\350\345\345"
+ "\351\342\342\346\331\331\334\313\313\313\271\271\271\245\245\245i\203\35"
+ "x\226!\210\254&\231\302*\244\320.\250\325/\250\325.\240\322\30\377\240\322"
+ "\27\303\240\322\27!\262\332D\317\350\211\252\263\221\200\200\200\223\223"
+ "\225\247\247\250\261\261\264\274\274\277\312\312\314\333\333\336\342\342"
+ "\344\335\335\342\355\355\360\364\364\367\361\361\365\363\363\367\364\364"
+ "\367\350\350\354\350\350\355\365\365\370\361\361\365\354\354\361\363\363"
+ "\367\361\361\365\347\347\355\354\354\361\342\342\350\341\341\347\346\346"
+ "\354\336\336\345\341\341\347\356\356\364\355\355\363\202\357\357\365b\355"
+ "\355\363\356\356\363\361\361\365\365\364\370\343\343\352\356\356\364\374"
+ "\374\375\375\375\375\372\372\374\355\355\363\361\361\366\373\373\374\356"
+ "\356\363\342\342\351\337\337\345\347\346\354\367\367\371\374\374\375\374"
+ "\374\374\373\373\373\370\370\370\342\342\342;;<\35\35\36QQT{{{\236\237\237"
+ "\246\246\247\32\32\32**,\177\177\177\262\262\262\317\317\317\351\351\351"
+ "\367\367\367\373\373\373\363\363\363\210\207\210\22\23\22DDE\306\306\306"
+ "\252\253\253&&&\270\270\270\311\311\311\332\332\332\356\356\356\371\371\372"
+ "\374\374\375\361\361\362ZZ[\13\13\13\216\216\216\317\317\317\350\350\350"
+ "\370\370\370\374\374\374\327\327\327GGH\36\36\37\265\264\265\323\323\324"
+ "\354\354\355\371\371\372\372\372\373\360\360\361~~\177\36\36\37+++\270\271"
+ "\271\330\330\331\342\342\345\254\254\255AAB\25\25\26\244\244\245\317\317"
+ "\320\353\353\354\366\366\367\360\360\362\355\355\360\354\354\356ggg\15\15"
+ "\15YY\\OOQ\16\16\17\17\17\20\243\243\244\331\331\333\345\345\347\342\342"
+ "\346\342\342\350\352\352\357\367\367\371\353\353\360\346\346\354\356\356"
+ "\363\202\365\365\371\14\362\361\366\356\356\364\360\360\364\363\363\370\340"
+ "\340\350\325\325\336\327\327\337\332\332\341\346\346\355\362\362\367\365"
+ "\365\372\373\373\375\202\374\374\375\21\372\372\373\363\363\366\343\343\351"
+ "\347\347\353\340\340\345\327\327\332\313\313\313\271\271\272\244\244\245"
+ "g\201\35u\224!\205\252%\225\276*\240\314-\245\324.\246\325/\237\322\33\377"
+ "\235\321\26\303\235\321\26*\250\3260\315\347\211\271\306\227||\177\216\216"
+ "\221\244\244\245\261\261\263\272\272\274\310\310\312\331\331\334\342\342"
+ "\344\335\335\342\351\351\354\363\363\366\361\361\364\361\361\365\365\365"
+ "\370\354\354\360\345\345\352\361\361\365\363\363\366\355\355\361\361\361"
+ "\365\362\362\366\346\346\354\352\352\357\346\346\353\340\340\346\347\347"
+ "\355\342\342\350\334\334\343\353\353\360\355\355\363\356\356\363\360\360"
+ "\366\357\357\365\356\356\363\357\357\364\364\364\371\347\347\355\346\346"
+ "\354\372\372\373\202\375\375\375\11\365\365\370\353\353\361\371\370\373\365"
+ "\365\371\350\350\356\341\341\350\345\345\352\361\361\365\373\373\374\202"
+ "\374\374\374[\372\372\372\257\260\260\16\16\16\0\0\0\202\202\203\200\200"
+ "\200\270\270\270lmo\3\3\3kkk\234\234\235\275\275\277\333\333\333\360\360"
+ "\360\373\373\373\375\375\375\367\367\367\307\307\307QQR\17\17\20\252\253"
+ "\253YY[bcc\305\305\305\317\317\317\343\343\343\365\365\365\374\374\374\374"
+ "\374\375\361\361\362YYY\13\13\13\220\220\221\317\317\317\350\350\350\370"
+ "\370\370\374\374\374\327\327\327HHI\36\36\37\265\266\267\323\323\324\354"
+ "\354\355\372\372\373\374\374\375\365\365\366\220\217\220\15\15\15""124\267"
+ "\266\267\317\317\321\345\345\347\266\266\266DDE\23\23\24\243\243\245\321"
+ "\321\322\352\352\353\356\356\360\354\354\357\361\361\364\277\277\300@@Af"
+ "ff\260\260\260\252\252\253\217\217\223\6\6\6qqs\313\313\315\327\327\333\336"
+ "\336\343\345\345\352\363\363\367\362\362\366\344\344\351\347\347\355\360"
+ "\360\365\366\366\372\363\363\367\356\356\364\353\353\361\363\363\367\355"
+ "\355\361\330\330\340\324\324\334\326\326\336\333\333\341\354\354\361\363"
+ "\363\370\367\367\372\203\374\374\375\21\372\372\373\357\357\363\345\345\353"
+ "\346\346\352\335\335\342\327\327\332\312\312\313\270\270\271\242\242\244"
+ "e\200\34r\220\40\201\246$\220\272(\234\311,\243\321-\244\323.\236\320\36"
+ "\377\233\317\25\303\233\317\25\25\236\320\33\306\343|\313\335\233\204\206"
+ "\203\212\212\214\240\240\242\260\260\263\272\272\275\307\307\311\326\326"
+ "\331\343\343\344\335\335\341\346\346\352\363\363\365\363\363\366\361\361"
+ "\364\365\365\371\360\360\363\343\343\350\354\354\360\364\364\367\202\357"
+ "\357\363\1\363\363\367\202\350\350\355\12\350\350\356\340\340\346\350\350"
+ "\355\347\347\354\333\333\342\344\344\352\354\354\362\353\352\360\357\357"
+ "\364\357\357\365\202\356\356\363\4\362\362\367\353\353\361\340\340\347\363"
+ "\363\367\202\374\374\374&\372\372\373\353\353\361\357\357\364\371\371\373"
+ "\356\356\363\344\344\352\342\342\350\351\351\357\370\370\371\372\373\374"
+ "\372\372\373\366\366\366efg\1\1\1ddf\200\200\200\262\262\262\256\256\257"
+ "\31\31\32\36\36\35\221\221\222\235\234\237\224\224\225\334\334\334\361\361"
+ "\361\372\372\372\374\374\374\372\372\372\356\356\356{z|\7\7\7cce**,\246\246"
+ "\247\304\304\304\326\326\326\353\353\353\370\370\370\202\374\374\3747\361"
+ "\361\361UUV\14\14\14\220\220\221\316\316\316\347\347\347\367\367\367\373"
+ "\373\373\327\327\327IIJ\36\36\37\265\265\266\322\322\323\353\353\354\370"
+ "\370\371\374\374\374\364\364\364\204\204\205\0\0\0\\\\\\\270\270\272\325"
+ "\325\327\356\356\356\273\273\273HHJ\22\22\22\240\240\241\317\317\317\340"
+ "\340\343\350\350\353\361\361\363\364\364\366\177\177\177\34\34\35\274\274"
+ "\275\314\314\314\271\271\272qqp,,.%%&\261\261\264\312\312\316\332\332\340"
+ "\351\351\356\340\340\342\236\236\240\305\305\310\344\344\352\360\360\363"
+ "\363\363\367\356\356\363\347\347\356\352\352\360\363\363\367\340\340\347"
+ "\202\322\322\332\5\324\324\334\335\335\345\360\360\366\363\363\367\370\370"
+ "\372\203\373\373\374\21\371\371\373\355\355\362\350\350\355\345\345\350\335"
+ "\335\341\326\326\332\310\310\312\265\265\270\237\237\242d\200\34p\217\37"
+ "\200\243$\216\267(\232\306+\240\317-\243\322.\236\321#\377\231\317\25\304"
+ "\231\317\25)\274\337g\320\346\234\224\227\211\207\207\211\233\233\235\257"
+ "\257\260\272\272\274\304\304\306\324\324\327\342\342\343\336\336\342\344"
+ "\344\347\361\361\363\364\364\367\360\360\364\363\363\366\362\362\365\343"
+ "\343\350\346\346\353\362\362\366\360\360\364\357\357\363\363\363\367\351"
+ "\351\356\345\344\352\353\353\360\341\341\347\346\346\354\353\353\360\336"
+ "\336\344\335\335\344\352\352\360\350\350\356\354\354\362\357\357\364\356"
+ "\356\363\355\355\362\356\356\364\357\357\365\336\336\345\351\351\357\203"
+ "\373\373\373%\361\361\365\347\347\355\366\366\371\365\365\371\350\350\356"
+ "\343\343\351\345\345\353\362\362\365\372\372\372\367\367\371\313\313\314"
+ "\34\34\34\32\32\31zz{\237\237\237\276\276\276eeg\6\6\6\247\247\250ffg233"
+ "\215\214\215\325\325\327\355\355\356\370\370\370\373\373\373\372\372\372"
+ "\363\363\363\256\256\256>>>\0\0\0OOP\272\273\273\307\307\307\337\337\337"
+ "\361\361\361\372\372\372\202\373\373\373?\361\361\361RRT\14\14\15\224\224"
+ "\224\315\315\315\346\346\346\366\366\366\372\372\372\341\341\341JJK\34\34"
+ "\35\265\265\266\320\320\320\350\350\350\365\365\365\364\364\364\307\307\311"
+ "\23\23\23\17\17\17\250\250\250\302\302\304\337\337\340\357\357\360\310\310"
+ "\311IIJ\20\20\20\244\244\245\307\307\310\331\331\334\353\353\355\366\366"
+ "\370\336\336\336TTUBBB\301\301\301\277\277\300\271\271\274ZYY\200\200\200"
+ "\10\10\10\220\220\222\276\276\302\325\325\331\343\343\347nnp$$%LLM\341\341"
+ "\345\354\354\360\356\356\361\350\350\355\342\342\351\355\355\362\355\355"
+ "\361\325\325\335\316\316\330\320\320\330\322\322\332\343\343\351\363\363"
+ "\367\362\362\366\367\367\372\371\371\373\202\372\372\373\21\366\366\370\354"
+ "\354\361\346\346\353\341\341\345\334\334\340\325\325\331\305\305\310\263"
+ "\263\266\235\235\237b\177\34n\214\37|\240#\212\264(\226\304,\235\315-\240"
+ "\321.\236\321'\377\227\316\25\304\227\316\25\12\261\332Q\317\347\226\243"
+ "\253\220\202\202\204\226\226\230\254\254\255\270\270\273\303\303\305\322"
+ "\322\324\340\340\341\202\337\337\343\2\356\356\361\364\364\367\202\361\361"
+ "\364\12\364\364\367\346\346\353\341\341\346\354\354\360\361\361\364\356\356"
+ "\362\362\362\366\353\353\360\342\342\347\352\352\357\202\343\343\351\16\355"
+ "\355\363\346\346\353\333\333\342\346\346\354\350\350\355\350\350\356\355"
+ "\355\363\356\356\363\355\355\361\354\354\361\357\357\364\341\341\350\341"
+ "\341\347\367\367\371\202\372\372\372\31\367\367\370\350\350\355\357\357\362"
+ "\370\370\371\357\356\363\345\345\353\344\344\352\354\354\357\367\367\371"
+ "\364\364\366wwy\3\3\4llnqrr\271\271\271\272\272\272\23\23\23\0\0\0VVW,,."
+ "\276\276\276\237\235\237\316\316\321\350\350\351\367\367\367\202\372\372"
+ "\372\22\366\366\366\336\337\336bbc\2\2\2\225\225\226\265\265\265\317\317"
+ "\317\346\346\346\365\365\365\372\372\372\371\371\371\363\363\363\325\325"
+ "\326BBD\4\4\5\230\230\232\306\306\306\340\340\340\202\361\361\361*\310\310"
+ "\311334\0\0\0\204\204\205\302\302\304\317\317\320\313\313\316\224\224\227"
+ "\34\34\34\13\13\13\203\204\204\275\275\276\317\317\320\344\344\345\352\352"
+ "\354\300\301\302BBC\2\1\1\236\236\241\274\274\277\327\327\332\356\356\357"
+ "\360\360\360\252\252\253\15\15\15oop\274\274\275\302\302\305\311\311\313"
+ "\240\240\241\201\200\202\2\2\2""234\263\263\266\321\321\323\325\325\327R"
+ "RR667JJL\333\333\336\345\345\352\346\346\353\202\341\341\347\37\361\361\364"
+ "\340\340\346\317\317\330\316\316\330\317\317\327\326\326\335\353\353\360"
+ "\362\362\366\360\360\364\365\365\371\367\367\372\371\371\373\371\371\372"
+ "\360\360\364\353\353\360\342\342\347\337\337\344\334\334\340\323\323\326"
+ "\301\301\305\261\261\264\232\232\236a~\34k\212\36y\235\"\207\261'\223\301"
+ "*\233\314,\237\321-\240\322,\226\316\25\377\226\316\24\303\226\316\24\34"
+ "\246\3259\314\347\214\263\300\226\200\200\200\221\221\222\245\245\247\267"
+ "\267\270\302\302\304\317\317\321\336\336\337\343\343\346\334\334\341\350"
+ "\350\353\364\364\366\357\357\362\356\356\361\362\362\365\352\352\356\334"
+ "\334\342\344\344\351\357\357\363\355\355\361\356\356\362\355\355\361\340"
+ "\340\345\346\346\353\345\345\353\340\340\345\202\354\354\361\14\336\336\343"
+ "\340\340\345\347\347\354\343\343\351\351\351\356\354\354\361\354\354\360"
+ "\352\351\357\353\353\361\347\347\354\333\333\342\355\355\361\203\370\370"
+ "\370\30\356\356\362\343\343\351\360\360\363\364\364\366\350\350\356\344\344"
+ "\351\346\346\353\361\361\364\362\362\362[[\\222kkk\244\244\244\305\305\305"
+ "\221\221\222\37\37!99:\200\200\201\343\343\343\301\301\301\277\277\277\322"
+ "\322\325\343\343\346\363\363\364\202\370\370\370B\366\366\366\355\355\355"
+ "\210\210\210MMO\263\263\263\276\276\276\327\327\327\354\354\354\366\366\366"
+ "\370\370\370\366\366\366\234\234\234zzzFFG443^^`\214\214\214\322\322\323"
+ "\350\350\351\246\247\250||}AAB:::445}}~\214\214\216yyzNON{{{www\265\265\265"
+ "\306\306\307\332\332\333\351\351\351\222\222\223\201\201\203RQR454]]_\206"
+ "\206\210\317\317\320\316\316\315\204\204\205yyz///acd\230\230\233\275\275"
+ "\301\257\257\261\210\210\211wxy>>?../wwy\261\261\262\324\324\331}}\200EE"
+ "Fnnp\332\332\336\341\341\343\336\336\343\333\333\342\350\350\355\352\352"
+ "\357\322\322\332\202\313\313\323\3\315\315\325\333\333\342\361\361\365\202"
+ "\355\355\362\25\362\362\366\364\364\371\367\367\371\362\362\366\355\355\362"
+ "\351\351\356\336\336\342\335\335\343\333\333\337\316\316\322\276\276\302"
+ "\255\255\261\230\230\232`}\33j\210\35x\231!\204\254%\221\275)\233\311+\237"
+ "\317,\240\320-\377\241\322-\304\241\322-\22\246\3259\313\346\213\311\330"
+ "\243\204\204\201\213\213\214\240\240\241\264\264\265\277\277\302\314\314"
+ "\316\331\331\333\341\341\343\332\332\337\342\342\346\361\361\364\357\357"
+ "\362\353\353\356\355\355\360\353\353\357\202\332\332\337\27\350\350\353\353"
+ "\353\357\352\352\356\353\353\357\336\336\344\336\336\343\345\345\351\335"
+ "\335\343\350\350\354\356\356\362\341\341\347\327\326\336\343\343\351\341"
+ "\341\347\341\341\346\350\350\354\351\351\355\347\347\353\344\344\351\347"
+ "\347\354\331\331\340\337\337\345\362\362\362\202\363\363\363\31\361\361\362"
+ "\342\342\350\341\341\346\360\360\362\353\353\357\343\343\350\341\341\346"
+ "\347\347\352\353\353\354\232\232\232\250\250\250\233\233\233\300\300\300"
+ "\320\320\320\256\255\255~~~\266\266\266\334\334\334\272\272\272\274\274\274"
+ "\317\317\317\336\336\337\346\346\351\353\353\356\360\360\362\202\363\363"
+ "\363\7\355\355\355\271\271\271\214\215\215\267\267\267\313\313\313\336\336"
+ "\336\354\354\354\202\363\363\363T\360\360\360\222\222\222\227\227\227\244"
+ "\244\244\235\235\235\222\222\222\242\242\242\306\306\307\335\335\336\222"
+ "\223\222\244\245\244\270\270\271\273\273\273\271\271\270\266\266\265\267"
+ "\267\267\305\304\304\330\331\331\300\300\300\274\274\274\304\304\305\324"
+ "\324\325\343\343\345\351\351\351\215\215\215\313\313\314\320\321\320\321"
+ "\321\321\311\311\311\256\256\256\315\315\315\267\267\267\260\260\260\324"
+ "\324\324\325\325\325\322\322\322\232\232\231\301\301\303\243\243\245\272"
+ "\272\273\322\322\322\325\325\325\327\327\327\265\265\265\244\244\245\277"
+ "\277\304\303\303\311\301\301\305\325\325\330\326\326\333\330\330\335\321"
+ "\321\327\331\331\337\353\353\357\330\330\337\310\310\321\307\307\316\305"
+ "\305\317\313\313\323\341\341\347\355\355\357\344\344\351\351\351\355\354"
+ "\354\361\356\356\362\357\357\363\354\354\361\352\352\357\341\341\347\327"
+ "\327\334\334\334\341\330\330\332\311\311\316\273\273\275\254\254\257\226"
+ "\226\230\\z\31f\204\33r\224\36\177\246\"\212\270%\224\304(\231\312)\233\314"
+ "*\377\234\316*\305\234\316*\24\274\335s\323\347\247\223\226\212\204\204\206"
+ "\230\230\232\255\255\256\273\273\275\305\305\310\324\324\327\336\336\340"
+ "\331\331\335\333\333\337\353\353\355\352\352\355\350\350\352\347\347\351"
+ "\351\351\353\333\333\337\322\322\327\336\336\342\202\347\347\351,\347\347"
+ "\353\335\335\342\326\326\332\337\337\344\332\332\340\336\336\343\352\352"
+ "\356\344\344\350\322\322\331\330\330\336\336\336\343\331\331\335\337\337"
+ "\345\343\343\347\342\342\346\336\336\344\340\340\347\333\333\340\322\322"
+ "\331\350\350\352\355\355\355\354\354\355\355\355\355\345\345\347\331\331"
+ "\336\344\344\347\352\352\354\342\342\347\335\335\342\336\336\343\343\343"
+ "\346\335\335\335\313\313\315\304\304\306\314\314\314\332\332\332\334\334"
+ "\334\323\323\323\303\303\303\274\274\274\301\301\301\316\316\316\333\333"
+ "\333\346\346\346\203\350\350\352\11\353\354\355\355\355\355\352\352\352\342"
+ "\342\342\327\327\327\317\317\317\326\326\326\341\341\341\352\352\352\202"
+ "\355\355\355S\352\352\352\343\343\343\325\325\325\306\306\306\275\275\275"
+ "\273\273\273\302\302\302\317\317\317\333\333\334\335\335\336\324\324\325"
+ "\305\305\306\275\275\275\272\272\272\274\274\274\276\276\276\300\300\300"
+ "\301\301\301\303\303\303\311\311\312\324\324\325\340\340\340\347\347\350"
+ "\346\346\346\331\331\332\305\305\307\271\271\274\267\267\270\272\272\272"
+ "\303\303\303\317\317\320\332\332\333\331\331\331\313\313\314\267\267\272"
+ "\252\252\255\264\265\267\315\315\316\321\321\325\303\303\306\265\265\270"
+ "\252\252\256\256\256\262\273\273\275\267\267\274\267\267\275\307\307\316"
+ "\326\326\331\332\332\335\326\326\332\317\317\326\313\313\322\335\335\341"
+ "\340\340\345\307\307\317\301\301\310\277\277\307\301\301\310\315\315\324"
+ "\345\345\350\341\341\346\333\333\342\343\343\350\346\346\352\347\347\353"
+ "\346\346\353\347\347\352\345\345\351\326\326\333\322\322\330\330\330\335"
+ "\322\322\325\303\303\307\267\267\272\250\250\253\224\224\226Yv\26a\200\31"
+ "m\216\33y\237\36\203\257\"\215\273$\223\303&\202\226\307&\377\227\310&\304"
+ "\227\310&*\255\323X\314\340\236\243\252\217~~\200\217\217\221\245\245\246"
+ "\265\265\266\301\301\302\314\314\316\331\331\333\327\327\332\323\323\327"
+ "\341\341\344\346\346\347\341\341\344\337\337\342\341\341\343\332\332\335"
+ "\313\313\321\321\321\325\335\335\341\340\340\342\340\340\344\332\332\335"
+ "\315\315\322\325\325\332\326\326\332\323\323\330\341\341\344\342\342\345"
+ "\322\322\330\312\311\320\324\324\331\322\322\326\323\323\330\331\331\335"
+ "\331\331\336\327\327\334\325\325\333\327\327\334\311\311\321\325\325\331"
+ "\203\344\344\344!\342\342\343\330\330\333\322\322\327\340\340\341\340\340"
+ "\343\331\331\335\326\326\332\330\330\334\331\331\334\325\325\326\317\317"
+ "\322\325\325\326\333\333\333\334\334\334\331\331\331\322\322\322\317\317"
+ "\317\322\322\322\331\331\331\337\337\337\342\342\342\344\344\344\343\343"
+ "\344\341\340\342\341\341\343\343\343\344\343\343\343\340\340\340\333\333"
+ "\333\330\330\330\333\333\333\340\340\340\343\343\343\202\344\344\344\4\342"
+ "\342\342\337\337\337\330\330\330\322\322\322\202\315\315\315\7\320\320\320"
+ "\325\325\325\333\333\333\334\334\334\330\330\330\322\322\322\316\316\316"
+ "\204\315\315\315\12\316\316\316\322\322\322\326\326\326\333\333\334\335\335"
+ "\336\332\332\335\324\324\330\320\320\323\315\315\320\315\315\316\202\315"
+ "\315\3157\317\317\320\325\325\326\331\331\331\330\330\331\311\311\314\270"
+ "\270\274\274\274\277\313\313\315\317\317\320\306\306\312\300\300\304\273"
+ "\273\300\276\276\302\310\310\312\301\301\304\263\263\271\274\274\302\314"
+ "\314\322\327\327\332\324\324\331\312\312\320\301\301\310\312\312\321\333"
+ "\333\337\310\310\317\272\272\302\270\270\277\270\270\300\274\274\303\321"
+ "\322\326\335\335\340\322\322\327\324\324\332\332\332\337\334\334\340\335"
+ "\335\341\333\333\340\337\337\343\325\325\332\312\312\320\316\316\323\322"
+ "\322\327\311\311\315\274\274\300\264\264\266\244\244\250\223\223\225Uq\24"
+ "]|\27g\206\31s\227\34\177\246\37\206\262!\214\272\"\217\276#\202\220\300"
+ "$\377\221\301$\303\221\301$3\235\307=\302\330\216\261\275\223zz{\204\204"
+ "\206\230\230\232\252\252\254\270\270\272\303\303\305\317\317\320\322\322"
+ "\324\312\312\315\324\324\327\333\333\336\330\330\333\324\324\327\323\323"
+ "\327\324\324\327\307\307\313\303\303\310\317\317\322\325\325\330\326\326"
+ "\331\324\324\327\305\305\312\306\306\313\317\317\323\310\310\316\323\323"
+ "\327\332\332\333\323\323\325\302\301\307\303\303\311\310\310\315\305\305"
+ "\311\313\313\320\317\317\322\316\316\322\311\311\317\314\314\321\305\305"
+ "\313\301\301\307\325\325\327\331\331\331\330\330\331\331\331\331\327\327"
+ "\327\310\310\316\311\311\316\327\327\330\324\324\327\202\315\315\322\4\320"
+ "\320\323\325\325\326\321\321\323\320\320\323\202\327\327\327\6\325\325\325"
+ "\323\323\323\322\322\322\325\325\325\327\327\327\330\330\330\204\331\331"
+ "\331\10\327\327\331\330\330\331\331\331\331\330\330\330\327\327\327\326\326"
+ "\326\327\327\327\330\330\330\204\331\331\331\3\327\327\327\326\326\326\324"
+ "\324\324\202\322\322\322\2\323\323\323\325\325\325\202\327\327\327\3\326"
+ "\326\326\324\324\324\323\323\323\205\322\322\322\11\322\322\323\322\322\322"
+ "\317\317\322\315\314\320\314\314\317\320\320\322\324\324\325\325\325\325"
+ "\323\323\323\202\322\322\3227\324\324\324\325\325\325\323\323\324\307\307"
+ "\312\274\274\301\301\301\304\316\316\320\314\314\317\302\302\306\274\274"
+ "\300\273\273\300\302\302\305\314\314\320\305\305\310\264\264\272\263\263"
+ "\272\301\301\306\315\315\322\316\316\322\304\304\311\271\271\276\270\270"
+ "\276\315\315\321\307\307\313\262\262\272\257\257\267\256\256\266\260\260"
+ "\270\273\273\302\321\321\324\313\313\317\303\303\310\311\311\316\315\315"
+ "\322\317\317\323\316\316\323\322\322\326\323\323\327\303\303\310\300\300"
+ "\305\306\306\314\307\307\314\276\276\302\265\265\270\256\256\262\240\240"
+ "\242\220\220\223Rn\23Xv\25b\201\27m\220\32w\236\34\200\252\36\205\262\37"
+ "\211\267\40\202\212\272!\377\213\272!\303\213\272!\17\214\273$\256\312o\302"
+ "\324\232\202\204\177}}\177\214\214\216\237\237\240\255\255\257\267\267\272"
+ "\303\303\304\307\307\310\300\300\304\304\304\307\320\320\321\314\314\317"
+ "\202\307\307\312\14\310\310\312\301\301\304\266\266\272\275\275\301\307\307"
+ "\313\311\311\314\311\311\313\276\276\302\267\267\273\300\300\304\275\275"
+ "\301\301\301\305\202\313\313\314\14\275\275\302\263\263\271\274\274\301\271"
+ "\271\275\271\271\277\300\300\304\302\302\305\276\276\303\275\275\302\277"
+ "\277\303\263\263\270\277\277\303\202\313\313\313\16\312\312\313\313\313\313"
+ "\306\306\307\267\267\275\300\300\303\312\312\313\305\305\310\300\300\304"
+ "\301\301\305\307\307\311\312\312\312\306\306\310\307\307\311\312\312\313"
+ "\207\312\312\312\233\313\313\313\1\312\312\313\202\311\311\312\7\307\307"
+ "\311\304\304\306\301\301\304\300\300\303\302\302\304\306\306\310\311\311"
+ "\311\204\313\313\313\1\312\313\313\202\313\313\313\12\311\311\311\273\273"
+ "\300\261\261\265\271\271\275\307\307\311\303\303\306\270\270\275\262\262"
+ "\266\261\261\266\266\266\273\202\303\303\306\13\257\257\264\250\250\260\263"
+ "\263\270\300\300\303\303\303\307\274\274\301\257\257\264\250\250\257\271"
+ "\271\275\302\302\305\255\255\263\203\243\243\252\6\250\250\257\271\271\276"
+ "\305\305\310\266\266\273\266\266\274\275\275\302\202\277\277\304\24\277\277"
+ "\303\307\307\313\277\277\303\261\261\267\267\267\274\274\274\300\272\272"
+ "\276\261\261\266\254\254\261\250\250\253\232\232\235\214\214\215Oi\21Uq\23"
+ "]|\25g\210\27q\226\31{\242\33\200\252\35\202\257\35\202\205\262\36\377\205"
+ "\263\36\304\205\263\36:\234\277R\271\314\220\217\224\201sst\200\200\200\221"
+ "\221\222\236\236\237\247\247\252\263\263\265\271\271\273\264\264\267\262"
+ "\262\265\275\275\300\274\274\276\270\270\273\267\267\272\270\270\272\267"
+ "\267\271\253\253\257\251\251\255\265\265\270\271\271\274\272\272\275\263"
+ "\263\267\252\252\256\256\256\262\262\262\266\257\257\263\272\272\273\274"
+ "\274\274\267\267\271\251\251\255\250\250\255\255\255\261\250\250\254\255"
+ "\255\262\262\262\266\260\260\265\255\255\261\257\257\264\252\252\256\247"
+ "\247\253\267\267\271\273\273\273\272\272\273\273\273\273\272\272\272\261"
+ "\261\264\251\251\255\264\264\266\272\272\272\265\265\270\262\262\266\265"
+ "\265\270\272\272\272\271\271\272\266\266\270\270\270\272\217\272\272\272"
+ "\221\273\273\273\202\272\272\273\2\270\270\272\267\267\272\204\266\266\270"
+ "\2\270\270\272\272\272\272\210\273\273\273\30\266\266\270\252\252\256\243"
+ "\243\251\254\254\260\270\270\271\264\264\266\251\251\255\243\243\250\242"
+ "\242\250\250\250\254\264\264\266\266\266\270\244\244\251\233\233\241\241"
+ "\241\246\255\255\261\264\264\267\260\260\264\244\244\252\231\231\240\243"
+ "\243\251\265\265\270\250\250\254\230\230\237\202\225\225\235\20\227\227\236"
+ "\243\243\251\264\264\267\255\255\261\244\244\251\251\251\255\254\254\261"
+ "\256\256\262\255\255\261\262\262\266\267\267\272\250\250\254\244\244\250"
+ "\253\253\257\255\255\262\252\252\256\202\244\244\247\3\240\240\241\222\222"
+ "\224\206\206\206",
+};
+
diff --git a/src/image_data/bnc_cable.h b/src/image_data/bnc_cable.h index 756946a..d627072 100644 --- a/src/image_data/bnc_cable.h +++ b/src/image_data/bnc_cable.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t bnc_cable = {
- 64, 64, 4,
+ 64, 64, 4, 0,
"\224\372\372\372\0\6\371\371\371\0\366\366\366\0\265\265\265\0\356\356\356"
"\0\273\273\273\0\261\260\261\0\202\332\332\332\0\6\311\311\311\0\225\224"
"\225\0\256\253\256\0\315\311\315\0\304\302\304\0\216\215\216\0\214\0\0\0"
diff --git a/src/image_data/clocks_banner.h b/src/image_data/clocks_banner.h index 46814e5..30debc6 100644 --- a/src/image_data/clocks_banner.h +++ b/src/image_data/clocks_banner.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t clocks_banner_image = {
- 360, 60, 3,
+ 360, 60, 3, 180,
"\204]y\30\202m\216\33\377\201\221\33\311\201\221\33\6\205\234G\226\244b\200"
"\200\205z{|\206\207\212\227\227\232\202\235\234\237\1\243\242\244\202\235"
"\234\237\2\217\217\222\206\207\212\203\217\217\222\3\206\207\212\200\200"
diff --git a/src/image_data/color_correction_banner.h b/src/image_data/color_correction_banner.h index 28f24b9..b8a7369 100644 --- a/src/image_data/color_correction_banner.h +++ b/src/image_data/color_correction_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t color_correction_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\203Qi\22\202i\204\27\377\201\221\34\312\201\221\34\2\214\233Q\232\240f\202" "\177~\200\11\206\207\211\227\227\231\232\232\237\237\237\240\240\240\244" "\237\237\240\232\232\237\220\216\223\206\207\211\203\220\216\223\203\206" diff --git a/src/image_data/configuration_banner.h b/src/image_data/configuration_banner.h index b5d5403..912d8d7 100644 --- a/src/image_data/configuration_banner.h +++ b/src/image_data/configuration_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t configuration_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\307" "\201\221\33\202\200\220\33\373\201\221\33\35\202\222\40\220\232S\224\235" "e\202\204{zz{\213\213\214\225\225\226\233\233\234\237\237\241\241\241\242" diff --git a/src/image_data/crt.h b/src/image_data/crt.h index 83bce95..145e3c3 100644 --- a/src/image_data/crt.h +++ b/src/image_data/crt.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t crt_image = { - 100, 100, 4, + 100, 100, 4, 0, "\377\377\0\377\0\377\377\0\377\0\225\377\0\377\0\25\336\336\337\377\333\333" "\335\377\330\330\331\377\322\322\324\377\317\317\320\377\312\312\320\377\303" "\303\310\377\277\277\305\377\275\275\304\377\277\277\305\377\303\303\310\377" diff --git a/src/image_data/crt_banner.h b/src/image_data/crt_banner.h index 551a340..ce8c4a0 100644 --- a/src/image_data/crt_banner.h +++ b/src/image_data/crt_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t crt_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\222" "\201\221\33\262\200\221\32\377\201\221\33\36\201\221\33\202\222\40\220\232" "S\224\235e\202\204{zz{\213\213\214\225\225\226\233\233\234\237\237\241\241" diff --git a/src/image_data/cursor_banner.h b/src/image_data/cursor_banner.h index 0e00436..de2e926 100644 --- a/src/image_data/cursor_banner.h +++ b/src/image_data/cursor_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t cursor_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\265" "\201\221\33\1\331\336\272\231\201\221\33\202\201\221\34\202\201\221\33\2" "\202\222\36\203\223\37\357\201\221\33\35\202\222\40\220\232S\224\235e\202" diff --git a/src/image_data/dfp.h b/src/image_data/dfp.h index 7813b00..d5d7b6c 100644 --- a/src/image_data/dfp.h +++ b/src/image_data/dfp.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t dfp_image = { - 100, 100, 4, + 100, 100, 4, 0, "\377\377\0\377\0\377\377\0\377\0\213\377\0\377\0\7\337\336\341\377\335\335" "\336\377\332\332\333\377\322\322\325\377\317\317\321\377\313\312\315\377\310" "\310\315\377\203\300\300\303\377\5\306\306\311\377\315\314\321\377\324\324" diff --git a/src/image_data/dfp_banner.h b/src/image_data/dfp_banner.h index 4c63e4f..462a1be 100644 --- a/src/image_data/dfp_banner.h +++ b/src/image_data/dfp_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t dfp_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\203Qe\30\203j\206\31\377\202\222\34\311\202\222\34\2\216\235O\226\237h\202" "}|\177\11\206\206\210\227\227\231\233\233\237\236\236\244\241\241\243\236" "\236\244\233\233\237\220\217\222\206\206\210\203\220\217\222\203\206\206" diff --git a/src/image_data/display_device_banner.h b/src/image_data/display_device_banner.h index 15007ab..d2f988b 100644 --- a/src/image_data/display_device_banner.h +++ b/src/image_data/display_device_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t display_device_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\203Un\21\202c\177\21\377\200\221\32\312\200\221\32\2\223\237S\231\241k\202" "~~\202\2\206\206\212\227\226\230\202\233\233\240\1\243\243\244\202\233\233" "\240\2\217\217\222\206\206\212\203\217\217\222\203\206\206\212\206\217\217" diff --git a/src/image_data/frame_lock_banner.h b/src/image_data/frame_lock_banner.h index 90c2cee..009efc2 100644 --- a/src/image_data/frame_lock_banner.h +++ b/src/image_data/frame_lock_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t frame_lock_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\226" "\201\221\33\320\204\223\26\222\204\222\"\1\204\223\26\203\204\222\"\1\204" "\223\26\203\204\222\"\1\204\223\26\236\204\222\"\245\201\221\33\35\202\222" diff --git a/src/image_data/glx_banner.h b/src/image_data/glx_banner.h index 305fe98..faa602e 100644 --- a/src/image_data/glx_banner.h +++ b/src/image_data/glx_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t glx_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\377" "\201\221\33\305\201\221\33\35\202\222\40\220\232S\223\234e\203\205|zz{\213" "\213\214\225\225\226\233\233\234\237\237\241\241\241\242\237\237\241\234" diff --git a/src/image_data/gvo_banner_comp_sync_green.h b/src/image_data/gvo_banner_comp_sync_green.h index 7f63e4c..d1e3c98 100644 --- a/src/image_data/gvo_banner_comp_sync_green.h +++ b/src/image_data/gvo_banner_comp_sync_green.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_comp_sync_green_image = { - 34, 60, 3, + 34, 60, 3, 0, "\242\201\221\33\242\235\257!\242\261\306&\242\301\326,\242\314\340.\242\321" "\345/\242\324\3462\242\325\3472\304\334\3567\242\335\3578\203\374\374\374" "\203\373\373\374\205\372\372\373\203\371\371\372\203\370\370\372\202\370" diff --git a/src/image_data/gvo_banner_comp_sync_grey.h b/src/image_data/gvo_banner_comp_sync_grey.h index 801a796..dec42be 100644 --- a/src/image_data/gvo_banner_comp_sync_grey.h +++ b/src/image_data/gvo_banner_comp_sync_grey.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_comp_sync_grey_image = { - 34, 60, 3, + 34, 60, 3, 0, "\242\201\221\33\242\235\257!\242\261\306&\242\301\326,\242\314\340.\242\321" "\345/\242\324\3462\242\325\3472\304\334\3567\242\335\3578\203\374\374\374" "\203\373\373\374\205\372\372\373\203\371\371\372\203\370\370\372\202\370" diff --git a/src/image_data/gvo_banner_comp_sync_red.h b/src/image_data/gvo_banner_comp_sync_red.h index c92087b..b7cdc19 100644 --- a/src/image_data/gvo_banner_comp_sync_red.h +++ b/src/image_data/gvo_banner_comp_sync_red.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_comp_sync_red_image = { - 34, 60, 3, + 34, 60, 3, 0, "\242\201\221\33\242\235\257!\242\261\306&\242\301\326,\242\314\340.\242\321" "\345/\242\324\3462\242\325\3472\304\334\3567\242\335\3578\203\374\374\374" "\203\373\373\374\205\372\372\373\203\371\371\372\203\370\370\372\202\370" diff --git a/src/image_data/gvo_banner_comp_sync_yellow.h b/src/image_data/gvo_banner_comp_sync_yellow.h index 87126b7..9059195 100644 --- a/src/image_data/gvo_banner_comp_sync_yellow.h +++ b/src/image_data/gvo_banner_comp_sync_yellow.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_comp_sync_yellow_image = { - 34, 60, 3, + 34, 60, 3, 0, "\242\201\221\33\242\235\257!\242\261\306&\242\301\326,\242\314\340.\242\321" "\345/\242\324\3462\242\325\3472\304\334\3567\242\335\3578\203\374\374\374" "\203\373\373\374\205\372\372\373\203\371\371\372\203\370\370\372\202\370" diff --git a/src/image_data/gvo_banner_left.h b/src/image_data/gvo_banner_left.h index a87539b..c0f6c2a 100644 --- a/src/image_data/gvo_banner_left.h +++ b/src/image_data/gvo_banner_left.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_left_image = { - 70, 60, 3, + 70, 60, 3, 0, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\275" "\201\221\33\10`k\25iu\26s\200\31\177\214\33\211\231\35\222\242\37\227\251" "\40\232\255!\202\234\256!\274\235\257!\11ly\27u\203\32\201\220\34\217\240" diff --git a/src/image_data/gvo_banner_right.h b/src/image_data/gvo_banner_right.h index ff6bd93..ce14d88 100644 --- a/src/image_data/gvo_banner_right.h +++ b/src/image_data/gvo_banner_right.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_right_image = { - 174, 60, 3, + 174, 60, 3, 0, "\223\201\221\33\35\202\222\40\220\232S\224\235e\202\204{zz{\213\213\214\225" "\225\226\233\233\234\237\237\241\241\241\242\237\237\241\234\234\236\220" "\220\222\212\212\216\216\216\220\222\222\223\221\221\223\212\212\214\203" diff --git a/src/image_data/gvo_banner_sdi_sync_green.h b/src/image_data/gvo_banner_sdi_sync_green.h index f8a2e0a..9385919 100644 --- a/src/image_data/gvo_banner_sdi_sync_green.h +++ b/src/image_data/gvo_banner_sdi_sync_green.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_sdi_sync_green_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\202\374\374\375" "\203\375\375\375\213\376\376\376\202\375\375\376\204\375\375\375\202\374" diff --git a/src/image_data/gvo_banner_sdi_sync_grey.h b/src/image_data/gvo_banner_sdi_sync_grey.h index 556f2f6..bc752c4 100644 --- a/src/image_data/gvo_banner_sdi_sync_grey.h +++ b/src/image_data/gvo_banner_sdi_sync_grey.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_sdi_sync_grey_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\202\374\374\375" "\203\375\375\375\213\376\376\376\202\375\375\376\204\375\375\375\202\374" diff --git a/src/image_data/gvo_banner_sdi_sync_red.h b/src/image_data/gvo_banner_sdi_sync_red.h index 0894cd2..29479ce 100644 --- a/src/image_data/gvo_banner_sdi_sync_red.h +++ b/src/image_data/gvo_banner_sdi_sync_red.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_sdi_sync_red_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\202\374\374\375" "\203\375\375\375\213\376\376\376\202\375\375\376\204\375\375\375\202\374" diff --git a/src/image_data/gvo_banner_sdi_sync_yellow.h b/src/image_data/gvo_banner_sdi_sync_yellow.h index b31475d..b1e7a56 100644 --- a/src/image_data/gvo_banner_sdi_sync_yellow.h +++ b/src/image_data/gvo_banner_sdi_sync_yellow.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_sdi_sync_yellow_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\202\374\374\375" "\203\375\375\375\213\376\376\376\202\375\375\376\204\375\375\375\202\374" diff --git a/src/image_data/gvo_banner_vid1_green.h b/src/image_data/gvo_banner_vid1_green.h index ec2bfea..dc1ec2e 100644 --- a/src/image_data/gvo_banner_vid1_green.h +++ b/src/image_data/gvo_banner_vid1_green.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid1_green_image = { - 30, 60, 3, + 30, 60, 3, 0, "\236\201\221\33\236\235\257!\236\261\306&\236\301\326,\236\314\340.\236\321" "\345/\236\324\3462\236\325\3472\274\334\3567\236\335\3578\2\355\357\341\357" "\357\363\204\360\360\363\1\360\360\364\204\361\361\364\1\362\362\364\204" diff --git a/src/image_data/gvo_banner_vid1_grey.h b/src/image_data/gvo_banner_vid1_grey.h index 3c43908..74bf8e8 100644 --- a/src/image_data/gvo_banner_vid1_grey.h +++ b/src/image_data/gvo_banner_vid1_grey.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid1_grey_image = { - 30, 60, 3, + 30, 60, 3, 0, "\236\201\221\33\236\235\257!\236\261\306&\236\301\326,\236\314\340.\236\321" "\345/\236\324\3462\236\325\3472\274\334\3567\236\335\3578\2\355\357\341\357" "\357\363\204\360\360\363\1\360\360\364\204\361\361\364\1\362\362\364\204" diff --git a/src/image_data/gvo_banner_vid1_red.h b/src/image_data/gvo_banner_vid1_red.h index 6133f09..f16dbde 100644 --- a/src/image_data/gvo_banner_vid1_red.h +++ b/src/image_data/gvo_banner_vid1_red.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid1_red_image = { - 30, 60, 3, + 30, 60, 3, 0, "\236\201\221\33\236\235\257!\236\261\306&\236\301\326,\236\314\340.\236\321" "\345/\236\324\3462\236\325\3472\274\334\3567\236\335\3578\2\355\357\341\357" "\357\363\204\360\360\363\1\360\360\364\204\361\361\364\1\362\362\364\204" diff --git a/src/image_data/gvo_banner_vid1_yellow.h b/src/image_data/gvo_banner_vid1_yellow.h index d988af3..51fa65e 100644 --- a/src/image_data/gvo_banner_vid1_yellow.h +++ b/src/image_data/gvo_banner_vid1_yellow.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid1_yellow_image = { - 30, 60, 3, + 30, 60, 3, 0, "\236\201\221\33\236\235\257!\236\261\306&\236\301\326,\236\314\340.\236\321" "\345/\236\324\3462\236\325\3472\274\334\3567\236\335\3578\2\355\357\341\357" "\357\363\204\360\360\363\1\360\360\364\204\361\361\364\1\362\362\364\204" diff --git a/src/image_data/gvo_banner_vid2_green.h b/src/image_data/gvo_banner_vid2_green.h index 58852c8..19b8311 100644 --- a/src/image_data/gvo_banner_vid2_green.h +++ b/src/image_data/gvo_banner_vid2_green.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid2_green_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\203\366\366\370" "\1\367\367\370\202\367\367\371\203\370\370\371\202\370\370\372\203\371\371" diff --git a/src/image_data/gvo_banner_vid2_grey.h b/src/image_data/gvo_banner_vid2_grey.h index 6e0b8be..5fa5a57 100644 --- a/src/image_data/gvo_banner_vid2_grey.h +++ b/src/image_data/gvo_banner_vid2_grey.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid2_grey_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\203\366\366\370" "\1\367\367\370\202\367\367\371\203\370\370\371\202\370\370\372\203\371\371" diff --git a/src/image_data/gvo_banner_vid2_red.h b/src/image_data/gvo_banner_vid2_red.h index 78929c3..ecdf9cc 100644 --- a/src/image_data/gvo_banner_vid2_red.h +++ b/src/image_data/gvo_banner_vid2_red.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid2_red_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\203\366\366\370" "\1\367\367\370\202\367\367\371\203\370\370\371\202\370\370\372\203\371\371" diff --git a/src/image_data/gvo_banner_vid2_yellow.h b/src/image_data/gvo_banner_vid2_yellow.h index 8a99d29..2bfc745 100644 --- a/src/image_data/gvo_banner_vid2_yellow.h +++ b/src/image_data/gvo_banner_vid2_yellow.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t gvo_banner_vid2_yellow_image = { - 26, 60, 3, + 26, 60, 3, 0, "\232\201\221\33\232\235\257!\232\261\306&\232\301\326,\232\314\340.\232\321" "\345/\232\324\3462\232\325\3472\264\334\3567\232\335\3578\203\366\366\370" "\1\367\367\370\202\367\367\371\203\370\370\371\202\370\370\372\203\371\371" diff --git a/src/image_data/help_banner.h b/src/image_data/help_banner.h index 180ba91..8218a6e 100644 --- a/src/image_data/help_banner.h +++ b/src/image_data/help_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t help_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\11S]\21Xc\22`k\23hv\25p\177\27x\206\30}\214\32\200\220\33\200\221\33\377" "\201\221\33\305\201\221\33\35\202\222\40\220\232S\224\235e\202\204{zz{\213" "\213\214\225\225\226\233\233\234\237\237\241\241\241\242\237\237\241\234" diff --git a/src/image_data/image.h b/src/image_data/image.h index be21329..2112c7b 100644 --- a/src/image_data/image.h +++ b/src/image_data/image.h @@ -29,6 +29,7 @@ typedef struct { unsigned int width; unsigned int height; unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned int fill_column_index; char *rle_pixel_data; } nv_image_t; diff --git a/src/image_data/led_green.h b/src/image_data/led_green.h index 1015f47..b70132a 100644 --- a/src/image_data/led_green.h +++ b/src/image_data/led_green.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t led_green = {
- 16, 16, 4,
+ 16, 16, 4, 0,
"\221\377\377\377\0\15\366\377\374\0\376\377\377\0\377\374\375\0\354\346\346"
"R\305\303\304\234\302\301\311\327\304\301\324\372\277\273\311\327\267\262"
"\266\234\322\307\327R\377\374\377\0\376\377\363\0\373\377\375\0\203\377\377"
diff --git a/src/image_data/led_grey.h b/src/image_data/led_grey.h index 41218ba..64faa6e 100644 --- a/src/image_data/led_grey.h +++ b/src/image_data/led_grey.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t led_grey = {
- 16, 16, 4,
+ 16, 16, 4, 0,
"\222\377\377\377\0\13\376\376\376\0\377\377\377\0\346\346\346R\275\275\275"
"\234\260\260\260\327\265\265\265\372\253\253\253\327\252\252\252\234\321"
"\321\321R\377\377\377\0\371\371\371\0\205\377\377\377\0\14\376\376\376\27"
diff --git a/src/image_data/led_red.h b/src/image_data/led_red.h index f66a900..045394f 100644 --- a/src/image_data/led_red.h +++ b/src/image_data/led_red.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t led_red = {
- 16, 16, 4,
+ 16, 16, 4, 0,
"\224\377\377\377\0\7\377\376\377J\364\362\365\227\334\330\331\324\325\323"
"\330\372\322\325\336\324\345\352\355\227\371\375\377J\207\377\377\377\0\13"
"\377\376\377\6\370\373\377|\274\313\306\356\326\340\325\377\345\341\326\377"
diff --git a/src/image_data/opengl_banner.h b/src/image_data/opengl_banner.h index 2eb6e86..12ec48c 100644 --- a/src/image_data/opengl_banner.h +++ b/src/image_data/opengl_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t opengl_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\1KY\16\203^q\22\202s\206\26\1z\216\27\377\201\221\33\310\201\221\33\2\217" "\237L\224\233j\202}}\177\10\214\214\217\222\222\224\232\232\235\237\237\243" "\242\242\244\237\237\243\236\235\237\222\222\224\202\214\214\217\202\222" diff --git a/src/image_data/rj45_input.h b/src/image_data/rj45_input.h index 75ea529..4e2dea7 100644 --- a/src/image_data/rj45_input.h +++ b/src/image_data/rj45_input.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rj45_input = {
- 20, 28, 4,
+ 20, 28, 4, 0,
"\225666\377\222\0\0\0\0\202666\377\1\0\0\0\0\206ddd\377\204\0\0\0\0\2066"
"66\377\1\0\0\0\0\202666\377\2\0\0\0\0ddd\377\204\0\377\0\377\1ddd\377\204"
"PPP\377\1""666\377\204\236\245\212\377\2""666\377\0\0\0\0\202666\377\2\0"
diff --git a/src/image_data/rj45_output.h b/src/image_data/rj45_output.h index 95674d8..7aa92d7 100644 --- a/src/image_data/rj45_output.h +++ b/src/image_data/rj45_output.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rj45_output = {
- 20, 28, 4,
+ 20, 28, 4, 0,
"\225666\377\222666\0\202666\377\1""666\0\206ddd\377\203\377\377\377\0\1""6"
"66\0\206666\377\1""666\0\202666\377\2""666\0ddd\377\204y\236y\377\1ddd\377"
"\204PPP\377\1""666\377\204\377\314\2\377\2""666\377\377\377\377\0\202666"
diff --git a/src/image_data/rj45_unused.h b/src/image_data/rj45_unused.h index cb08fe6..a3d01bf 100644 --- a/src/image_data/rj45_unused.h +++ b/src/image_data/rj45_unused.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t rj45_unused = { - 20, 28, 4, + 20, 28, 4, 0, "\225666\200\222\0\0\0\0\202666\200\1\0\0\0\0\206666\200\204\0\0\0\0\2066" "66\200\1\0\0\0\0\202666\200\2\0\0\0\0""666\200\204\0\0\0\0\206666\200\204" "\0\0\0\0\2""666\200\0\0\0\0\202666\200\2\0\0\0\0""666\200\204\0\0\0\0\1""6" diff --git a/src/image_data/rotate_left_off.h b/src/image_data/rotate_left_off.h index e65a9b5..ac3416a 100644 --- a/src/image_data/rotate_left_off.h +++ b/src/image_data/rotate_left_off.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotate_left_off_image = {
- 26, 26, 3,
+ 26, 26, 3, 0,
"\231\230\230\230\177rrr\230\230\230\376\376\376\375\375\375\374\374\374\373"
"\373\373\372\372\372\371\371\371\370\370\370\367\367\367\365\365\365\364"
"\364\364\363\363\363\362\362\362\361\361\361\360\360\360\357\357\357\356"
diff --git a/src/image_data/rotate_left_on.h b/src/image_data/rotate_left_on.h index c7df6e3..7f9bbe2 100644 --- a/src/image_data/rotate_left_on.h +++ b/src/image_data/rotate_left_on.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotate_left_on_image = {
- 26, 26, 3,
+ 26, 26, 3, 0,
"\231222\177\213\213\213222\306\306\306\304\304\304\302\302\302\300\300\300"
"\277\277\277\275\275\275\273\273\273\271\271\271\267\267\267\265\265\265"
"\264\264\264\262\262\262\260\260\260\256\256\256\254\254\254\252\252\252"
diff --git a/src/image_data/rotate_right_off.h b/src/image_data/rotate_right_off.h index 426b0cb..e36c405 100644 --- a/src/image_data/rotate_right_off.h +++ b/src/image_data/rotate_right_off.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotate_right_off_image = {
- 26, 26, 3,
+ 26, 26, 3, 0,
"\231\230\230\230\177rrr\230\230\230\376\376\376\375\375\375\374\374\374\373"
"\373\373\372\372\372\371\371\371\370\370\370\367\367\367\365\365\365\364"
"\364\364\363\363\363\362\362\362\361\361\361\360\360\360\357\357\357\356"
diff --git a/src/image_data/rotate_right_on.h b/src/image_data/rotate_right_on.h index 2f5847e..42f37f7 100644 --- a/src/image_data/rotate_right_on.h +++ b/src/image_data/rotate_right_on.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotate_right_on_image = {
- 26, 26, 3,
+ 26, 26, 3, 0,
"\231222\177\213\213\213222\306\306\306\304\304\304\302\302\302\300\300\300"
"\277\277\277\275\275\275\273\273\273\271\271\271\267\267\267\265\265\265"
"\264\264\264\262\262\262\260\260\260\256\256\256\254\254\254\252\252\252"
diff --git a/src/image_data/rotation_banner.h b/src/image_data/rotation_banner.h index 69ef080..b85ee76 100644 --- a/src/image_data/rotation_banner.h +++ b/src/image_data/rotation_banner.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotation_banner_image = {
- 360, 60, 3,
+ 360, 60, 3, 180,
"\202N_\30\1ct(\203p\206\26\377\201\221\34\311\201\221\34\6\216\247J\220\232"
"l\201\201\203uty\212\213\215\227\227\230\202\235\236\235\1\243\243\244\202"
"\235\236\235\2\221\221\223\212\213\215\203\221\221\223\1\212\213\215\202"
diff --git a/src/image_data/rotation_orientation_horiz.h b/src/image_data/rotation_orientation_horiz.h index c78436e..01c6dfd 100644 --- a/src/image_data/rotation_orientation_horiz.h +++ b/src/image_data/rotation_orientation_horiz.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotation_orientation_horiz_image = {
- 120, 90, 3,
+ 120, 90, 3, 0,
"\377\0\0\0\363\0\0\0\35\7\15\20V\220\272t\277\366v\300\365x\301\365y\301"
"\365{\302\365~\303\364\200\303\364\200\304\364\202\305\364\205\305\363\206"
"\306\363\210\307\363\212\307\363\214\310\362\215\310\362\217\311\362\220"
diff --git a/src/image_data/rotation_orientation_horiz_flipped.h b/src/image_data/rotation_orientation_horiz_flipped.h index fda740c..20ce1d9 100644 --- a/src/image_data/rotation_orientation_horiz_flipped.h +++ b/src/image_data/rotation_orientation_horiz_flipped.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t rotation_orientation_horiz_flipped_image = { - 120, 90, 3, + 120, 90, 3, 0, "\377\0\0\0\363\0\0\0\2\2\16\2\27\233\27\216\37\315\37\2\34\237>\26""9\353" "\340\25""5\375\2\20(\277\1\4\21\204\0\0\0\1\40\240\40\220*\324*\1'\255S\341" "\34F\375\1\25""5\277\204\0\0\0\2224\3334\342$X\375\204\0\0\0\222>\342>\1" diff --git a/src/image_data/rotation_orientation_vert.h b/src/image_data/rotation_orientation_vert.h index 3b1e195..441aba7 100644 --- a/src/image_data/rotation_orientation_vert.h +++ b/src/image_data/rotation_orientation_vert.h @@ -3,7 +3,7 @@ #include "image.h"
static const nv_image_t rotation_orientation_vert_image = {
- 90, 120, 3,
+ 90, 120, 3, 0,
"\377\0\0\0\267\0\0\0\11\12\16\20w\233\265\235\316\360\236\316\360\240\317"
"\360\241\317\360\242\317\360\243\320\357\244\320\357\202\246\321\357\5\247"
"\321\357\250\321\357\250\322\357\251\322\357\252\322\357\202\253\322\357"
diff --git a/src/image_data/rotation_orientation_vert_flipped.h b/src/image_data/rotation_orientation_vert_flipped.h index a6cc354..5586d04 100644 --- a/src/image_data/rotation_orientation_vert_flipped.h +++ b/src/image_data/rotation_orientation_vert_flipped.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t rotation_orientation_vert_flipped_image = { - 90, 120, 3, + 90, 120, 3, 0, "\377\0\0\0\377\0\0\0\222\0\0\0\1\37\246\37\217)\334)\2&\262Q\35M\356\303" "\34E\375\1\25""4\277\204\0\0\0\221.\337.\1+\271\\\304\40N\375\204\0\0\0\222" "4\3424\304#W\375\204\0\0\0\2229\3449\1)s\346\303'`\375\204\0\0\0\221>\347" diff --git a/src/image_data/thermal_banner.h b/src/image_data/thermal_banner.h index 6ff37f0..ce92342 100644 --- a/src/image_data/thermal_banner.h +++ b/src/image_data/thermal_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t thermal_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\205c{\31\377\200\221\32\311\200\221\32\3\202\222$\214\232P\227\237k\202" "}~\177\3\216\217\217\227\227\230\234\236\233\203\243\243\244\2\232\233\240" "\220\220\225\202\216\217\217\202\220\220\225\1\216\217\217\202\205\207\207" diff --git a/src/image_data/tv.h b/src/image_data/tv.h index 957c862..a9a6f60 100644 --- a/src/image_data/tv.h +++ b/src/image_data/tv.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t tv_image = { - 100, 100, 4, + 100, 100, 4, 0, "\377\377\0\377\0\377\377\0\377\0\222\377\0\377\0\203\332\332\332\377\202\271" "\272\274\377\5\252\253\256\377\232\232\237\377\215\215\223\377}}\202\377l" "lx\377\202]]g\377\7rr\177\377\200\200\215\377\215\215\223\377\232\232\237" diff --git a/src/image_data/tv_banner.h b/src/image_data/tv_banner.h index f9fe950..17aa23d 100644 --- a/src/image_data/tv_banner.h +++ b/src/image_data/tv_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t tv_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\1MV'\203]x\20\202l\212\25\377\201\222\34\311\201\222\34\15\215\231L\224" "\232j\202\203\206zz\200\212\212\216\221\221\224\232\233\237\237\237\240\240" "\240\244\237\237\240\232\233\237\221\221\224\212\212\216\203\221\221\224" diff --git a/src/image_data/xvideo_banner.h b/src/image_data/xvideo_banner.h index db72142..92166ac 100644 --- a/src/image_data/xvideo_banner.h +++ b/src/image_data/xvideo_banner.h @@ -3,7 +3,7 @@ #include "image.h" static const nv_image_t xvideo_banner_image = { - 360, 60, 3, + 360, 60, 3, 180, "\204Zr\27\1j\207\30\377\202\222\34\312\202\222\34\7\220\233P\231\243j\200" "\200\201yy{\214\214\217\222\222\224\234\234\237\203\237\237\243\2\234\234" "\237\222\222\224\202\214\214\217\202\222\222\224\4\214\214\217\200\200\211" diff --git a/src/libXNVCtrl/Makefile.inc b/src/libXNVCtrl/Makefile.inc index d256dbb..d3ecbeb 100644 --- a/src/libXNVCtrl/Makefile.inc +++ b/src/libXNVCtrl/Makefile.inc @@ -26,6 +26,7 @@ # EXTRA_DIST += \ + Makefile.inc \ NVCtrl.h \ NVCtrlLib.h \ libXNVCtrl.a \ @@ -33,3 +34,6 @@ EXTRA_DIST += \ nv_control.h \ README.LIBXNVCTRL \ Imakefile + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/libXNVCtrl/NVCtrl.c b/src/libXNVCtrl/NVCtrl.c index 78fe373..cbb7be6 100644 --- a/src/libXNVCtrl/NVCtrl.c +++ b/src/libXNVCtrl/NVCtrl.c @@ -1199,6 +1199,82 @@ Bool XNVCTRLQueryBinaryData ( attribute, ptr, len); } +Bool XNVCTRLStringOperation ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *pIn, + char **ppOut +) { + XExtDisplayInfo *info = find_display(dpy); + xnvCtrlStringOperationReq *req; + xnvCtrlStringOperationReply rep; + Bool ret; + int inSize, outSize, length, slop; + + if (!XextHasExtension(info)) + return False; + + if (!ppOut) + return False; + + *ppOut = NULL; + + XNVCTRLCheckExtension(dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + if (pIn) { + inSize = strlen(pIn) + 1; + } else { + inSize = 0; + } + + LockDisplay(dpy); + GetReq(nvCtrlStringOperation, req); + + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlStringOperation; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + + req->length += ((inSize + 3) & ~3) >> 2; + req->num_bytes = inSize; + + if (pIn) { + Data(dpy, pIn, inSize); + } + + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + length = rep.length; + outSize = rep.num_bytes; + slop = outSize & 3; + + if (outSize) *ppOut = (char *) Xmalloc(outSize); + + if (!*ppOut) { + _XEatData(dpy, length); + } else { + _XRead(dpy, (char *) *ppOut, outSize); + if (slop) _XEatData(dpy, 4-slop); + } + + ret = rep.ret; + + UnlockDisplay(dpy); + SyncHandle(); + + return ret; +} + static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire) { diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h index 86a819c..b015dd7 100644 --- a/src/libXNVCtrl/NVCtrl.h +++ b/src/libXNVCtrl/NVCtrl.h @@ -18,6 +18,7 @@ #define NV_CTRL_TARGET_TYPE_X_SCREEN 0 #define NV_CTRL_TARGET_TYPE_GPU 1 #define NV_CTRL_TARGET_TYPE_FRAMELOCK 2 +#define NV_CTRL_TARGET_TYPE_VCSC 3 /* Visual Computing System Controller */ /**************************************************************************/ @@ -55,6 +56,13 @@ * * F: The attribute may be queried using an NV_CTRL_TARGET_TYPE_FRAMELOCK * target type via XNVCTRLQueryTargetAttribute(). + * + * X: When Xinerama is enabled, this attribute is kept consistent across + * all Physical X Screens; Assignment of this attribute will be + * broadcast by the NVIDIA X Driver to all X Screens. + * + * V: The attribute may be queried using an NV_CTRL_TARGET_TYPE_VCSC + * target type via XNVCTRLQueryTargetXXXAttribute(). * * NOTE: Unless mentioned otherwise, all attributes may be queried using * an NV_CTRL_TARGET_TYPE_X_SCREEN target type via @@ -93,7 +101,7 @@ * ratio correct) */ -#define NV_CTRL_FLATPANEL_SCALING 2 /* RWD */ +#define NV_CTRL_FLATPANEL_SCALING 2 /* RWDG */ #define NV_CTRL_FLATPANEL_SCALING_DEFAULT 0 #define NV_CTRL_FLATPANEL_SCALING_NATIVE 1 #define NV_CTRL_FLATPANEL_SCALING_SCALED 2 @@ -110,7 +118,7 @@ * 2: disabled (the driver will never dither) */ -#define NV_CTRL_FLATPANEL_DITHERING 3 /* RWD */ +#define NV_CTRL_FLATPANEL_DITHERING 3 /* RWDG */ #define NV_CTRL_FLATPANEL_DITHERING_DEFAULT 0 #define NV_CTRL_FLATPANEL_DITHERING_ENABLED 1 #define NV_CTRL_FLATPANEL_DITHERING_DISABLED 2 @@ -121,7 +129,7 @@ * specified display device. */ -#define NV_CTRL_DIGITAL_VIBRANCE 4 /* RWD */ +#define NV_CTRL_DIGITAL_VIBRANCE 4 /* RWDG */ /* @@ -129,7 +137,7 @@ * driving the specified X screen is connected to the computer. */ -#define NV_CTRL_BUS_TYPE 5 /* R-- */ +#define NV_CTRL_BUS_TYPE 5 /* R--G */ #define NV_CTRL_BUS_TYPE_AGP 0 #define NV_CTRL_BUS_TYPE_PCI 1 #define NV_CTRL_BUS_TYPE_PCI_EXPRESS 2 @@ -137,11 +145,16 @@ /* - * NV_CTRL_VIDEO_RAM - returns the amount of video ram on the GPU - * driving the specified X screen. + * NV_CTRL_VIDEO_RAM - returns the total amount of memory available + * to the specified GPU (or the GPU driving the specified X + * screen). Note: if the GPU supports TurboCache(TM), the value + * reported may exceed the amount of video memory installed on the + * GPU. The value reported for integrated GPUs may likewise exceed + * the amount of dedicated system memory set aside by the system + * BIOS for use by the integrated GPU. */ -#define NV_CTRL_VIDEO_RAM 6 /* R-- */ +#define NV_CTRL_VIDEO_RAM 6 /* R--G */ /* @@ -149,7 +162,7 @@ * driving the specified X screen. */ -#define NV_CTRL_IRQ 7 /* R-- */ +#define NV_CTRL_IRQ 7 /* R--G */ /* @@ -157,7 +170,7 @@ * the X server is running. */ -#define NV_CTRL_OPERATING_SYSTEM 8 /* R-- */ +#define NV_CTRL_OPERATING_SYSTEM 8 /* R--G */ #define NV_CTRL_OPERATING_SYSTEM_LINUX 0 #define NV_CTRL_OPERATING_SYSTEM_FREEBSD 1 #define NV_CTRL_OPERATING_SYSTEM_SUNOS 2 @@ -169,7 +182,7 @@ * after this setting is applied. */ -#define NV_CTRL_SYNC_TO_VBLANK 9 /* RW- */ +#define NV_CTRL_SYNC_TO_VBLANK 9 /* RW-X */ #define NV_CTRL_SYNC_TO_VBLANK_OFF 0 #define NV_CTRL_SYNC_TO_VBLANK_ON 1 @@ -182,7 +195,7 @@ * clients that are started after this setting is applied. */ -#define NV_CTRL_LOG_ANISO 10 /* RW- */ +#define NV_CTRL_LOG_ANISO 10 /* RW-X */ /* @@ -203,7 +216,7 @@ * after this setting is applied. */ -#define NV_CTRL_FSAA_MODE 11 /* RW- */ +#define NV_CTRL_FSAA_MODE 11 /* RW-X */ #define NV_CTRL_FSAA_MODE_NONE 0 #define NV_CTRL_FSAA_MODE_2x 1 #define NV_CTRL_FSAA_MODE_2x_5t 2 @@ -223,7 +236,7 @@ * started after this setting is applied. */ -#define NV_CTRL_TEXTURE_SHARPEN 12 /* RW- */ +#define NV_CTRL_TEXTURE_SHARPEN 12 /* RW-X */ #define NV_CTRL_TEXTURE_SHARPEN_OFF 0 #define NV_CTRL_TEXTURE_SHARPEN_ON 1 @@ -566,7 +579,7 @@ * after this setting is applied. */ -#define NV_CTRL_FORCE_GENERIC_CPU 37 /* RW- */ +#define NV_CTRL_FORCE_GENERIC_CPU 37 /* RW-X */ #define NV_CTRL_FORCE_GENERIC_CPU_DISABLE 0 #define NV_CTRL_FORCE_GENERIC_CPU_ENABLE 1 @@ -580,7 +593,7 @@ * applied. */ -#define NV_CTRL_OPENGL_AA_LINE_GAMMA 38 /* RW- */ +#define NV_CTRL_OPENGL_AA_LINE_GAMMA 38 /* RW-X */ #define NV_CTRL_OPENGL_AA_LINE_GAMMA_DISABLE 0 #define NV_CTRL_OPENGL_AA_LINE_GAMMA_ENABLE 1 @@ -606,7 +619,7 @@ * can this be enabled dynamically? */ -#define NV_CTRL_FLIPPING_ALLOWED 40 /* RW- */ +#define NV_CTRL_FLIPPING_ALLOWED 40 /* RW-X */ #define NV_CTRL_FLIPPING_ALLOWED_FALSE 0 #define NV_CTRL_FLIPPING_ALLOWED_TRUE 1 @@ -631,7 +644,7 @@ * GPUS, or incorrect texture clamping in certain applications. */ -#define NV_CTRL_TEXTURE_CLAMPING 42 /* RW- */ +#define NV_CTRL_TEXTURE_CLAMPING 42 /* RW-X */ #define NV_CTRL_TEXTURE_CLAMPING_EDGE 0 #define NV_CTRL_TEXTURE_CLAMPING_SPEC 1 @@ -658,7 +671,7 @@ * NV_CTRL_FSAA_MODE */ -#define NV_CTRL_FSAA_APPLICATION_CONTROLLED 50 /* RW- */ +#define NV_CTRL_FSAA_APPLICATION_CONTROLLED 50 /* RW-X */ #define NV_CTRL_FSAA_APPLICATION_CONTROLLED_ENABLED 1 #define NV_CTRL_FSAA_APPLICATION_CONTROLLED_DISABLED 0 @@ -670,7 +683,7 @@ * NV_CTRL_LOG_ANISO */ -#define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED 51 /* RW- */ +#define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED 51 /* RW-X */ #define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_ENABLED 1 #define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_DISABLED 0 @@ -682,7 +695,7 @@ * newer. */ -#define NV_CTRL_IMAGE_SHARPENING 52 /* RWD */ +#define NV_CTRL_IMAGE_SHARPENING 52 /* RWDG */ /* @@ -690,7 +703,7 @@ * display device. */ -#define NV_CTRL_TV_OVERSCAN 53 /* RWD */ +#define NV_CTRL_TV_OVERSCAN 53 /* RWDG */ /* @@ -698,7 +711,7 @@ * the specified display device. */ -#define NV_CTRL_TV_FLICKER_FILTER 54 /* RWD */ +#define NV_CTRL_TV_FLICKER_FILTER 54 /* RWDG */ /* @@ -706,7 +719,7 @@ * specified display device. */ -#define NV_CTRL_TV_BRIGHTNESS 55 /* RWD */ +#define NV_CTRL_TV_BRIGHTNESS 55 /* RWDG */ /* @@ -714,7 +727,7 @@ * device. */ -#define NV_CTRL_TV_HUE 56 /* RWD */ +#define NV_CTRL_TV_HUE 56 /* RWDG */ /* @@ -722,7 +735,7 @@ * display device. */ -#define NV_CTRL_TV_CONTRAST 57 /* RWD */ +#define NV_CTRL_TV_CONTRAST 57 /* RWDG */ /* @@ -730,7 +743,7 @@ * specified display device. */ -#define NV_CTRL_TV_SATURATION 58 /* RWD */ +#define NV_CTRL_TV_SATURATION 58 /* RWDG */ /* @@ -740,7 +753,7 @@ * the TV attributes be queried to retrieve their new values. */ -#define NV_CTRL_TV_RESET_SETTINGS 59 /* -WD */ +#define NV_CTRL_TV_RESET_SETTINGS 59 /* -WDG */ /* @@ -748,7 +761,7 @@ * of the GPU driving the X screen. */ -#define NV_CTRL_GPU_CORE_TEMPERATURE 60 /* R-- */ +#define NV_CTRL_GPU_CORE_TEMPERATURE 60 /* R--G */ /* @@ -761,9 +774,9 @@ * GPU is throttled to prevent overheating. */ -#define NV_CTRL_GPU_CORE_THRESHOLD 61 /* R-- */ -#define NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD 62 /* R-- */ -#define NV_CTRL_GPU_MAX_CORE_THRESHOLD 63 /* R-- */ +#define NV_CTRL_GPU_CORE_THRESHOLD 61 /* R--G */ +#define NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD 62 /* R--G */ +#define NV_CTRL_GPU_MAX_CORE_THRESHOLD 63 /* R--G */ /* @@ -771,7 +784,7 @@ * immediate neighbourhood of the GPU driving the X screen. */ -#define NV_CTRL_AMBIENT_TEMPERATURE 64 /* R-- */ +#define NV_CTRL_AMBIENT_TEMPERATURE 64 /* R--G */ /* @@ -952,16 +965,16 @@ #define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274 26 #define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274 27 #define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274 28 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE372 29 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE372 30 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_30_00_SMPTE372 31 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_29_97_SMPTE372 32 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE372 33 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_25_00_SMPTE372 34 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE372 35 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_98_SMPTE372 36 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_24_00_SMPTE372 37 -#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_23_98_SMPTE372 38 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_30_00_SMPTE372 29 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_29_97_SMPTE372 30 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_60_00_SMPTE372 31 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_59_94_SMPTE372 32 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_25_00_SMPTE372 33 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_50_00_SMPTE372 34 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_24_00_SMPTE372 35 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_23_98_SMPTE372 36 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_48_00_SMPTE372 37 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_47_96_SMPTE372 38 /* * NV_CTRL_GVO_INPUT_VIDEO_FORMAT - indicates the input video format @@ -1186,7 +1199,7 @@ * has been enabled in the X server (by the user). */ -#define NV_CTRL_GPU_OVERCLOCKING_STATE 88 /* RW- */ +#define NV_CTRL_GPU_OVERCLOCKING_STATE 88 /* RW-G */ #define NV_CTRL_GPU_OVERCLOCKING_STATE_NONE 0 #define NV_CTRL_GPU_OVERCLOCKING_STATE_MANUAL 1 @@ -1205,8 +1218,8 @@ * attribute after the set to determine success or failure. */ -#define NV_CTRL_GPU_2D_CLOCK_FREQS 89 /* RW- */ -#define NV_CTRL_GPU_3D_CLOCK_FREQS 90 /* RW- */ +#define NV_CTRL_GPU_2D_CLOCK_FREQS 89 /* RW-G */ +#define NV_CTRL_GPU_3D_CLOCK_FREQS 90 /* RW-G */ /* @@ -1214,8 +1227,8 @@ * and GPU core clocks of the device driving the X screen. */ -#define NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS 91 /* R-- */ -#define NV_CTRL_GPU_DEFAULT_3D_CLOCK_FREQS 92 /* R-- */ +#define NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS 91 /* R--G */ +#define NV_CTRL_GPU_DEFAULT_3D_CLOCK_FREQS 92 /* R--G */ /* @@ -1223,7 +1236,7 @@ * clocks of the graphics device driving the X screen. */ -#define NV_CTRL_GPU_CURRENT_CLOCK_FREQS 93 /* R-- */ +#define NV_CTRL_GPU_CURRENT_CLOCK_FREQS 93 /* R--G */ /* @@ -1237,7 +1250,7 @@ * optimal clock detection process is unavailable. */ -#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS 94 /* R-- */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS 94 /* R--G */ #define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_INVALID 0 @@ -1255,7 +1268,7 @@ * optimal clock detection process is unavailable. */ -#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION 95 /* -W- */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION 95 /* -W-G */ #define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_START 0 #define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_CANCEL 1 @@ -1270,7 +1283,7 @@ * optimal clock detection process is unavailable. */ -#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE 96 /* R-- */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE 96 /* R--G */ #define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_IDLE 0 #define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_BUSY 1 @@ -2543,7 +2556,6 @@ * stereo drawable is visible. */ - #define NV_CTRL_FORCE_STEREO 220 /* RW- */ #define NV_CTRL_FORCE_STEREO_FALSE 0 #define NV_CTRL_FORCE_STEREO_TRUE 1 @@ -2556,7 +2568,7 @@ * after this setting is applied. */ -#define NV_CTRL_IMAGE_SETTINGS 221 /* RW- */ +#define NV_CTRL_IMAGE_SETTINGS 221 /* RW-X */ #define NV_CTRL_IMAGE_SETTINGS_HIGH_QUALITY 0 #define NV_CTRL_IMAGE_SETTINGS_QUALITY 1 #define NV_CTRL_IMAGE_SETTINGS_PERFORMANCE 2 @@ -2567,8 +2579,7 @@ * NV_CTRL_XINERAMA - return whether xinerama is enabled */ - -#define NV_CTRL_XINERAMA 222 /* RW- */ +#define NV_CTRL_XINERAMA 222 /* R--G */ #define NV_CTRL_XINERAMA_OFF 0 #define NV_CTRL_XINERAMA_ON 1 @@ -2589,19 +2600,19 @@ * returns the width of the physical link. */ -#define NV_CTRL_BUS_RATE 224 /* R-- */ +#define NV_CTRL_BUS_RATE 224 /* R--G */ /* * NV_CTRL_SHOW_SLI_HUD - when TRUE, OpenGL will draw information about the * current SLI mode. */ -#define NV_CTRL_SHOW_SLI_HUD 225 /* RW- */ +#define NV_CTRL_SHOW_SLI_HUD 225 /* RW-X */ #define NV_CTRL_SHOW_SLI_HUD_FALSE 0 #define NV_CTRL_SHOW_SLI_HUD_TRUE 1 /* - * NV_CTRL_XV_SYNC_TO_DISPLAY - this control is valid when twinview and + * NV_CTRL_XV_SYNC_TO_DISPLAY - this control is valid when TwinView and * XVideo Sync To VBlank are enabled. * It controls which display device will be synched to. */ @@ -2739,10 +2750,99 @@ * specified display device. */ -#define NV_CTRL_CURRENT_SCANLINE 237 /* R-D */ +#define NV_CTRL_CURRENT_SCANLINE 237 /* R-DG */ + + +/* + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT - Controls where X pixmaps are initially + * created. + * + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM causes to pixmaps to stay in + * system memory. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM creates pixmaps in system memory + * initially, but allows them to migrate to video memory. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM creates pixmaps in video memory + * when enough resources are available. + */ + +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT 238 /* RW- */ +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM 0 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM 1 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM 2 + + +/* + * NV_CTRL_PCI_BUS - Returns the PCI bus number the GPU is using. + */ +#define NV_CTRL_PCI_BUS 239 /* R--G */ -#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_CURRENT_SCANLINE + +/* + * NV_CTRL_PCI_DEVICE - Returns the PCI device number the GPU is using. + */ + +#define NV_CTRL_PCI_DEVICE 240 /* R--G */ + + +/* + * NV_CTRL_PCI_FUNCTION - Returns the PCI function number the GPU is using. + */ + +#define NV_CTRL_PCI_FUNCTION 241 /* R--G */ + + +/* + * NV_CTRL_FRAMELOCK_FPGA_REVISION - Querys the FPGA revision of the + * Frame Lock device. + * + * This attribute must be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. + */ + +#define NV_CTRL_FRAMELOCK_FPGA_REVISION 242 /* R--F */ + + +/* + * NV_CTRL_MAX_SCREEN_{WIDTH,HEIGHT} - the maximum allowable size, in + * pixels, of either the specified X screen (if the target_type of the + * query is an X screen), or any X screen on the specified GPU (if the + * target_type of the query is a GPU). + */ + +#define NV_CTRL_MAX_SCREEN_WIDTH 243 /* R--G */ +#define NV_CTRL_MAX_SCREEN_HEIGHT 244 /* R--G */ + + +/* + * NV_CTRL_MAX_DISPLAYS - the maximum number of display devices that + * can be driven simultaneously on a GPU (e.g., that can be used in a + * MetaMode at once). Note that this does not indicate the maximum + * number of bits that can be set in NV_CTRL_CONNECTED_DISPLAYS, + * because more display devices can be connected than are actively in + * use. + */ + +#define NV_CTRL_MAX_DISPLAYS 245 /* R--G */ + + +/* + * NV_CTRL_DYNAMIC_TWINVIEW - Returns whether or not the screen + * supports dynamic twinview. + */ + +#define NV_CTRL_DYNAMIC_TWINVIEW 246 /* R-- */ + + +/* + * NV_CTRL_MULTIGPU_DISPLAY_OWNER - Returns the GPU ID of the GPU + * that has the display device(s) used for showing the X Screen. + */ + +#define NV_CTRL_MULTIGPU_DISPLAY_OWNER 247 /* R-- */ + + +#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_MULTIGPU_DISPLAY_OWNER /**************************************************************************/ @@ -2781,7 +2881,7 @@ * which the specified X screen is running. */ -#define NV_CTRL_STRING_VBIOS_VERSION 1 /* R-- */ +#define NV_CTRL_STRING_VBIOS_VERSION 1 /* R--G */ /* @@ -2789,7 +2889,7 @@ * NVIDIA driver version number for the NVIDIA X driver in use. */ -#define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION 3 /* R-- */ +#define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION 3 /* R--G */ /* @@ -2808,7 +2908,7 @@ * specified display device; only valid if the display device is a TV. */ -#define NV_CTRL_STRING_TV_ENCODER_NAME 5 /* R-D */ +#define NV_CTRL_STRING_TV_ENCODER_NAME 5 /* R-DG */ /* NV_CTRL_STRING_DDCCI_MISC_TRANSMIT_DISPLAY_DESCRIPTOR - @@ -2841,35 +2941,44 @@ /* - * NV_CTRL_STRING_CURRENT_MODELINE - Return the modeline currently + * NV_CTRL_STRING_CURRENT_MODELINE - Return the ModeLine currently * being used by the specified display device. * * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() - * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * + * The ModeLine string may be prepended with a comma-separated list of + * "token=value" pairs, separated from the ModeLine string by "::". + * This "token=value" syntax is the same as that used in + * NV_CTRL_BINARY_DATA_MODELINES */ #define NV_CTRL_STRING_CURRENT_MODELINE 9 /* R-DG */ /* - * NV_CTRL_STRING_ADD_MODELINE - Adds a modeline to the specified - * display device. The modeline is not added if validation fails. + * NV_CTRL_STRING_ADD_MODELINE - Adds a ModeLine to the specified + * display device. The ModeLine is not added if validation fails. * - * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() - * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * The ModeLine string should have the same syntax as a ModeLine in + * the X configuration file; e.g., + * + * "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync */ #define NV_CTRL_STRING_ADD_MODELINE 10 /* -WDG */ /* - * NV_CTRL_STRING_DELETE_MODLEINE - Deletes an existing modeline + * NV_CTRL_STRING_DELETE_MODELINE - Deletes an existing ModeLine * from the specified display device. The currently selected - * modeline cannot be deleted. (This also means you cannot delete - * the last modeline.) + * ModeLine cannot be deleted. (This also means you cannot delete + * the last ModeLine.) * - * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() - * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * The ModeLine string should have the same syntax as a ModeLine in + * the X configuration file; e.g., + * + * "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync */ #define NV_CTRL_STRING_DELETE_MODELINE 11 /* -WDG */ @@ -2877,36 +2986,244 @@ /* * NV_CTRL_STRING_CURRENT_METAMODE - Returns the metamode currently - * being used by the specified X screen. + * being used by the specified X screen. The MetaMode string has the + * same syntax as the MetaMode X configuration option, as documented + * in the NVIDIA driver README. + * + * The returned string may be prepended with a comma-separated list of + * "token=value" pairs, separated from the MetaMode string by "::". + * This "token=value" syntax is the same as that used in + * NV_CTRL_BINARY_DATA_METAMODES. */ #define NV_CTRL_STRING_CURRENT_METAMODE 12 /* R--- */ /* - * NV_CTRL_STRING_ADD_METAMODE - Adds a metamode to the specified - * X Screen (or GPU). All modelines referenced in the metamode - * must already exist for each display device (as returned by the - * NV_CTRL_BINARY_DATA_MODELINES attribute) + * NV_CTRL_STRING_ADD_METAMODE - Adds a MetaMode to the specified + * X Screen. * - * TwinView must be enabled on the X Screen/GPU to access this attribute. + * It is recommended to not use this attribute, but instead use + * NV_CTRL_STRING_OPERATION_ADD_METAMODE. */ #define NV_CTRL_STRING_ADD_METAMODE 13 /* -W-- */ /* - * NV_CTRL_STRING_DELETE_METAMODE - Deletes an existing metamode - * from the specified X Screen (or GPU). The currently selected - * metamode cannot be deleted. (This also means you cannot delete - * the last metamode.) - * - * TwinView must be enabled on the X Screen/GPU to access this attribute. + * NV_CTRL_STRING_DELETE_METAMODE - Deletes an existing MetaMode from + * the specified X Screen. The currently selected MetaMode cannot be + * deleted. (This also means you cannot delete the last MetaMode). + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. */ #define NV_CTRL_STRING_DELETE_METAMODE 14 /* -WD-- */ -#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_DELETE_METAMODE + +/* + * NV_CTRL_STRING_VCSC_PRODUCT_NAME - Querys the product name of the + * VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_PRODUCT_NAME 15 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_PRODUCT_ID - Querys the product ID of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_PRODUCT_ID 16 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_SERIAL_NUMBER - Querys the unique serial number + * of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_SERIAL_NUMBER 17 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_BUILD_DATE - Querys the date of the VCSC device. + * the returned string is in the following format: "Week.Year" + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_BUILD_DATE 18 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_FIRMWARE_VERSION - Querys the firmware version + * of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_FIRMWARE_VERSION 19 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_FIRMWARE_REVISION - Querys the firmware revision + * of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_FIRMWARE_REVISION 20 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_HARDWARE_VERSION - Querys the hardware version + * of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_HARDWARE_VERSION 21 /* R---V */ + + +/* + * NV_CTRL_STRING_VCSC_HARDWARE_REVISION - Querys the hardware revision + * of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_HARDWARE_REVISION 22 /* R---V */ + + +/* + * NV_CTRL_STRING_MOVE_METAMODE - Moves a MetaMode to the specified + * index location. The MetaMode must already exist in the X Screen's + * list of MetaModes (as returned by the NV_CTRL_BINARY_DATA_METAMODES + * attribute). If the index is larger than the number of MetaModes in + * the list, the MetaMode is moved to the end of the list. The + * MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + + * The MetaMode string must be prepended with a comma-separated list + * of "token=value" pairs, separated from the MetaMode string by "::". + * Currently, the only valid token is "index", which indicates where + * in the MetaMode list the MetaMode should be moved to. + * + * Other tokens may be added in the future. + * + * E.g., + * "index=5 :: CRT-0: 1024x768 @1024x768 +0+0" + */ + +#define NV_CTRL_STRING_MOVE_METAMODE 23 /* -W-- */ + + + +/* + * NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES - returns the valid + * horizontal sync ranges used to perform mode validation for the + * specified display device. The ranges are in the same format as the + * "HorizSync" X config option: + * + * "horizsync-range may be a comma separated list of either discrete + * values or ranges of values. A range of values is two values + * separated by a dash." + * + * The values are in kHz. + * + * Additionally, the string may be prepended with a comma-separated + * list of "token=value" pairs, separated from the HorizSync string by + * "::". Valid tokens: + * + * Token Value + * "source" "edid" - HorizSync is from the display device's EDID + * "xconfig" - HorizSync is from the "HorizSync" entry in + * the Monitor section of the X config file + * "option" - HorizSync is from the "HorizSync" NVIDIA X + * config option + * "twinview" - HorizSync is from the "SecondMonitorHorizSync" + * NVIDIA X config option + * "builtin" - HorizSync is from NVIDIA X driver builtin + * default values + * + * Additional tokens and/or values may be added in the future. + * + * Example: "source=edid :: 30.000-62.000" + */ + +#define NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES 24 /* R-DG */ + + +/* + * NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES - returns the valid + * vertical refresh ranges used to perform mode validation for the + * specified display device. The ranges are in the same format as the + * "VertRefresh" X config option: + * + * "vertrefresh-range may be a comma separated list of either discrete + * values or ranges of values. A range of values is two values + * separated by a dash." + * + * The values are in Hz. + * + * Additionally, the string may be prepended with a comma-separated + * list of "token=value" pairs, separated from the VertRefresh string by + * "::". Valid tokens: + * + * Token Value + * "source" "edid" - VertRefresh is from the display device's EDID + * "xconfig" - VertRefresh is from the "VertRefresh" entry in + * the Monitor section of the X config file + * "option" - VertRefresh is from the "VertRefresh" NVIDIA X + * config option + * "twinview" - VertRefresh is from the "SecondMonitorVertRefresh" + * NVIDIA X config option + * "builtin" - VertRefresh is from NVIDIA X driver builtin + * default values + * + * Additional tokens and/or values may be added in the future. + * + * Example: "source=edid :: 50.000-75.000" + */ + +#define NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES 25 /* R-DG */ + + +/* + * NV_CTRL_STRING_XINERAMA_SCREEN_INFO - returns the physical X Screen's + * initial position and size (in absolute coordinates) within the Xinerama + * desktop as the "token=value" string: "x=#, y=#, width=#, height=#" + * + * Querying this attribute returns FALSE if NV_CTRL_XINERAMA is not + * NV_CTRL_XINERAMA_ON. + */ + +#define NV_CTRL_STRING_XINERAMA_SCREEN_INFO 26 /* R--- */ + + +/* + * NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER - used to specify the + * order that display devices will be returned via Xinerama when + * TwinViewXineramaInfo is enabled. Follows the same syntax as the + * TwinViewXineramaInfoOrder X config option. + */ + +#define NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER 27 /* RW-- */ + +#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER /**************************************************************************/ @@ -2939,13 +3256,43 @@ /* * NV_CTRL_BINARY_DATA_MODELINES - Returns a display device's supported - * modelines. Modelines are returned in a buffer, separated by a single - * \0 and terminated by two consecuitive \0's like so: + * ModeLines. ModeLines are returned in a buffer, separated by a single + * '\0' and terminated by two consecutive '\0' s like so: * - * "Modeline 1\0Modeline 2\0Modeline 3\0Last Modeline\0\0" + * "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0" * * This attribute may be queried through XNVCTRLQueryTargetBinaryData() * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * + * Each ModeLine string may be prepended with a comma-separated list + * of "token=value" pairs, separated from the ModeLine string with a + * "::". Valid tokens: + * + * Token Value + * "source" "xserver" - the ModeLine is from the core X server + * "xconfig" - the ModeLine was specified in the X config file + * "builtin" - the NVIDIA driver provided this builtin ModeLine + * "vesa" - this is a VESA standard ModeLine + * "edid" - the ModeLine was in the display device's EDID + * "nv-control" - the ModeLine was specified via NV-CONTROL + * + * "xconfig-name" - for ModeLines that were specified in the X config + * file, this is the name the X config file + * gave for the ModeLine. + * + * Note that a ModeLine can have several sources; the "source" token + * can appear multiple times in the "token=value" pairs list. + * Additional source values may be specified in the future. + * + * Additional tokens may be added in the future, so it is recommended + * that any token parser processing the returned string from + * NV_CTRL_BINARY_DATA_MODELINES be implemented to gracefully ignore + * unrecognized tokens. + * + * E.g., + * + * "source=xserver, source=vesa, source=edid :: "1024x768_70" 75.0 1024 1048 1184 1328 768 771 777 806 -HSync -VSync" + * "source=xconfig, xconfig-name=1600x1200_60.00 :: "1600x1200_60_0" 161.0 1600 1704 1880 2160 1200 1201 1204 1242 -HSync +VSync" */ #define NV_CTRL_BINARY_DATA_MODELINES 1 /* R-DG */ @@ -2953,10 +3300,47 @@ /* * NV_CTRL_BINARY_DATA_METAMODES - Returns an X Screen's supported - * metamodes. Metamodes are returned in a buffer separated by a single - * \0 and terminated by two consecuitive \0's like so: + * MetaModes. MetaModes are returned in a buffer separated by a + * single '\0' and terminated by two consecutive '\0' s like so: * * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" + * + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + + * Each MetaMode string may be prepended with a comma-separated list + * of "token=value" pairs, separated from the MetaMode string with + * "::". Currently, valid tokens are: + * + * Token Value + * "id" <number> - the id of this MetaMode; this is stored in + * the Vertical Refresh field, as viewed + * by the XRandR and XF86VidMode X * + * extensions. + * + * "switchable" "yes"/"no" - whether this MetaMode may be switched to via + * ctrl-alt-+/-; Implicit MetaModes (see + * the "IncludeImplicitMetaModes" X + * config option), for example, are not + * normally made available through + * ctrl-alt-+/-. + * + * "source" "xconfig" - the MetaMode was specified in the X + * config file. + * "implicit" - the MetaMode was implicitly added; see the + * "IncludeImplicitMetaModes" X config option + * for details. + * "nv-control" - the MetaMode was added via the NV-CONTROL X + * extension to the currently running X server. + * + * Additional tokens may be added in the future, so it is recommended + * that any token parser processing the returned string from + * NV_CTRL_BINARY_DATA_METAMODES be implemented to gracefully ignore + * unrecognized tokens. + * + * E.g., + * + * "id=50, switchable=yes, source=xconfig :: CRT-0: 1024x768 @1024x768 +0+0" */ #define NV_CTRL_BINARY_DATA_METAMODES 2 /* R-D- */ @@ -2978,6 +3362,7 @@ #define NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU 3 /* R-DG */ + /* * NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN - Returns the list of GPUs * currently in use by the given X screen. @@ -2990,6 +3375,7 @@ #define NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN 4 /* R--- */ + /* * NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK - Returns the list of * GPUs currently connected to the given frame lock board. @@ -3006,8 +3392,153 @@ #define NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK 5 /* R-DF */ + +/* + * NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT - Returns the Display Device's + * viewport box into the given X Screen (in X Screen coordinates.) + * + * The format of the returned data is: + * + * 4 CARD32 Offset X + * 4 CARD32 Offset Y + * 4 CARD32 Width + * 4 CARD32 Height + */ + +#define NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT 6 /* R-DG */ + + #define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE \ - NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK + NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT + + +/**************************************************************************/ + +/* + * String Operation Attributes: + * + * These attributes are used with the XNVCTRLStringOperation() + * function; a string is specified as input, and a string is returned + * as output. + * + * Unless otherwise noted, all attributes can be operated upon using + * an NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + + +/* + * NV_CTRL_STRING_OPERATION_ADD_METAMODE - provide a MetaMode string + * as input, and returns a string containing comma-separated list of + * "token=value" pairs as output. Currently, the only output token is + * "id", which indicates the id that was assigned to the MetaMode. + * + * All ModeLines referenced in the MetaMode must already exist for + * each display device (as returned by the + * NV_CTRL_BINARY_DATA_MODELINES attribute). + * + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + * + * The input string can optionally be prepended with a string of + * comma-separated "token=value" pairs, separated from the MetaMode + * string by "::". Currently, the only valid token is "index" which + * indicates the insertion index for the MetaMode. + * + * E.g., + * + * Input: "index=5 :: 1600x1200+0+0, 1600x1200+1600+0" + * Output: "id=58" + * + * which causes the MetaMode to be inserted at position 5 in the + * MetaMode list (all entries after 5 will be shifted down one slot in + * the list), and the X server's containing mode stores 58 as the + * VRefresh, so that the MetaMode can be uniquely identifed through + * XRandR and XF86VidMode. + */ + +#define NV_CTRL_STRING_OPERATION_ADD_METAMODE 0 + + +/* + * NV_CTRL_STRING_OPERATION_GTF_MODELINE - provide as input a string + * of comma-separated "token=value" pairs, and returns a ModeLine + * string, computed using the GTF formula using the parameters from + * the input string. Valid tokens for the input string are "width", + * "height", and "refreshrate". + * + * E.g., + * + * Input: "width=1600, height=1200, refreshrate=60" + * Output: "160.96 1600 1704 1880 2160 1200 1201 1204 1242 -HSync +VSync" + * + * This operation does not have any impact on any display device's + * modePool, and the ModeLine is not validated; it is simply intended + * for generating ModeLines. + */ + +#define NV_CTRL_STRING_OPERATION_GTF_MODELINE 1 + + +/* + * NV_CTRL_STRING_OPERATION_CVT_MODELINE - provide as input a string + * of comma-separated "token=value" pairs, and returns a ModeLine + * string, computed using the CVT formula using the parameters from + * the input string. Valid tokens for the input string are "width", + * "height", "refreshrate", and "reduced-blanking". The + * "reduced-blanking" argument can be "0" or "1", to enable or disable + * use of reduced blanking for the CVT formula. + * + * E.g., + * + * Input: "width=1600, height=1200, refreshrate=60, reduced-blanking=1" + * Output: "130.25 1600 1648 1680 1760 1200 1203 1207 1235 +HSync -VSync" + * + * This operation does not have any impact on any display device's + * modePool, and the ModeLine is not validated; it is simply intended + * for generating ModeLines. + */ + +#define NV_CTRL_STRING_OPERATION_CVT_MODELINE 2 + + +/* + * NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL - build a ModePool for the + * specified display device on the specified target (either an X + * screen or a GPU). This is typically used to generate a ModePool + * for a display device on a GPU on which no X screens are present. + * + * Currently, a display device's ModePool is static for the life of + * the X server, so XNVCTRLStringOperation will return FALSE if + * requested to build a ModePool on a display device that already has + * a ModePool. + * + * The string input to BUILD_MODEPOOL may be NULL. If it is not NULL, + * then it is interpreted as a double-semicolon ("::") separated list + * of "option=value" pairs, where the options and the syntax of their + * values are the X configuration options that impact the behavior of + * modePool construction; namely: + * + * "ModeValidation" + * "HorizSync" + * "VertRefresh" + * "FlatPanelProperties" + * "TVStandard" + * "ExactModeTimingsDVI" + * "UseEdidFreqs" + * + * An example input string might look like: + * + * "ModeValidation=NoVesaModes :: HorizSync=50-110 :: VertRefresh=50-150" + * + * This request currently does not return a string. + */ + +#define NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL 3 /* DG */ + + +#define NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE \ + NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL + /**************************************************************************/ @@ -3049,6 +3580,9 @@ * ATTRIBUTE_TYPE_GPU - Attribute is valid for GPU target types. * ATTRIBUTE_TYPE_FRAMELOCK - Attribute is valid for Frame Lock target types. * ATTRIBUTE_TYPE_X_SCREEN - Attribute is valid for X Screen target types. + * ATTRIBUTE_TYPE_XINERAMA - Attribute will be made consistent for all + * X Screens when the Xinerama extension is enabled. + * * * See 'Key to Integer Attribute "Permissions"' at the top of this * file for a description of what these permission bits mean. @@ -3067,6 +3601,8 @@ #define ATTRIBUTE_TYPE_GPU 0x08 #define ATTRIBUTE_TYPE_FRAMELOCK 0x10 #define ATTRIBUTE_TYPE_X_SCREEN 0x20 +#define ATTRIBUTE_TYPE_XINERAMA 0x40 +#define ATTRIBUTE_TYPE_VCSC 0x80 typedef struct _NVCTRLAttributeValidValues { int type; diff --git a/src/libXNVCtrl/NVCtrlLib.h b/src/libXNVCtrl/NVCtrlLib.h index 318e978..75b07ad 100644 --- a/src/libXNVCtrl/NVCtrlLib.h +++ b/src/libXNVCtrl/NVCtrlLib.h @@ -661,6 +661,25 @@ Bool XNVCTRLQueryTargetBinaryData ( /* + * XNVCTRLStringOperation - + * + * Takes a string as input and returns a Xmalloc'ed string as output. + * Returns True on success and False on failure. + */ + +Bool XNVCTRLStringOperation ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *pIn, + char **ppOut +); + + + +/* * XNVCtrlSelectNotify - * * This enables/disables receiving of NV-CONTROL events. The type diff --git a/src/libXNVCtrl/libXNVCtrl.a b/src/libXNVCtrl/libXNVCtrl.a Binary files differindex 9ec60d2..3b9c342 100644 --- a/src/libXNVCtrl/libXNVCtrl.a +++ b/src/libXNVCtrl/libXNVCtrl.a diff --git a/src/libXNVCtrl/nv_control.h b/src/libXNVCtrl/nv_control.h index e595918..012f397 100644 --- a/src/libXNVCtrl/nv_control.h +++ b/src/libXNVCtrl/nv_control.h @@ -6,7 +6,7 @@ #define NV_CONTROL_NAME "NV-CONTROL" #define NV_CONTROL_MAJOR 1 -#define NV_CONTROL_MINOR 10 +#define NV_CONTROL_MINOR 12 #define X_nvCtrlQueryExtension 0 #define X_nvCtrlIsNv 1 @@ -33,7 +33,8 @@ #define X_nvCtrlQueryGvoColorConversion 22 #define X_nvCtrlSelectTargetNotify 23 #define X_nvCtrlQueryTargetCount 24 -#define X_nvCtrlLastRequest (X_nvCtrlQueryTargetCount + 1) +#define X_nvCtrlStringOperation 25 +#define X_nvCtrlLastRequest (X_nvCtrlStringOperation + 1) /* Define 32 bit floats */ @@ -609,6 +610,32 @@ typedef struct { #define sz_xnvCtrlSelectNotifyReq 12 typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 num_bytes B32; /* Length of string */ +} xnvCtrlStringOperationReq; +#define sz_xnvCtrlStringOperationReq 20 + +typedef struct { + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ret B32; + CARD32 num_bytes B32; /* Length of string */ + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; +} xnvCtrlStringOperationReply; +#define sz_xnvCtrlStringOperationReply 32 + +typedef struct { union { struct { BYTE type; diff --git a/src/libXNVCtrlAttributes/Makefile.inc b/src/libXNVCtrlAttributes/Makefile.inc index 257cc7f..7c2a87c 100644 --- a/src/libXNVCtrlAttributes/Makefile.inc +++ b/src/libXNVCtrlAttributes/Makefile.inc @@ -34,5 +34,9 @@ SRC += \ NvCtrlAttributesXrandr.c EXTRA_DIST += \ + Makefile.inc \ NvCtrlAttributes.h \ NvCtrlAttributesPrivate.h + +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.c b/src/libXNVCtrlAttributes/NvCtrlAttributes.c index 5cea7c5..172acf0 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.c @@ -299,6 +299,163 @@ int NvCtrlGetXrandrEventBase(NvCtrlAttributeHandle *handle) } /* NvCtrlGetXrandrEventBase() */ +/* + * NvCtrlGetServerVendor() - return the server vendor + * information string associated with this + * NvCtrlAttributeHandle. + */ + +char *NvCtrlGetServerVendor(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return NULL; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->dpy) return NULL; + return ServerVendor(h->dpy); + +} /* NvCtrlGetServerVendor() */ + + +/* + * NvCtrlGetVendorRelease() - return the server vendor + * release number associated with this NvCtrlAttributeHandle. + */ + +int NvCtrlGetVendorRelease(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->dpy) return -1; + return VendorRelease(h->dpy); + +} /* NvCtrlGetVendorRelease() */ + + +/* + * NvCtrlGetScreenCount() - return the number of (logical) + * X Screens associated with this NvCtrlAttributeHandle. + */ + +int NvCtrlGetScreenCount(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->dpy) return -1; + return ScreenCount(h->dpy); + +} /* NvCtrlGetScreenCount() */ + + +/* + * NvCtrlGetProtocolVersion() - Returns the majoy version + * number of the X protocol (server). + */ + +int NvCtrlGetProtocolVersion(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->dpy) return -1; + return ProtocolVersion(h->dpy); + +} /* NvCtrlGetProtocolVersion() */ + + +/* + * NvCtrlGetProtocolRevision() - Returns the revision number + * of the X protocol (server). + */ + +int NvCtrlGetProtocolRevision(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->dpy) return -1; + return ProtocolRevision(h->dpy); + +} /* NvCtrlGetProtocolRevision() */ + + +/* + * NvCtrlGetScreenWidthMM() - return the width (in Millimeters) of the + * screen associated with this NvCtrlAttributeHandle. + */ + +int NvCtrlGetScreenWidthMM(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; + + return DisplayWidthMM(h->dpy, h->target_id); + +} /* NvCtrlGetScreenWidthMM() */ + + +/* + * NvCtrlGetScreenHeightMM() - return the height (in Millimeters) of the + * screen associated with this NvCtrlAttributeHandle. + */ + +int NvCtrlGetScreenHeightMM(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; + + return DisplayHeightMM(h->dpy, h->target_id); + +} /* NvCtrlGetScreenHeightMM() */ + + +/* + * NvCtrlGetScreenPlanes() - return the number of planes (the depth) + * of the screen associated with this NvCtrlAttributeHandle. + */ + +int NvCtrlGetScreenPlanes(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; + + return DisplayPlanes(h->dpy, h->target_id); + +} /* NvCtrlGetScreenPlanes() */ + + + ReturnStatus NvCtrlQueryTargetCount(NvCtrlAttributeHandle *handle, int target_type, int *val) @@ -550,6 +707,26 @@ NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, } /* NvCtrlGetBinaryAttribute() */ +ReturnStatus +NvCtrlStringOperation(NvCtrlAttributeHandle *handle, + unsigned int display_mask, int attr, + char *ptrIn, char **ptrOut) +{ + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if ((attr >= 0) && (attr <= NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE)) { + if (!h->nv) return NvCtrlMissingExtension; + return NvCtrlNvControlStringOperation(h, display_mask, attr, ptrIn, + ptrOut); + } + + return NvCtrlNoAttribute; + +} /* NvCtrlStringOperation() */ + + char *NvCtrlAttributesStrError(ReturnStatus status) { switch (status) { @@ -610,3 +787,12 @@ NvCtrlXrandrSetScreenMode (NvCtrlAttributeHandle *handle, return NvCtrlXrandrSetScreenMagicMode ((NvCtrlAttributePrivateHandle *)handle, width, height, refresh); } /* NvCtrlXrandrSetScreenMode() */ + + +ReturnStatus +NvCtrlXrandrGetScreenMode (NvCtrlAttributeHandle *handle, + int *width, int *height, int *refresh) +{ + return NvCtrlXrandrGetScreenMagicMode + ((NvCtrlAttributePrivateHandle *)handle, width, height, refresh); +} /* NvCtrlXrandrGetScreenMode() */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.h b/src/libXNVCtrlAttributes/NvCtrlAttributes.h index 08f958d..3cdad09 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.h +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.h @@ -265,6 +265,14 @@ int NvCtrlGetScreenWidth(NvCtrlAttributeHandle *handle); int NvCtrlGetScreenHeight(NvCtrlAttributeHandle *handle); int NvCtrlGetEventBase(NvCtrlAttributeHandle *handle); int NvCtrlGetXrandrEventBase(NvCtrlAttributeHandle *handle); +char *NvCtrlGetServerVendor(NvCtrlAttributeHandle *handle); +int NvCtrlGetVendorRelease(NvCtrlAttributeHandle *handle); +int NvCtrlGetProtocolVersion(NvCtrlAttributeHandle *handle); +int NvCtrlGetProtocolRevision(NvCtrlAttributeHandle *handle); +int NvCtrlGetScreenCount(NvCtrlAttributeHandle *handle); +int NvCtrlGetScreenWidthMM(NvCtrlAttributeHandle *handle); +int NvCtrlGetScreenHeightMM(NvCtrlAttributeHandle *handle); +int NvCtrlGetScreenPlanes(NvCtrlAttributeHandle *handle); ReturnStatus NvCtrlGetColorAttributes (NvCtrlAttributeHandle *handle, float contrast[3], @@ -390,6 +398,18 @@ NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, unsigned char **data, int *len); /* + * NvCtrlStringOperation() - Performs the string operation associated + * with the specified attribute, where valid values are the + * NV_CTRL_STRING_OPERATION_* #defines in NVCtrl.h. If 'ptrOut' + * is specified, (string) result information is returned. + */ + +ReturnStatus +NvCtrlStringOperation(NvCtrlAttributeHandle *handle, + unsigned int display_mask, int attr, + char *ptrIn, char **ptrOut); + +/* * NvCtrl[SG]etGvoColorConversion() - get and set the color conversion * matrix and offset used in the Graphics to Video Out (GVO) * extension. These should only be used if the NV_CTRL_GVO_SUPPORTED @@ -416,4 +436,8 @@ ReturnStatus NvCtrlXrandrSetScreenMode (NvCtrlAttributeHandle *handle, int width, int height, int refresh); +ReturnStatus +NvCtrlXrandrGetScreenMode (NvCtrlAttributeHandle *handle, + int *width, int *height, int *refresh); + #endif /* __NVCTRL_ATTRIBUTES__ */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c b/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c index 08a40b6..9d99c39 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c @@ -137,6 +137,7 @@ static Bool open_libgl(void) if ( !__libGL ) { __libGL = (__libGLInfo *) calloc(1, sizeof(__libGLInfo)); if ( !__libGL ) { + error_str = "Could not allocate memory."; goto fail; } } @@ -152,6 +153,7 @@ static Bool open_libgl(void) /* We are the first to open the library */ __libGL->handle = dlopen("libGL.so.1", RTLD_LAZY); if ( !__libGL->handle ) { + error_str = dlerror(); goto fail; } diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c index 32177e8..e0929ac 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c @@ -174,7 +174,7 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *h, return NvCtrlNoAttribute; -} /* NvCtrlGetStringAttribute() */ +} /* NvCtrlNvControlGetStringAttribute() */ ReturnStatus @@ -235,6 +235,26 @@ NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, ReturnStatus +NvCtrlNvControlStringOperation(NvCtrlAttributePrivateHandle *h, + unsigned int display_mask, int attr, + char *ptrIn, char **ptrOut) +{ + if (attr <= NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE) { + if (XNVCTRLStringOperation (h->dpy, h->target_type, + h->target_id, display_mask, + attr, ptrIn, ptrOut)) { + return NvCtrlSuccess; + } else { + return NvCtrlAttributeNotAvailable; + } + } + + return NvCtrlNoAttribute; + +} /* NvCtrlNvControlStringOperation() */ + + +ReturnStatus NvCtrlSetGvoColorConversion(NvCtrlAttributeHandle *handle, float colorMatrix[3][3], float colorOffset[3], diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h index 314234d..43841e9 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h @@ -58,7 +58,7 @@ /* minimum required version for the NV-CONTROL extension */ #define NV_MINMAJOR 1 -#define NV_MINMINOR 9 +#define NV_MINMINOR 11 /* minimum required version for the XF86VidMode extension */ @@ -205,6 +205,10 @@ NvCtrlXrandrSetAttribute (NvCtrlAttributePrivateHandle *, int, int); ReturnStatus NvCtrlXrandrSetScreenMagicMode (NvCtrlAttributePrivateHandle *, int, int, int); +ReturnStatus +NvCtrlXrandrGetScreenMagicMode (NvCtrlAttributePrivateHandle *, int *, int *, + int *); + /* Generic attribute functions */ @@ -235,6 +239,12 @@ ReturnStatus NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, unsigned char **data, int *len); + +ReturnStatus +NvCtrlNvControlStringOperation (NvCtrlAttributePrivateHandle *h, + unsigned int display_mask, int attr, + char *ptrIn, char **ptrOut); + ReturnStatus NvCtrlXvGetAttribute (NvCtrlAttributePrivateHandle *, int, int *); diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c b/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c index 29b0412..60c3d78 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c @@ -42,17 +42,26 @@ #include "msg.h" #include "parse.h" +/* Make sure we are compiling with XRandR version 1.1 or greater */ +#define MIN_RANDR_MAJOR 1 +#define MIN_RANDR_MINOR 1 +#if (RANDR_MAJOR < MIN_RANDR_MAJOR) || ((RANDR_MAJOR == MIN_RANDR_MAJOR) && (RANDR_MINOR < MIN_RANDR_MINOR)) +#error XRandR version 1.1 or greater is required. +#endif typedef struct __libXrandrInfoRec { /* libXrandr.so library handle */ void *handle; int ref_count; /* # users of the library */ - - + + /* XRandR functions used */ Bool (* XRRQueryExtension) (Display *dpy, int *event_base, int *error_base); + + Status (* XRRQueryVersion) + (Display *dpy, int *major_versionp, int *minor_versionp); void (* XRRSelectInput) (Display *dpy, Window window, int mask); @@ -62,6 +71,9 @@ typedef struct __libXrandrInfoRec { SizeID (* XRRConfigCurrentConfiguration) (XRRScreenConfiguration *config, Rotation *rotation); + + short (* XRRConfigCurrentRate) + (XRRScreenConfiguration *config); Rotation (* XRRConfigRotations) (XRRScreenConfiguration *config, Rotation *rotation); @@ -104,6 +116,7 @@ static Bool open_libxrandr(void) if ( !__libXrandr ) { __libXrandr = (__libXrandrInfo *) calloc(1, sizeof(__libXrandrInfo)); if ( !__libXrandr ) { + error_str = "Could not allocate memory."; goto fail; } } @@ -118,6 +131,7 @@ static Bool open_libxrandr(void) /* We are the first to open the library */ __libXrandr->handle = dlopen("libXrandr.so.2", RTLD_LAZY); if ( !__libXrandr->handle ) { + error_str = dlerror(); goto fail; } @@ -127,6 +141,10 @@ static Bool open_libxrandr(void) NV_DLSYM(__libXrandr->handle, "XRRQueryExtension"); if ((error_str = dlerror()) != NULL) goto fail; + __libXrandr->XRRQueryVersion = + NV_DLSYM(__libXrandr->handle, "XRRQueryVersion"); + if ((error_str = dlerror()) != NULL) goto fail; + __libXrandr->XRRSelectInput = NV_DLSYM(__libXrandr->handle, "XRRSelectInput"); if ((error_str = dlerror()) != NULL) goto fail; @@ -139,6 +157,10 @@ static Bool open_libxrandr(void) NV_DLSYM(__libXrandr->handle, "XRRConfigCurrentConfiguration"); if ((error_str = dlerror()) != NULL) goto fail; + __libXrandr->XRRConfigCurrentRate = + NV_DLSYM(__libXrandr->handle, "XRRConfigCurrentRate"); + if ((error_str = dlerror()) != NULL) goto fail; + __libXrandr->XRRConfigRotations = NV_DLSYM(__libXrandr->handle, "XRRConfigRotations"); if ((error_str = dlerror()) != NULL) goto fail; @@ -249,6 +271,8 @@ NvCtrlInitXrandrAttributes (NvCtrlAttributePrivateHandle *h) NvCtrlXrandrAttributes * xrandr = NULL; XRRScreenConfiguration *sc; Rotation rotation, rotations; + int ver_major; + int ver_minor; /* Check parameters */ @@ -285,6 +309,15 @@ NvCtrlInitXrandrAttributes (NvCtrlAttributePrivateHandle *h) goto fail; } + /* Verify server version of the XRandR extension */ + if ( !__libXrandr->XRRQueryVersion(h->dpy, &(ver_major), &(ver_minor)) || + ((ver_major < MIN_RANDR_MAJOR) || + ((ver_major == MIN_RANDR_MAJOR) && + (ver_minor < MIN_RANDR_MINOR)))) { + XSync(h->dpy, False); + XSetErrorHandler(old_error_handler); + goto fail; + } /* Register to receive XRandR events */ __libXrandr->XRRSelectInput(h->dpy, RootWindow(h->dpy, h->target_id), @@ -564,3 +597,58 @@ NvCtrlXrandrSetScreenMagicMode (NvCtrlAttributePrivateHandle *h, return NvCtrlError; } /* NvCtrlXrandrSetScreenMagicMode */ + + + +/****************************************************************************** + * + * Gets XRandR size and refresh rate. + * + ****/ + +ReturnStatus +NvCtrlXrandrGetScreenMagicMode (NvCtrlAttributePrivateHandle *h, + int *width, int *height, int *magic_ref_rate) +{ + XRRScreenConfiguration *sc; + Rotation cur_rotation; + int nsizes; + XRRScreenSize *sizes; + int cur_size; + short cur_rate; + + + /* Validate */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { + return NvCtrlBadHandle; + } + + if ( !h->xrandr || !__libXrandr ) { + return NvCtrlMissingExtension; + } + + + /* Get current screen configuration information */ + sc = __libXrandr->XRRGetScreenInfo(h->dpy, RootWindow(h->dpy, + h->target_id)); + if ( !sc ) { + return NvCtrlError; + } + cur_size = __libXrandr->XRRConfigCurrentConfiguration(sc, &cur_rotation); + cur_rate = __libXrandr->XRRConfigCurrentRate(sc); + sizes = __libXrandr->XRRConfigSizes(sc, &nsizes); + if (cur_size >= nsizes) { + __libXrandr->XRRFreeScreenConfigInfo(sc); + return NvCtrlError; + } + + + /* Get the width & height from the size information */ + *width = sizes[cur_size].width; + *height = sizes[cur_size].height; + *magic_ref_rate = (int)cur_rate; + + __libXrandr->XRRFreeScreenConfigInfo(sc); + return NvCtrlSuccess; + +} /* NvCtrlXrandrGetScreenMagicMode */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c b/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c index 5d061d6..07ede41 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c @@ -79,6 +79,7 @@ static Bool open_libxv(void) if ( !__libXv ) { __libXv = (__libXvInfo *) calloc(1, sizeof(__libXvInfo)); if ( !__libXv ) { + error_str = "Could not allocate memory."; goto fail; } } @@ -94,6 +95,7 @@ static Bool open_libxv(void) /* We are the first to open the library */ __libXv->handle = dlopen("libXv.so.1", RTLD_LAZY); if ( __libXv->handle == NULL ) { + error_str = dlerror(); goto fail; } @@ -23,6 +23,7 @@ */ #include "msg.h" +#include "command-line.h" #include <stdio.h> #include <stdarg.h> @@ -35,6 +36,8 @@ #include <sys/termios.h> #endif +extern int __verbosity; + static void format(FILE*, const char*, char *); static int get_terminal_width(void); @@ -49,10 +52,14 @@ do { \ /* * nv_error_msg() - print an error message, nicely formatted using the * format() function. + * + * This function should be used for all errors. */ void nv_error_msg(const char *fmt, ...) { + if (__verbosity < VERBOSITY_ERROR) return; + fprintf(stderr, "\n"); NV_FORMAT(stderr, "ERROR: ", fmt); @@ -66,10 +73,14 @@ void nv_error_msg(const char *fmt, ...) /* * nv_warning_msg() - print a warning message, nicely formatted using * the format() function. + * + * This function should be used for all warnings. */ void nv_warning_msg(const char *fmt, ...) { + if (__verbosity < VERBOSITY_WARNING) return; + fprintf(stdout, "\n"); NV_FORMAT(stdout, "WARNING: ", fmt); @@ -81,8 +92,28 @@ void nv_warning_msg(const char *fmt, ...) /* + * nv_info_msg() - print an info message, nicely formatted using + * the format() function. + * + * This function should be used to display verbose information. + */ + +void nv_info_msg(const char *prefix, const char *fmt, ...) +{ + if (__verbosity < VERBOSITY_ALL) return; + + NV_FORMAT(stdout, prefix, fmt); + +} /* nv_info_msg() */ + + + +/* * nv_msg() - print a message, nicely formatted using the format() * function. + * + * This function should be used to display messages independent + * of the verbosity level. */ void nv_msg(const char *prefix, const char *fmt, ...) @@ -159,7 +190,7 @@ static void format(FILE *stream, const char *prefix, if (b <= a) { b = a; - while (!isspace(*b)) b++; + while (*b && !isspace(*b)) b++; } } @@ -30,6 +30,7 @@ void nv_error_msg(const char*, ...); void nv_warning_msg(const char*, ...); +void nv_info_msg(const char*, const char*, ...); void nv_msg(const char*, const char*, ...); /* diff --git a/src/nvidia-settings.c b/src/nvidia-settings.c index 79e6f75..7a9d2e9 100644 --- a/src/nvidia-settings.c +++ b/src/nvidia-settings.c @@ -39,9 +39,11 @@ int main(int argc, char **argv) ConfigProperties conf; ParsedAttribute *p; CtrlHandles *h; - NvCtrlAttributeHandle **handles; + NvCtrlAttributeHandle **screen_handles = NULL; + NvCtrlAttributeHandle **gpu_handles = NULL; + NvCtrlAttributeHandle **vcsc_handles = NULL; Options *op; - int ret, i, num_handles; + int ret, i, num_screen_handles, num_gpu_handles, num_vcsc_handles; /* * initialize the ui @@ -69,16 +71,24 @@ int main(int argc, char **argv) p = nv_parsed_attribute_init(); + /* initialize the ConfigProperties */ + + init_config_properties(&conf); + /* upload the data from the config file */ - ret = nv_read_config_file(op->config, op->ctrl_display, p, &conf); + if (!op->no_load) { + ret = nv_read_config_file(op->config, op->ctrl_display, p, &conf); + } else { + ret = 1; + } /* * if the user requested that we only load the config file, then * exit now */ - if (op->load) { + if (op->only_load) { return ret ? 0 : 1; } @@ -91,25 +101,58 @@ int main(int argc, char **argv) } /* - * pull the screens' handles out of the CtrlHandles so that we can + * pull the screen and gpu handles out of the CtrlHandles so that we can * pass them to the gui */ - num_handles = h->targets[X_SCREEN_TARGET].n; - - if (num_handles) { - handles = malloc(num_handles * sizeof(NvCtrlAttributeHandle *)); - - for (i = 0; i < num_handles; i++) { - handles[i] = h->targets[X_SCREEN_TARGET].t[i].h; + num_screen_handles = h->targets[X_SCREEN_TARGET].n; + + if (num_screen_handles) { + screen_handles = + malloc(num_screen_handles * sizeof(NvCtrlAttributeHandle *)); + if (screen_handles) { + for (i = 0; i < num_screen_handles; i++) { + screen_handles[i] = h->targets[X_SCREEN_TARGET].t[i].h; + } + } else { + num_screen_handles = 0; + } + } + + num_gpu_handles = h->targets[GPU_TARGET].n; + + if (num_gpu_handles) { + gpu_handles = + malloc(num_gpu_handles * sizeof(NvCtrlAttributeHandle *)); + if (gpu_handles) { + for (i = 0; i < num_gpu_handles; i++) { + gpu_handles[i] = h->targets[GPU_TARGET].t[i].h; + } + } else { + num_gpu_handles = 0; + } + } + + num_vcsc_handles = h->targets[VCSC_TARGET].n; + + if (num_vcsc_handles) { + vcsc_handles = + malloc(num_vcsc_handles * sizeof(NvCtrlAttributeHandle *)); + if (vcsc_handles) { + for (i = 0; i < num_vcsc_handles; i++) { + vcsc_handles[i] = h->targets[VCSC_TARGET].t[i].h; + } + } else { + num_vcsc_handles = 0; } - } else { - handles = NULL; } /* pass control to the gui */ - ctk_main(handles, num_handles, p, &conf); + ctk_main(screen_handles, num_screen_handles, + gpu_handles, num_gpu_handles, + vcsc_handles, num_vcsc_handles, + p, &conf); /* write the configuration file */ @@ -117,7 +160,8 @@ int main(int argc, char **argv) /* cleanup */ - if (handles) free(handles); + if (screen_handles) free(screen_handles); + if (gpu_handles) free(gpu_handles); nv_free_ctrl_handles(h); nv_parsed_attribute_free(p); diff --git a/src/parse.c b/src/parse.c index d681736..121279b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -59,7 +59,7 @@ static char *nv_strndup(char *s, int n); #define D NV_PARSER_TYPE_VALUE_IS_DISPLAY #define A NV_PARSER_TYPE_NO_QUERY_ALL #define Z NV_PARSER_TYPE_NO_ZERO_VALUE - +#define H NV_PARSER_TYPE_100Hz AttributeTableEntry attributeTable[] = { @@ -87,6 +87,7 @@ AttributeTableEntry attributeTable[] = { { "TwinView", NV_CTRL_TWINVIEW, 0 }, { "ConnectedDisplays", NV_CTRL_CONNECTED_DISPLAYS, 0 }, { "EnabledDisplays", NV_CTRL_ENABLED_DISPLAYS, 0 }, + { "AssociatedDisplays", NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, N|D }, { "ProbeDisplays", NV_CTRL_PROBE_DISPLAYS, A }, { "ForceGenericCpu", NV_CTRL_FORCE_GENERIC_CPU, 0 }, { "GammaCorrectedAALines", NV_CTRL_OPENGL_AA_LINE_GAMMA, 0 }, @@ -100,7 +101,13 @@ AttributeTableEntry attributeTable[] = { { "CursorShadowBlue", NV_CTRL_CURSOR_SHADOW_BLUE, 0 }, { "FSAAAppControlled", NV_CTRL_FSAA_APPLICATION_CONTROLLED, 0 }, { "LogAnisoAppControlled", NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED,0 }, - { "RefreshRate", NV_CTRL_REFRESH_RATE, 0 }, + { "RefreshRate", NV_CTRL_REFRESH_RATE, N|H }, + { "InitialPixmapPlacement",NV_CTRL_INITIAL_PIXMAP_PLACEMENT, N }, + { "PCIBus", NV_CTRL_PCI_BUS, N }, + { "PCIDevice", NV_CTRL_PCI_DEVICE, N }, + { "PCIFunc", NV_CTRL_PCI_FUNCTION, N }, + { "DynamicTwinview", NV_CTRL_DYNAMIC_TWINVIEW, N }, + { "MultiGpuDisplayOwner", NV_CTRL_MULTIGPU_DISPLAY_OWNER, N }, { "FrameLockMaster", NV_CTRL_FRAMELOCK_MASTER, N|F|G|D }, { "FrameLockSlaves", NV_CTRL_FRAMELOCK_SLAVES, N|F|G|D }, @@ -121,6 +128,7 @@ AttributeTableEntry attributeTable[] = { { "FrameLockSyncRate", NV_CTRL_FRAMELOCK_SYNC_RATE, N|F|G }, { "FrameLockTiming", NV_CTRL_FRAMELOCK_TIMING, N|F|G }, { "FrameLockMasterable", NV_CTRL_FRAMELOCK_MASTERABLE, N|F|G }, + { "FrameLockFPGARevision", NV_CTRL_FRAMELOCK_FPGA_REVISION, N|F|G }, { "Brightness", BRIGHTNESS_VALUE|ALL_CHANNELS, N|C|G }, { "RedBrightness", BRIGHTNESS_VALUE|RED_CHANNEL, C|G }, @@ -170,7 +178,8 @@ AttributeTableEntry attributeTable[] = { #undef P #undef D #undef A - +#undef Z +#undef H /* * When new integer attributes are added to NVCtrl.h, an entry should @@ -179,7 +188,7 @@ AttributeTableEntry attributeTable[] = { * about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_REFRESH_RATE +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_MULTIGPU_DISPLAY_OWNER #warning "Have you forgotten to add a new integer attribute to attributeTable?" #endif @@ -212,7 +221,14 @@ TargetTypeEntry targetTypeTable[] = { NV_CTRL_TARGET_TYPE_FRAMELOCK, /* nvctrl */ ATTRIBUTE_TYPE_FRAMELOCK, /* permission_bit */ NV_FALSE }, /* uses_display_devices */ - + + { "VCSC", /* name */ + "vcsc", /* parsed_name */ + VCSC_TARGET, /* target_index */ + NV_CTRL_TARGET_TYPE_VCSC, /* nvctrl */ + ATTRIBUTE_TYPE_VCSC, /* permission_bit */ + NV_FALSE }, /* uses_display_devices */ + { NULL, NULL, 0, 0, 0 }, }; @@ -330,7 +346,7 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a) a->val |= strtol((tmp + 1), &tmp, 10) & 0xffff; } else { /* all other attributes are integer */ - a->val = strtol(s, &tmp, 10); + a->val = strtol(s, &tmp, 0); } if (tmp && (s != tmp)) a->flags |= NV_PARSER_HAS_VAL; diff --git a/src/parse.h b/src/parse.h index d12c7b6..99b420c 100644 --- a/src/parse.h +++ b/src/parse.h @@ -52,6 +52,7 @@ #define NV_PARSER_TYPE_VALUE_IS_DISPLAY (1<<22) #define NV_PARSER_TYPE_NO_QUERY_ALL (1<<23) #define NV_PARSER_TYPE_NO_ZERO_VALUE (1<<24) +#define NV_PARSER_TYPE_100Hz (1<<25) #define NV_PARSER_ASSIGNMENT 0 #define NV_PARSER_QUERY 1 @@ -138,7 +139,8 @@ extern AttributeTableEntry attributeTable[]; #define X_SCREEN_TARGET 0 #define GPU_TARGET 1 #define FRAMELOCK_TARGET 2 -#define MAX_TARGET_TYPES 3 +#define VCSC_TARGET 3 +#define MAX_TARGET_TYPES 4 diff --git a/src/query-assign.c b/src/query-assign.c index 2ff1de4..1784486 100644 --- a/src/query-assign.c +++ b/src/query-assign.c @@ -356,6 +356,11 @@ static int process_attribute_queries(int num, char **queries, continue; } + if (nv_strcasecmp(queries[query], "vcscs")) { + query_all_targets(display_name, VCSC_TARGET); + continue; + } + /* call the parser to parse queries[query] */ @@ -673,7 +678,7 @@ static void print_valid_values(char *name, uint32 flags, if (n == 0) sprintf(c, "None"); - nv_msg(INDENT, "'%s' can use the following target types: %s", + nv_msg(INDENT, "'%s' can use the following target types: %s.", name, str); #undef INDENT @@ -683,6 +688,52 @@ static void print_valid_values(char *name, uint32 flags, /* + * print_queried_value() - print the attribute value that we queried + * from NV-CONTROL + */ + +static void print_queried_value(CtrlHandleTarget *t, + NVCTRLAttributeValidValuesRec *v, + int val, + uint32 flags, + char *name, + uint32 mask, + const char *indent) +{ + char d_str[64], val_str[64], *tmp_d_str; + + /* assign val_str */ + + if (flags & NV_PARSER_TYPE_100Hz) { + snprintf(val_str, 64, "%.2f Hz", ((float) val) / 100.0); + } else if (v->type == ATTRIBUTE_TYPE_BITMASK) { + snprintf(val_str, 64, "0x%08x", val); + } else if (flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { + snprintf(val_str, 64, "%d,%d", val >> 16, val & 0xffff); + } else { + snprintf(val_str, 64, "%d", val); + } + + /* append the display device name, if necessary */ + + if (v->permissions & ATTRIBUTE_TYPE_DISPLAY) { + tmp_d_str = display_device_mask_to_display_device_name(mask); + snprintf(d_str, 64, "; display device: %s", tmp_d_str); + free(tmp_d_str); + } else { + d_str[0] = '\0'; + } + + /* print the string */ + + nv_msg(indent, "Attribute '%s' (%s%s): %s.", + name, t->name, d_str, val_str); + +} /* print_queried_value() */ + + + +/* * query_all() - loop through all screens, and query all attributes * for those screens. The current attribute values for all display * devices on all screens are printed, along with the valid values for @@ -698,24 +749,9 @@ static int query_all(const char *display_name) uint32 mask; ReturnStatus status; AttributeTableEntry *a; - char *tmp_d_str; - const char *fmt, *fmt_display; NVCTRLAttributeValidValuesRec valid; CtrlHandles *h; CtrlHandleTarget *t; - - static const char *__fmt_str_int = - "Attribute '%s' (screen: %s): %d."; - static const char *__fmt_str_int_display = - "Attribute '%s' (screen: %s; display: %s): %d."; - static const char *__fmt_str_hex = - "Attribute '%s' (screen: %s): 0x%08x."; - static const char *__fmt_str_hex_display = - "Attribute '%s' (screen: %s; display: %s): 0x%08x."; - static const char *__fmt_str_packed_int = - "Attribute '%s' (screen: %s): %d,%d."; - static const char *__fmt_str_packed_int_display = - "Attribute '%s' (screen: %s; display: %s): %d,%d."; h = nv_alloc_ctrl_handles(display_name); @@ -777,55 +813,20 @@ static int query_all(const char *display_name) NvCtrlAttributesStrError(status)); goto exit_bit_loop; } - - if (valid.type == ATTRIBUTE_TYPE_BITMASK) { - fmt = __fmt_str_hex; - fmt_display = __fmt_str_hex_display; - } else if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { - fmt = __fmt_str_packed_int; - fmt_display = __fmt_str_packed_int_display; - } else { - fmt = __fmt_str_int; - fmt_display = __fmt_str_int_display; - } + print_queried_value(t, &valid, val, a->flags, + a->name, mask, INDENT); + + print_valid_values(a->name, a->flags, valid); + + nv_msg(NULL,""); + if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) { - - tmp_d_str = - display_device_mask_to_display_device_name(mask); - - if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { - nv_msg(INDENT, fmt_display, a->name, - t->name, tmp_d_str, - val >> 16, val & 0xffff); - } else { - nv_msg(INDENT, fmt_display, a->name, - t->name, tmp_d_str, val); - } - - free(tmp_d_str); - - print_valid_values(a->name, a->flags, valid); - - nv_msg(NULL,""); - continue; - - } else { - if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { - nv_msg(INDENT, fmt, a->name, t->name, - val >> 16, val & 0xffff); - } else { - nv_msg(INDENT, fmt, a->name, t->name, val); - } - - print_valid_values(a->name, a->flags, valid); - - nv_msg(NULL,""); - - /* fall through to exit_bit_loop */ } + /* fall through to exit_bit_loop */ + exit_bit_loop: bit = 25; /* XXX force us out of the display device loop */ @@ -918,6 +919,13 @@ static int query_all_targets(const char *display_name, const int target_index) product_name = malloc(32); snprintf(product_name, 32, "G-Sync %d", i); + } else if (target_index == VCSC_TARGET) { + + status = NvCtrlGetStringAttribute + (t->h, NV_CTRL_STRING_VCSC_PRODUCT_NAME, &product_name); + + if (status != NvCtrlSuccess) product_name = strdup("Unknown"); + } else { /* for X_SCREEN_TARGET or GPU_TARGET, query the product name */ @@ -1023,14 +1031,9 @@ static int process_parsed_attribute_internal(CtrlHandleTarget *t, NvCtrlAttributesStrError(status)); return NV_FALSE; } else { - if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { - nv_msg(" ", "Attribute '%s' (%s%s): %d,%d.", - a->name, t->name, str, - a->val >> 16, a->val & 0xffff); - } else { - nv_msg(" ", "Attribute '%s' (%s%s): %d.", - a->name, t->name, str, a->val); - } + + print_queried_value(t, &valid, a->val, a->flags, a->name, d, " "); + print_valid_values(a->name, a->flags, valid); } } diff --git a/src/xpm_data/Makefile.inc b/src/xpm_data/Makefile.inc index d50561d..3221772 100644 --- a/src/xpm_data/Makefile.inc +++ b/src/xpm_data/Makefile.inc @@ -26,10 +26,11 @@ # EXTRA_DIST += \ + Makefile.inc \ blue_xpm.h \ green_xpm.h \ - mini_xpm.h \ red_xpm.h \ - rgb_xpm.h \ - x11_xpm.h + rgb_xpm.h +dist_list:: + @ echo $(SRC) $(EXTRA_DIST) diff --git a/src/xpm_data/mini_xpm.h b/src/xpm_data/mini_xpm.h deleted file mode 100644 index c834b98..0000000 --- a/src/xpm_data/mini_xpm.h +++ /dev/null @@ -1,26 +0,0 @@ -/* XPM */ -static const char * mini_xpm[] = { -"16 14 9 1", -" c None", -". c #FFFFFF", -"+ c #848201", -"@ c #000000", -"# c #C0BDC0", -"$ c #848284", -"% c #CECBC6", -"& c #B9E313", -"* c #D6CFC6", -"......+++++++++@", -"......+++++++++@", -"...#$@.%#++++++@", -"..$$#.++..+++++@", -".@$.$@..+&.#+++@", -"$@.@$.+.&+.&+++@", -"$@.@$.+++.*++++@", -".@$#@#+%.&+%..+@", -".#@$#@*&++..#++@", -"..#@$#++..%++++@", -"....$$..#++++++@", -"......+++++++++@", -"......+++++++++@", -"$$$$$$@@@@@@@@@@"}; diff --git a/src/xpm_data/x11_xpm.h b/src/xpm_data/x11_xpm.h deleted file mode 100644 index 4eb3862..0000000 --- a/src/xpm_data/x11_xpm.h +++ /dev/null @@ -1,67 +0,0 @@ -/* XPM */ -static const char * x11_xpm[] = { -"14 14 50 1", -" c None", -". c #5E5E5E", -"+ c #000000", -"@ c #2C2C2C", -"# c #F4F4F4", -"$ c #FFFFFF", -"% c #787878", -"& c #454545", -"* c #2B2B2B", -"= c #616161", -"- c #AAAAAA", -"; c #232323", -"> c #EFEFEF", -", c #D5D5D5", -"' c #0B0B0B", -") c #9F9F9F", -"! c #D3D3D3", -"~ c #191919", -"{ c #D0D0D0", -"] c #A0A0A0", -"^ c #0A0A0A", -"/ c #D4D4D4", -"( c #A2A2A2", -"_ c #FEFEFE", -": c #F3F3F3", -"< c #515151", -"[ c #6C6C6C", -"} c #F2F2F2", -"| c #6A6A6A", -"1 c #818181", -"2 c #414141", -"3 c #FAFAFA", -"4 c #090909", -"5 c #666666", -"6 c #1F1F1F", -"7 c #E3E3E3", -"8 c #3B3B3B", -"9 c #5C5C5C", -"0 c #0F0F0F", -"a c #7A7A7A", -"b c #444444", -"c c #777777", -"d c #ABABAB", -"e c #EEEEEE", -"f c #CFCFCF", -"g c #A1A1A1", -"h c #535353", -"i c #6B6B6B", -"j c #828282", -"k c #404040", -".++@#$$$$$$$%&", -"#*++=$$$$$$-;>", -"$,'++)$$$$!~{$", -"$$]++^/$$>*($$", -"$$_=++@:_<[$$$", -"$$$}*++|123$$$", -"$$$$,4+567$$$$", -"$$$$38904,$$$$", -"$$$$abc++*}$$$", -"$$$d;e:@++=_$$", -"$$/~f$$/^++]$$", -"$>@g$$$$)++',$", -"_hi$$$$$$=++*#", -"jk3$$$$$$#@++."}; |