diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:55 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:55 -0800 |
commit | 9cec52adf6e908620eeb819927b7395734e47f09 (patch) | |
tree | b44fae751b5b6b4e4d21ed8f4dd54effbb2aa378 | |
parent | 03dfb75016524ca18b3cf5cc71a60163150983d7 (diff) |
1.0-87561.0-8756
71 files changed, 11969 insertions, 4406 deletions
@@ -50,10 +50,6 @@ ifndef CC CC = gcc endif -ifndef CFLAGS - CFLAGS = -Wall -endif - ifndef PKG_CONFIG PKG_CONFIG = pkg-config endif @@ -70,16 +66,20 @@ ifndef X11R6_INC_DIR X11R6_INC_DIR = /usr/X11R6/include endif +# define local variables + +LOCAL_CFLAGS = -Wall + # the NVDEBUG environment variable controls whether we build debug or retail ifeq ($(NVDEBUG),1) STRIP = true - CFLAGS += -g -DDEBUG + LOCAL_CFLAGS += -g -DDEBUG else ifndef STRIP STRIP = strip endif - CFLAGS += -O + LOCAL_CFLAGS += -O -DNDEBUG endif # default prefix @@ -137,7 +137,7 @@ SRCDIRS := $(addprefix $(CURDIR)/, $(RELATIVE_SRCDIRS)) INC_FLAGS := $(addprefix -I , $(RELATIVE_SRCDIRS)) -ALL_CFLAGS = $(CFLAGS) $(X11R6_CFLAGS) $(GTK_CFLAGS) $(INC_FLAGS) +ALL_CFLAGS = $(CFLAGS) $(LOCAL_CFLAGS) $(X11R6_CFLAGS) $(GTK_CFLAGS) $(INC_FLAGS) ALL_LDFLAGS = $(LD_RUN_FLAG) $(LDFLAGS) $(GTK_LDFLAGS) $(X11R6_LIBS) CPPFLAGS = $(ALL_CFLAGS) @@ -156,8 +156,16 @@ MANPAGE = nvidia-settings.1 # Define the files in the SAMPLES directory -SAMPLES = Makefile README nv-control-dvc.c nv-control-info.c \ - nv-control-events.c nv-ddcci-client.c +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 diff --git a/doc/nvidia-settings.1.m4 b/doc/nvidia-settings.1.m4 index d5d6cdd..12fbe09 100644 --- a/doc/nvidia-settings.1.m4 +++ b/doc/nvidia-settings.1.m4 @@ -1,7 +1,7 @@ changequote([[[, ]]])dnl dnl Solaris man chokes on three-letter macros. ifelse(__BUILD_OS__,SunOS,[[[define(__URL__,UR)]]],[[[define(__URL__,URL)]]])dnl -.\" Copyright (C) 2005 NVIDIA Corporation. +.\" Copyright (C) 2006 NVIDIA Corporation. __HEADER__ .\" Define the .__URL__ macro and then override it with the www.tmac package if it .\" exists. @@ -9,7 +9,7 @@ __HEADER__ \\$2 \(la \\$1 \(ra\\$3 .. .if \n[.g] .mso www.tmac -.TH nvidia-settings 1 2005-12-01 "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 @@ -92,13 +92,43 @@ This assigns the attribute {attribute name} to the value {value} on the X Displa option. If the X screen is not specified, then the assignment is made to all X screens. Note that the '/' is only required when {DISPLAY} is present. +.sp +.br +{DISPLAY} can additionally include a target specification to direct an assignment to something other than an X screen. +A target specification is contained within brackets and consists of a target type name, a colon, and the target id. +The target type name can be one of +.B screen, +.B gpu, +or +.B framelock; +the target id is the index into the list of targets (for that target type). +The target specification can be used in {DISPLAY} wherever an X screen can be used, following the syntax {host}:{display}[{target_type}:{target_id}]. +See the output of +.nf + + nvidia-settings --query all + +.fi +for information on which target types can be used with which attributes. +See the output of +.nf + + nvidia-settings -q screens -q gpus -q framelocks + +.fi +for lists of targets for each target type. +.br +.sp The [{display devices}] portion is also optional; if it is not specified, then the attribute is assigned to all display devices. +.br +.sp Some examples: .nf -a FSAA=5 -a localhost:0.0/DigitalVibrance[CRT-0]=0 --assign="SyncToVBlank=1" + -a [gpu:0]/DigitalVibrance[DFP-1]=63 .fi .TP @@ -114,12 +144,18 @@ commandline option is of the form: .fi This queries the current value of the attribute {attribute name} on the X Display {DISPLAY}. -The format is the same as that for the +The syntax is the same as that for the .B \-\-assign option, without .B ={value}. Specify -.B \-q all' +.B \-q screens, +.B \-q gpus, +or +.B \-q framelocks +to query a list of X screens, GPUs, or Frame Lock devices, respectively, that are present on the X Display {DISPLAY}. +Specify +.B \-q all to query all attributes. .TP .B \-g, \-\-glxinfo @@ -288,14 +324,14 @@ option can be used to query the current value of attributes. This will also report the valid values for the attribute. You can run .B nvidia\-settings \-\-query all -for a complete list of available attributes, what the current value is, and what values are valid for the attribute. +for a complete list of available attributes, what the current value is, what values are valid for the attribute, and through which target types (e.g., X screens, GPUs) the attributes can be addressed. Additionally, individual attributes may be specified like this: .nf nvidia-settings --query CursorShadow .fi -Attributes that may differ per display device (for example DigitalVibrance can be set independently on each display device when in TwinView) can be appended with a "display device name" within brackets; e.g.: +Attributes that may differ per display device (for example, DigitalVibrance can be set independently on each display device when in TwinView) can be appended with a "display device name" within brackets; e.g.: .nf nvidia-settings --query DigitalVibrance[CRT-0] @@ -307,7 +343,7 @@ An attribute name may be prepended with an X Display name and a forward slash to indicate a different X Display; e.g.: .nf - nvidia-settings --query 192.168.1.33:0.0/DigitalVibrance[DFP-1] + nvidia-settings --query localhost:0.0/DigitalVibrance[DFP-1] .fi An attribute name may also just be prepended with the screen number and a forward slash: @@ -319,6 +355,53 @@ An attribute name may also just be prepended with the screen number and a forwar in which case the default X Display will be used, but you can indicate to which X screen to direct the query (if your X server has multiple X screens). If no X screen is specified, then the attribute value will be queried for all X screens. .PP +Attributes can be addressed through "target types". +A target type indicates the object that is queried when you query an attribute. +The default target type is an X screen, but other possible target types are GPUs and Frame Lock devices. +.PP +Target types give you different granularities with which to perform queries and assignments. +Since X screens can span multiple GPUs (in the case of Xinerama, or SLI), and multiple X screens can exist on the same GPU, it is sometimes useful to address attributes by GPU rather than X screen. +.PP +A target specification is contained within brackets and consists of a target type name, a colon, and the target id. +The target type name can be one of +.B screen, +.B gpu, +or +.B framelock; +the target id is the index into the list of targets (for that target type). +Target specifications can be used wherever an X screen is used in query and assignment commands; the target specification can be used either by itself on the left side of the forward slash, or as part of an X Display name. +.PP +For example, the following queries address X screen 0 on the localhost: +.nf + + nvidia-settings --query 0/VideoRam + nvidia-settings --query localhost:0.0/VideoRam + nvidia-settings --query [screen:0]/VideoRam + nvidia-settings --query localhost:0[screen:0]/VideoRam + +.fi +To address GPU 0 instead, you can use either of: +.nf + + nvidia-settings --query [gpu:0]/VideoRam + nvidia-settings --query localhost:0[gpu:0]/VideoRam + +.fi +See the output of +.nf + + nvidia-settings --query all + +.fi +for what targets types can be used with each attribute. +See the output of +.nf + + nvidia-settings --query screens --query gpus --query framelocks + +.fi +for lists of targets for each target type. +.PP The .B \-\-assign option can be used to assign a new value to an attribute. @@ -333,7 +416,7 @@ For example: nvidia-settings --assign FSAA=2 nvidia-settings --assign 0/DigitalVibrance[CRT-1]=9 - + nvidia-settings --assign [gpu:0]/DigitalVibrance=0 .fi .PP Multiple queries and assignments may be specified on the commandline for a single invocation of @@ -509,4 +592,4 @@ NVIDIA Corporation .BR nvidia\-xconfig (1)ifelse(__BUILD_OS__,Linux,[[[, .BR nvidia\-installer (1)]]]) .SH COPYRIGHT -Copyright \(co 2005 NVIDIA Corporation. +Copyright \(co 2006 NVIDIA Corporation. diff --git a/samples/Makefile b/samples/Makefile index 544d634..471a715 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -42,7 +42,7 @@ ifndef CC endif ifndef CFLAGS - CFLAGS = -Wall -fpedantic + CFLAGS = -Wall endif ifndef LDFLAGS @@ -68,7 +68,14 @@ ALL_CFLAGS = $(CFLAGS) -I $(LIBXNVCTRL_DIR) -I $(X11R6_INC_DIR) ALL_LDFLAGS = $(LDFLAGS) -L $(LIBXNVCTRL_DIR) -L $(X11R6_LIB_DIR) \ -lXNVCtrl -lXext -lX11 -SAMPLES = nv-control-info nv-control-dvc nv-control-events nv-ddcci-client +SAMPLES = \ + nv-control-info \ + nv-control-dvc \ + nv-control-events \ + nv-ddcci-client \ + nv-control-dpy \ + nv-control-targets \ + nv-control-framelock all: $(SAMPLES) diff --git a/samples/README b/samples/README index 3992ba8..a984aeb 100644 --- a/samples/README +++ b/samples/README @@ -20,8 +20,19 @@ Sample applications: shows how to handle multiple display devices. nv-control-events: demonstrates how to register to receive and - interpret NV-CONTROL events. - + interpret NV-CONTROL events. nv-ddcci-client: demonstrates how to use the implementation of the DDC/CI interface with the NV-CONTROL X extension. + + nv-control-dpy: demonstrates how to configure display devices + using the NV-CONTROL X extension. + + nv-control-targets: demonstrates how to query various attributes + from varying target types (GPUs, X Screens, + Frame Lock Boards) using the XNVCTRL target + functions. + + nv-control-framelock: demonstrates how to query frame lock related + attributes. Also demonstrates how to enable/ + disable frame lock. diff --git a/samples/nv-control-dpy.c b/samples/nv-control-dpy.c new file mode 100644 index 0000000..b37bfe7 --- /dev/null +++ b/samples/nv-control-dpy.c @@ -0,0 +1,389 @@ +/* + * 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 + * + */ + + +/* + * nv-control-dpy.c - NV-CONTROL client that demonstrates how to + * configure display devices using NV-CONTROL. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <X11/Xlib.h> + +#include "NVCtrl.h" +#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() */ + + + + +int main(int argc, char *argv[]) +{ + Display *dpy; + Bool ret; + int screen, display_devices, mask, major, minor, len, j; + char *str, *start; + 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. + */ + + dpy = XOpenDisplay(NULL); + if (!dpy) { + fprintf(stderr, "Cannot open display '%s'.\n", XDisplayName(NULL)); + return 1; + } + + screen = DefaultScreen(dpy); + + if (!XNVCTRLIsNvScreen(dpy, screen)) { + fprintf(stderr, "The NV-CONTROL X not available on screen " + "%d of '%s'.\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)); + return 1; + } + + ret = XNVCTRLQueryAttribute(dpy, screen, 0, + NV_CTRL_ENABLED_DISPLAYS, &display_devices); + + if (!ret) { + fprintf(stderr, "Failed to query the enabled Display Devices.\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"); + + 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); + + displayDeviceNames[nDisplayDevice++] = str; + + printf(" %s (0x%08x): %s\n", + display_device_name(mask), mask, str); + } + } + + printf("\n"); + + /* now, parse the commandline and perform the requested action */ + + + if (argc <= 1) goto printHelp; + + if (strcmp(argv[1], "-l") == 0) { + + /* get list of modelines, per display device */ + + 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); + + 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]; + } + } + + XFree(str); + } + } + + } else if (strcmp(argv[1], "-m") == 0) { + + /* get list of metamodes */ + + XNVCTRLQueryBinaryData(dpy, screen, 0, // n/a + NV_CTRL_BINARY_DATA_METAMODES, + (void *) &str, &len); + + printf("MetaModes:\n"); + + start = str; + for (j = 0; j < len; j++) { + if (str[j] == '\0') { + printf(" %s\n", start); + start = &str[j+1]; + } + } + + XFree(str); + + } else if ((strcmp(argv[1], "-M") == 0) && (argv[2])) { + + ret = XNVCTRLSetStringAttribute(dpy, + screen, + 0, + NV_CTRL_STRING_ADD_METAMODE, + argv[2]); + + if (!ret) { + fprintf(stderr, "Failed to add the MetaMode.\n"); + return 1; + } + + printf("Uploaded MetaMode \"%s\"; magicID: %d\n", + argv[2], ret); + + } else if ((strcmp(argv[1], "-D") == 0) && (argv[1])) { + + ret = XNVCTRLSetStringAttribute(dpy, + screen, + 0, + NV_CTRL_STRING_DELETE_METAMODE, + argv[2]); + + if (!ret) { + fprintf(stderr, "Failed to delete the MetaMode.\n"); + return 1; + } + + } else if (strcmp(argv[1], "-c") == 0) { + + ret = XNVCTRLQueryStringAttribute + (dpy, screen, mask, + NV_CTRL_STRING_CURRENT_METAMODE, + &str); + + if (!ret) { + fprintf(stderr, "Failed to query the current MetaMode.\n"); + return 1; + } + + printf("current metamode: \"%s\"\n", str); + + } else if ((strcmp(argv[1], "-L") == 0) && argv[2] && argv[3]) { + + ret = XNVCTRLSetStringAttribute(dpy, + screen, + strtol(argv[2], NULL, 0), + NV_CTRL_STRING_ADD_MODELINE, + argv[3]); + + if (!ret) { + fprintf(stderr, "Failed to add the modeline \"%s\".\n", argv[3]); + 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]); + + if (!ret) { + fprintf(stderr, "Failed to delete the mode \"%s\".\n", argv[3]); + return 1; + } + + } else if (strcmp(argv[1], "-g") == 0) { + + int num_gpus, num_screens, i; + unsigned int *pData; + + printf("GPU Information:\n"); + + /* 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"); + 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, + i, // target_id + 0, + 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); + + for (j = 1; j <= pData[0]; j++) { + printf(" %d", pData[j]); + } + printf("\n"); + } + + + /* Get the number of X Screens in the system + * + * NOTE: If Xinerama is enabled, ScreenCount(dpy) will return 1, + * 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"); + 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); + + for (i = 0; i < num_screens; i++) { + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + i, // target_id + 0, + NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, + (unsigned char **) &pData, + &len); + if (!ret) { + fprintf(stderr, "Failed to query list of gpus\n"); + return 1; + } + + 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); + for (j = 1; j <= pData[0]; j++) { + printf(" %d", pData[j]); + } + printf("\n"); + } + + printf("\n"); + + } else { + + printHelp: + + 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"); + } + + return 0; + +} diff --git a/samples/nv-control-events.c b/samples/nv-control-events.c index 884c9c0..a709220 100644 --- a/samples/nv-control-events.c +++ b/samples/nv-control-events.c @@ -35,14 +35,18 @@ #include "NVCtrlLib.h" static const char *attr2str(int n); +static const char *target2str(int n); int main(void) { Display *dpy; Bool ret; - int event_base, error_base, screen; + int event_base, error_base; + int num_screens, num_gpus, num_framelocks, i; + int sources; XEvent event; XNVCtrlAttributeChangedEvent *nvevent; + XNVCtrlAttributeChangedEventTarget *nveventtarget; /* * Open a display connection, and make sure the NV-CONTROL X @@ -55,14 +59,6 @@ int main(void) return 1; } - screen = DefaultScreen(dpy); - - if (!XNVCTRLIsNvScreen(dpy, screen)) { - fprintf(stderr, "The NV-CONTROL X not available on screen " - "%d of '%s'.\n", screen, XDisplayName(NULL)); - return 1; - } - /* * check if the NV-CONTROL X extension is present on this X server */ @@ -74,19 +70,163 @@ int main(void) return 1; } + /* Query number of X Screens */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + &num_screens); + if (ret != True) { + fprintf(stderr, "Failed to query the number of X Screens on '%s'.\n", + XDisplayName(NULL)); + return 1; + } + + /* Query number of GPUs */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_GPU, + &num_gpus); + if (ret != True) { + fprintf(stderr, "Failed to query the number of GPUs on '%s'.\n", + XDisplayName(NULL)); + return 1; + } + + /* Query number of Frame Lock (G-Sync) devices */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, + &num_framelocks); + if (ret != True) { + fprintf(stderr, "Failed to query the number of G-Sync 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 * can receive notification of the change. */ - ret = XNVCtrlSelectNotify(dpy, screen, ATTRIBUTE_CHANGED_EVENT, True); - if (ret != True) { - fprintf(stderr, "Unable to register to receive NV-CONTROL events " - "on '%s'.\n", XDisplayName(NULL)); - return 1; + sources = 0; + + /* + * - Register to receive ATTRIBUTE_CHANGE_EVENT events. These events + * are specific to attributes set on X Screens. + */ + + printf("Registering to receive ATTRIBUTE_CHANGED_EVENT events...\n"); + fflush(stdout); + + for (i = 0; i < num_screens; i++ ) { + + /* Only register to receive events if this screen is controlled by + * the NVIDIA driver. + */ + if (!XNVCTRLIsNvScreen(dpy, i)) { + printf("- The NV-CONTROL X not available on screen " + "%d of '%s'.\n", i, XDisplayName(NULL)); + continue; + } + + ret = XNVCtrlSelectNotify(dpy, i, ATTRIBUTE_CHANGED_EVENT, True); + if (ret != True) { + printf("- Unable to register to receive NV-CONTROL events on '%s'." + "\n", XDisplayName(NULL)); + continue; + } + + printf("+ Listening to ATTRIBUTE_CHANGE_EVENTs on screen %d.\n", i); + sources++; + } + printf("\n"); + + /* + * - Register to receive TARGET_ATTRIBUTE_CHANGED_EVENT events. These + * events are specific to attributes set on various devices and + * structures controlled by the NVIDIA driver. Some possible targets + * include X Screens, GPUs, and Frame Lock boards. + */ + + printf("Registering to receive TARGET_ATTRIBUTE_CHANGED_EVENT " + "events...\n"); + fflush(stdout); + + /* Register to receive on all X Screen targets */ + + for (i = 0; i < num_screens; i++ ) { + + /* Only register to receive events if this screen is controlled by + * the NVIDIA driver. + */ + if (!XNVCTRLIsNvScreen(dpy, i)) { + printf("- The NV-CONTROL X not available on screen " + "%d of '%s'.\n", i, XDisplayName(NULL)); + continue; + } + + ret = XNVCtrlSelectTargetNotify(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + i, TARGET_ATTRIBUTE_CHANGED_EVENT, + True); + if (ret != True) { + printf("- Unable to register to receive NV-CONTROL X Screen " + "target events for screen %d on '%s'.\n", + i, XDisplayName(NULL)); + continue; + } + + printf("+ Listening to TARGET_ATTRIBUTE_CHANGE_EVENTs on X Screen " + "%d.\n", i); + sources++; } + /* Register to receive on all GPU targets */ + + for (i = 0; i < num_gpus; i++ ) { + + ret = XNVCtrlSelectTargetNotify(dpy, NV_CTRL_TARGET_TYPE_GPU, + i, TARGET_ATTRIBUTE_CHANGED_EVENT, + True); + if (ret != True) { + printf("- Unable to register to receive NV-CONTROL GPU " + "target events for GPU %d on '%s'.\n", + i, XDisplayName(NULL)); + continue; + } + + printf("+ Listening to TARGET_ATTRIBUTE_CHANGE_EVENTs on GPU " + "%d.\n", i); + sources++; + } + + /* Register to receive on all Frame Lock (G-Sync) targets */ + + for (i = 0; i < num_framelocks; i++ ) { + + ret = XNVCtrlSelectTargetNotify(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, + i, TARGET_ATTRIBUTE_CHANGED_EVENT, + True); + if (ret != True) { + printf("- Unable to register to receive NV-CONTROL GPU " + "target events for Frame Lock %d on '%s'.\n", + i, XDisplayName(NULL)); + continue; + } + + printf("+ Listening to TARGET_ATTRIBUTE_CHANGE_EVENTs on Frame Lock " + "%d.\n", i); + sources++; + } + + + /* + * Report the number of sources (things that we have registered to + * listen for NV-CONTROL X Events on.) + */ + + printf("\n"); + printf("Listening on %d sources for NV-CONTROL X Events...\n", sources); + + /* * Loop forever, processing events */ @@ -99,26 +239,68 @@ int main(void) /* if this is not one of our events, then bail out of this iteration */ - if (event.type != (event_base + ATTRIBUTE_CHANGED_EVENT)) continue; + if ((event.type != (event_base + ATTRIBUTE_CHANGED_EVENT)) && + (event.type != (event_base + TARGET_ATTRIBUTE_CHANGED_EVENT))) + continue; - /* cast the X event as an XNVCtrlAttributeChangedEvent */ + /* Handle ATTRIBUTE_CHANGED_EVENTS */ + if (event.type == (event_base + ATTRIBUTE_CHANGED_EVENT)) { - nvevent = (XNVCtrlAttributeChangedEvent *) &event; + /* cast the X event as an XNVCtrlAttributeChangedEvent */ + + nvevent = (XNVCtrlAttributeChangedEvent *) &event; + + /* print out the event information */ + + printf("received NV-CONTROL event [attribute: %d (%s) " + "value: %d]\n", + nvevent->attribute, + attr2str(nvevent->attribute), + nvevent->value); - /* print out the event information */ - - printf("received NV-CONTROL event [attribute: %d (%s) value: %d]\n", - nvevent->attribute, - attr2str(nvevent->attribute), - nvevent->value); + /* Handle TARGET_ATTRIBUTE_CHANGED_EVENTS */ + } else if (event.type == + (event_base + TARGET_ATTRIBUTE_CHANGED_EVENT)) { + /* cast the X event as an XNVCtrlAttributeChangedEventTarget */ + + nveventtarget = (XNVCtrlAttributeChangedEventTarget *) &event; + + /* print out the event information */ + + printf("received NV-CONTROL target event [target: %d (%s) " + "id: %d ] [attribute: %d (%s) value: %d]\n", + nveventtarget->target_type, + target2str(nveventtarget->target_type), + nveventtarget->target_id, + nveventtarget->attribute, + attr2str(nveventtarget->attribute), + nveventtarget->value); + } } - + return 0; } /* + * target2str() - translate a target type into a string + */ +static const char *target2str(int n) +{ + switch (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; + default: + return "Unknown"; + } +} + + + + +/* * attr2str() - translate an attribute integer into a string */ @@ -132,10 +314,17 @@ static const char *attr2str(int n) case NV_CTRL_LOG_ANISO: return "log aniso"; break; case NV_CTRL_FSAA_MODE: return "fsaa mode"; break; case NV_CTRL_TEXTURE_SHARPEN: return "texture sharpen"; break; + case NV_CTRL_EMULATE: return "OpenGL software emulation"; break; + case NV_CTRL_FRAMELOCK_MASTER: return "frame lock master"; break; + case NV_CTRL_FRAMELOCK_POLARITY: return "frame lock sync edge"; break; + case NV_CTRL_FRAMELOCK_SYNC_DELAY: return "frame lock sync delay"; break; + case NV_CTRL_FRAMELOCK_SYNC_INTERVAL: return "frame lock sync interval"; break; + case NV_CTRL_FRAMELOCK_SYNC: return "frame lock sync"; break; + case NV_CTRL_FRAMELOCK_TEST_SIGNAL: return "frame lock test signal"; break; + case NV_CTRL_FRAMELOCK_VIDEO_MODE: return "frame lock video mode"; break; case NV_CTRL_FORCE_GENERIC_CPU: return "force generic cpu"; break; case NV_CTRL_OPENGL_AA_LINE_GAMMA: return "opengl aa line gamma"; break; case NV_CTRL_FLIPPING_ALLOWED: return "flipping allowed"; break; - case NV_CTRL_FORCE_STEREO: return "force stereo"; break; case NV_CTRL_TEXTURE_CLAMPING: return "texture clamping"; break; case NV_CTRL_CURSOR_SHADOW: return "cursor shadow"; break; case NV_CTRL_CURSOR_SHADOW_ALPHA: return "cursor shadow alpha"; break; @@ -159,7 +348,32 @@ static const char *attr2str(int n) case NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD: return "gpu default core threshold"; break; case NV_CTRL_GPU_MAX_CORE_THRESHOLD: return "gpu max core_threshold"; break; case NV_CTRL_AMBIENT_TEMPERATURE: return "ambient temperature"; break; + case NV_CTRL_PBUFFER_SCANOUT_XID: return "scanout pbuffer xid"; break; + + /* XXX GVO stuff */ + + case NV_CTRL_GPU_OVERCLOCKING_STATE: return "overclocking state"; break; + 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_STATE: return "gpu optimal clock frequency detection state"; break; + + /* XXX DDCCI stuff */ + case NV_CTRL_USE_HOUSE_SYNC: return "use house sync"; break; + case NV_CTRL_FORCE_STEREO: return "force stereo"; break; + case NV_CTRL_IMAGE_SETTINGS: return "image settings"; break; + case NV_CTRL_XINERAMA: return "xinerama"; break; + case NV_CTRL_XINERAMA_STEREO: return "xinerama stereo"; break; + case NV_CTRL_SHOW_SLI_HUD: return "show sli hud"; break; + case NV_CTRL_XV_SYNC_TO_DISPLAY: return "xv sync to display"; break; + + /* XXX More GVO stuff */ + + case NV_CTRL_ASSOCIATED_DISPLAY_DEVICES: return "associated_display_devices"; break; + case NV_CTRL_FRAMELOCK_SLAVES: return "frame lock slaves"; break; + case NV_CTRL_PROBE_DISPLAYS: return "probed displays"; break; + default: return "Unknown"; } diff --git a/samples/nv-control-framelock.c b/samples/nv-control-framelock.c new file mode 100644 index 0000000..2e251ee --- /dev/null +++ b/samples/nv-control-framelock.c @@ -0,0 +1,567 @@ +/* + * 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 new file mode 100644 index 0000000..fd7377a --- /dev/null +++ b/samples/nv-control-targets.c @@ -0,0 +1,310 @@ +/* + * 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-targets.c - NV-CONTROL client that demonstrates how to + * talk to various target types on an X Server (X Screens, GPU, FrameLock) + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <X11/Xlib.h> + +#include "NVCtrl.h" +#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() */ + + + +int main(int argc, char *argv[]) +{ + Display *dpy; + Bool ret; + + int major, minor; + + int num_gpus, num_screens, num_gsyncs; + int gpu, screen; + int display_devices, mask; + int *pData; + int len, j; + char *str; + + + + /* + * 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) { + fprintf(stderr, "Cannot open display '%s'.\n", XDisplayName(NULL)); + return 1; + } + + /* XXX Maybe check all screens for the NV-CONTROL X extension? */ + + screen = DefaultScreen(dpy); + + if (!XNVCTRLIsNvScreen(dpy, screen)) { + fprintf(stderr, "The NV-CONTROL X not available on screen " + "%d of '%s'.\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)); + return 1; + } + + /* Print some information */ + + printf("\n"); + printf("Using NV-CONTROL extension %d.%d on %s\n", + major, minor, XDisplayName(NULL)); + + + /* Start printing server system information */ + + printf("\n"); + printf("Server System Information:\n"); + printf("\n"); + + + /* 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"); + return 1; + } + printf(" number of GPUs: %d\n", num_gpus); + + + /* Get the number of X Screens in the system */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + &num_screens); + if (!ret) { + fprintf(stderr, "Failed to query number of xscreens\n"); + return 1; + } + printf(" number of X Screens: %d\n", num_screens); + + + /* Get the number of Frame Lock devices in the system */ + + ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, + &num_gsyncs); + if (!ret) { + fprintf(stderr, "Failed to query number of xscreens\n"); + return 1; + } + printf(" number of Frame Lock Devices: %d\n", num_gsyncs); + + + /* display information about all GPUs */ + + for (gpu = 0; gpu < num_gpus; gpu++) { + + printf("\n\n"); + printf("GPU %d information:\n", gpu); + + + /* GPU name */ + + ret = XNVCTRLQueryTargetStringAttribute(dpy, + NV_CTRL_TARGET_TYPE_GPU, + gpu, // target_id + 0, // display_mask + NV_CTRL_STRING_PRODUCT_NAME, + &str); + if (!ret) { + fprintf(stderr, "Failed to query gpu product name\n"); + return 1; + } + printf(" Product Name : %s\n", str); + + + /* Connected Display Devices on GPU */ + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_GPU, + gpu, // target_id + 0, // display_mask + NV_CTRL_CONNECTED_DISPLAYS, + &display_devices); + if (!ret) { + fprintf(stderr, "Failed to query connected displays\n"); + return 1; + } + printf(" Display Device Mask (Connected) : 0x%08x\n", + display_devices); + + + /* Enabled Display Devices on GPU */ + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + gpu, // target_id + 0, // display_mask + NV_CTRL_ENABLED_DISPLAYS, + &display_devices); + if (!ret) { + fprintf(stderr, "Failed to query enabled displays\n"); + return 1; + } + printf(" Display Device Mask (Enabled) : 0x%08x\n", + display_devices); + + + /* X Screens driven by this GPU */ + + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_GPU, + gpu, // target_id + 0, // display_mask + 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 on GPU %d : %d\n", gpu, pData[0]); + + + /* List all X Screens on GPU */ + + for (j = 1; j <= pData[0]; j++) { + screen = pData[j]; + + printf("\n"); + printf(" X Screen %d information:\n", screen); + + + /* Connected Display Devices on X Screen */ + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, // target_id + 0, // display_mask + NV_CTRL_CONNECTED_DISPLAYS, + &display_devices); + if (!ret) { + fprintf(stderr, "Failed to query connected displays\n"); + return 1; + } + printf(" Display Device Mask (Connected) : 0x%08x\n", + display_devices); + + + /* Enabled Display Devices on X Screen */ + + ret = XNVCTRLQueryTargetAttribute(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, // target_id + 0, // display_mask + NV_CTRL_ENABLED_DISPLAYS, + &display_devices); + if (!ret) { + fprintf(stderr, "Failed to query enabled displays\n"); + return 1; + } + printf(" Display Device Mask (Enabled) : 0x%08x\n", + display_devices); + + + /* List all display devices on this X Screen */ + + for (mask = 1; mask < (1 << 24); mask <<= 1) { + if (!(display_devices & mask)) { + continue; + } + + ret = XNVCTRLQueryTargetStringAttribute + (dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, // target_id + mask, // display_mask + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &str); + printf(" Display Device (0x%08x) : %s - '%s'\n", + mask, + display_device_name(mask), + str); + } + } + } + + return 0; +} diff --git a/src/command-line.c b/src/command-line.c index fe262ba..199db69 100644 --- a/src/command-line.c +++ b/src/command-line.c @@ -145,15 +145,41 @@ static void print_assign_help(void) "implied following the same rule as the --ctrl-display option. " "If the X screen is not specified, then the assignment is made to " "all X screens. Note that the '/' is only required when {DISPLAY} " - "is present. The [{display devices}] portion is also optional; " + "is present."); + + nv_msg(NULL, ""); + + nv_msg(BIGTAB, "{DISPLAY} can additionally include a target " + "specification to direct an assignment to something other than " + "an X screen. A target specification is contained within brackets " + "and consists of a target type name, a colon, and the " + "target id. The target type name can be one of \"screen\", " + "\"gpu\", or \"framelock\"; the target id is the index into the " + "list of targets (for that target type). The target specification " + "can be used in {DISPLAY} wherever an X screen can be used, " + "following the syntax {host}:{display}[{target_type}:" + "{target_id}]. See the output of `nvidia-settings -q all` for " + "information on which target types can be used with which " + "attributes. See the output of `nvidia-settings -q screens " + "-q gpus -q framelocks` for lists of targets for each " + "target type."); + + nv_msg(NULL, ""); + + nv_msg(BIGTAB, "The [{display devices}] portion is also optional; " "if it is not specified, then the attribute is assigned to all " - "display devices. Some examples:"); + "display devices."); + + nv_msg(NULL, ""); + + nv_msg(BIGTAB, "Some examples:"); nv_msg(NULL, ""); nv_msg(BIGTAB TAB, "-a FSAA=5"); nv_msg(BIGTAB TAB, "-a localhost:0.0/DigitalVibrance[CRT-0]=0"); nv_msg(BIGTAB TAB, "--assign=\"SyncToVBlank=1\""); + nv_msg(BIGTAB TAB, "-a [gpu:0]/DigitalVibrance[DFP-1]=63"); } /* print_assign_help() */ @@ -177,7 +203,10 @@ static void print_query_help(void) nv_msg(BIGTAB, "This queries the current value of the attribute " "{attribute name} on the X Display {DISPLAY}. The format is " "the same as that for the '--assign' option, without " - "'={value}'. Specify '-q all' to query all attributes."); + "'={value}'. Specify '-q screens', '-q gpus', or '-q framelocks' " + "to query a list of X screens, GPUs, or Frame Lock devices, " + "respectively, that are present on the X Display {DISPLAY}. " + "Specify '-q all' to query all attributes."); } /* print_query_help() */ diff --git a/src/config-file.c b/src/config-file.c index 9c2a4a1..c620795 100644 --- a/src/config-file.c +++ b/src/config-file.c @@ -66,6 +66,7 @@ typedef struct { static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, + const int length, ConfigProperties *); static int process_config_file_attributes(const char *file, @@ -103,7 +104,7 @@ static void write_config_properties(FILE *stream, ConfigProperties *conf); int nv_read_config_file(const char *file, const char *display_name, ParsedAttribute *p, ConfigProperties *conf) { - int fd, ret; + int fd, ret, length; struct stat stat_buf; char *buf; ParsedAttributeWrapper *w = NULL; @@ -138,9 +139,11 @@ int nv_read_config_file(const char *file, const char *display_name, return NV_TRUE; } + length = stat_buf.st_size; + /* map the file into memory */ - buf = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0); + buf = mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); if (buf == (void *) -1) { nv_error_msg("Unable to mmap file '%s' for reading (%s).", file, strerror(errno)); @@ -149,7 +152,7 @@ int nv_read_config_file(const char *file, const char *display_name, /* parse the actual text in the file */ - w = parse_config_file(buf, file, conf); + w = parse_config_file(buf, file, length, conf); if (munmap (buf, stat_buf.st_size) == -1) { nv_error_msg("Unable to unmap file '%s' after reading (%s).", @@ -203,6 +206,7 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, ReturnStatus status; NVCTRLAttributeValidValuesRec valid; uint32 mask; + CtrlHandleTarget *t; char *tmp_d_str, *tmp, *prefix, scratch[4]; stream = fopen(filename, "w"); @@ -235,12 +239,19 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, fprintf(stream, "\n"); fprintf(stream, "# Attributes:\n"); fprintf(stream, "\n"); + + /* + * Note: we only save writable attributes addressable by X screen + * (i.e., we don't look at other target types, yet). + */ - for (screen = 0; screen < h->num_screens; screen++) { + for (screen = 0; screen < h->targets[X_SCREEN_TARGET].n; screen++) { + + t = &h->targets[X_SCREEN_TARGET].t[screen]; /* skip it if we don't have a handle for this screen */ - if (!h->h[screen]) continue; + if (!t->h) continue; /* * construct the prefix that will be printed in the config @@ -250,7 +261,7 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, if (conf->booleans & CONFIG_PROPERTIES_INCLUDE_DISPLAY_NAME_IN_CONFIG_FILE) { - prefix = h->screen_names[screen]; + prefix = t->name; } else { snprintf(scratch, 4, "%d", screen); prefix = scratch; @@ -276,7 +287,7 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) { float c[3], b[3], g[3]; - status = NvCtrlGetColorAttributes(h->h[screen], c, b, g); + status = NvCtrlGetColorAttributes(t->h, c, b, g); if (status != NvCtrlSuccess) continue; fprintf(stream, "%s%c%s=%f\n", prefix, DISPLAY_NAME_SEPARATOR, a->name, @@ -288,19 +299,17 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, mask = 1 << bit; - if ((h->d[screen] & mask) == 0x0) continue; + if ((t->d & mask) == 0x0) continue; - status = - NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask, - a->attr, &valid); + status = NvCtrlGetValidDisplayAttributeValues + (t->h, mask, a->attr, &valid); if (status != NvCtrlSuccess) goto exit_bit_loop; if ((valid.permissions & ATTRIBUTE_TYPE_WRITE) == 0x0) goto exit_bit_loop; - status = NvCtrlGetDisplayAttribute(h->h[screen], mask, - a->attr, &val); + status = NvCtrlGetDisplayAttribute(t->h, mask, a->attr, &val); if (status != NvCtrlSuccess) goto exit_bit_loop; @@ -344,28 +353,56 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, */ while (p) { - + char target_str[64]; + if (!p->next) { p = p->next; continue; } tmp = nv_get_attribute_name(p->attr); - if (!tmp) continue; + if (!tmp) { + nv_error_msg("Failure to save unknown attribute %d.", p->attr); + p = p->next; + continue; + } + /* + * if the parsed attribute has a target specification, and a + * target type other than an X screen, include a target + * specification in what we write to the .rc file. + */ + + target_str[0] = '\0'; + + if ((p->flags & NV_PARSER_HAS_TARGET) && + (p->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN)) { + + int j; + + /* Find the target name of the target type */ + for (j = 0; targetTypeTable[j].name; j++) { + if (targetTypeTable[j].nvctrl == p->target_type) { + snprintf(target_str, 64, "[%s:%d]", + targetTypeTable[j].parsed_name, p->target_id); + break; + } + } + } + if (p->display_device_mask) { - + tmp_d_str = display_device_mask_to_display_device_name (p->display_device_mask); - - fprintf(stream, "%s%c%s[%s]=%d\n", p->display, + + fprintf(stream, "%s%s%c%s[%s]=%d\n", p->display, target_str, DISPLAY_NAME_SEPARATOR, tmp, tmp_d_str, p->val); free(tmp_d_str); } else { - fprintf(stream, "%s%c%s=%d\n", p->display, + fprintf(stream, "%s%s%c%s=%d\n", p->display, target_str, DISPLAY_NAME_SEPARATOR, tmp, p->val); } @@ -399,6 +436,7 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, */ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, + const int length, ConfigProperties *conf) { int line, has_data, len, n, ret; @@ -415,7 +453,10 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, comment = NULL; has_data = NV_FALSE;; - while((*c != '\n') && (*c != '\0') && (*c != EOF)) { + while (((c - buf) < length) && + (*c != '\n') && + (*c != '\0') && + (*c != EOF)) { if (comment) { c++; continue; } if (*c == '#') { comment = c; continue; } if (!isspace(*c)) has_data = NV_TRUE; @@ -457,7 +498,7 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, } } - if ((*c == '\0') || (*c == EOF)) cur = NULL; + if (((c - buf) >= length) || (*c == '\0') || (*c == EOF)) cur = NULL; else cur = c + 1; line++; @@ -540,10 +581,11 @@ static int process_config_file_attributes(const char *file, "on line %d of configuration file " "'%s'", w[i].line, file); /* - * We do not fail if processing the attribute failed. - * If the GPU or the X config changed (for example stereo is disabled), - * some attributes written in the config file may not be advertised by - * the the NVCTRL extension (for example the control to force stereo) + * We do not fail if processing the attribute failed. If the + * GPU or the X config changed (for example stereo is + * disabled), some attributes written in the config file may + * not be advertised by the the NVCTRL extension (for example + * the control to force stereo) */ } diff --git a/src/glxinfo.c b/src/glxinfo.c index c252d25..f9f0800 100644 --- a/src/glxinfo.c +++ b/src/glxinfo.c @@ -247,6 +247,7 @@ void print_glxinfo(const char *display_name) { int screen; CtrlHandles *h; + CtrlHandleTarget *t; ReturnStatus status = NvCtrlSuccess; char *direct_rendering = NULL; @@ -266,27 +267,28 @@ void print_glxinfo(const char *display_name) char *formated_ext_str = NULL; - h = nv_alloc_ctrl_handles(display_name); if ( h == NULL ) { return; } /* Print information for each screen */ - for (screen = 0; screen < h->num_screens; screen++) { + for (screen = 0; screen < h->targets[X_SCREEN_TARGET].n; screen++) { + + t = &h->targets[X_SCREEN_TARGET].t[screen]; /* No screen, move on */ - if ( !h->h[screen] ) continue; + if ( !t->h ) continue; - nv_msg(NULL, "GLX Information for %s:", h->screen_names[screen]); + nv_msg(NULL, "GLX Information for %s:", t->name); /* Get GLX information */ - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_DIRECT_RENDERING, &direct_rendering); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_GLX_EXTENSIONS, &glx_extensions); if ( status != NvCtrlSuccess && @@ -299,17 +301,17 @@ void print_glxinfo(const char *display_name) } } /* Get server GLX information */ - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_SERVER_VENDOR, &server_vendor); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_SERVER_VERSION, &server_version); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_SERVER_EXTENSIONS, &server_extensions); if ( status != NvCtrlSuccess && @@ -322,17 +324,17 @@ void print_glxinfo(const char *display_name) } } /* Get client GLX information */ - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_CLIENT_VENDOR, &client_vendor); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_CLIENT_VERSION, &client_version); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_CLIENT_EXTENSIONS, &client_extensions); if ( status != NvCtrlSuccess && @@ -345,22 +347,22 @@ void print_glxinfo(const char *display_name) } } /* Get OpenGL information */ - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_OPENGL_VENDOR, &opengl_vendor); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_OPENGL_RENDERER, &opengl_renderer); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_OPENGL_VERSION, &opengl_version); if ( status != NvCtrlSuccess && status != NvCtrlNoAttribute ) { goto finish; } - status = NvCtrlGetStringAttribute(h->h[screen], + status = NvCtrlGetStringAttribute(t->h, NV_CTRL_STRING_GLX_OPENGL_EXTENSIONS, &opengl_extensions); if ( status != NvCtrlSuccess && @@ -374,7 +376,7 @@ void print_glxinfo(const char *display_name) } /* Get FBConfig information */ - status = NvCtrlGetVoidAttribute(h->h[screen], + status = NvCtrlGetVoidAttribute(t->h, NV_CTRL_ATTR_GLX_FBCONFIG_ATTRIBS, (void *)(&fbconfig_attribs)); if ( status != NvCtrlSuccess && diff --git a/src/gtk+-2.x/Makefile.inc b/src/gtk+-2.x/Makefile.inc index 1adf9cb..9794f16 100644 --- a/src/gtk+-2.x/Makefile.inc +++ b/src/gtk+-2.x/Makefile.inc @@ -49,11 +49,13 @@ SRC += \ ctkdisplaydevice-dfp.c \ ctkthermal.c \ ctkgvo.c \ + ctkgvo-csc.c \ ctkdropdownmenu.c \ ctkrandr.c \ ctkclocks.c \ ctkutils.c \ - ctkedid.c + ctkedid.c \ + ctkimage.c EXTRA_DIST += \ @@ -81,8 +83,10 @@ EXTRA_DIST += \ ctkconstants.h \ ctkthermal.h \ ctkgvo.h \ + ctkgvo-csc.h \ ctkdropdownmenu.h \ ctkrandr.h \ ctkclocks.h \ ctkutils.h \ - ctkedid.h + ctkedid.h \ + ctkimage.h diff --git a/src/gtk+-2.x/ctkclocks.c b/src/gtk+-2.x/ctkclocks.c index 3f1d977..9835ec4 100644 --- a/src/gtk+-2.x/ctkclocks.c +++ b/src/gtk+-2.x/ctkclocks.c @@ -28,6 +28,7 @@ #include <gdk/gdkx.h> #include "clocks_banner.h" +#include "ctkimage.h" #include "ctkclocks.h" @@ -283,6 +284,7 @@ GtkWidget* ctk_clocks_new(NvCtrlAttributeHandle *handle, GtkWidget *label; GtkWidget *frame; + GtkWidget *banner; GtkWidget *hbox; GtkWidget *vbox; @@ -616,29 +618,8 @@ GtkWidget* ctk_clocks_new(NvCtrlAttributeHandle *handle, gtk_box_set_spacing(GTK_BOX(ctk_object), 10); - - { /* Banner image */ - const nv_image_t *image_data = &clocks_banner_image; - guint8 *image_buffer = decompress_image_data(image_data); - GdkPixbuf *image_pixbuf = - gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, image_data->width, - image_data->height, - image_data->width * image_data->bytes_per_pixel, - free_decompressed_image, NULL); - GtkWidget *image = gtk_image_new_from_pixbuf(image_pixbuf); - - frame = gtk_frame_new(NULL); - - hbox = gtk_hbox_new(FALSE, 0); - - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); - - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(frame), image); - } + banner = ctk_banner_image_new(&clocks_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); /* Add Overclocking checkbox */ diff --git a/src/gtk+-2.x/ctkcolorcorrection.c b/src/gtk+-2.x/ctkcolorcorrection.c index 53df87e..991bc9c 100644 --- a/src/gtk+-2.x/ctkcolorcorrection.c +++ b/src/gtk+-2.x/ctkcolorcorrection.c @@ -31,6 +31,7 @@ #include "green_xpm.h" #include "blue_xpm.h" #include "color_correction_banner.h" +#include "ctkimage.h" #include "ctkcurve.h" #include "ctkscale.h" @@ -160,8 +161,8 @@ GtkWidget* ctk_color_correction_new(NvCtrlAttributeHandle *handle, GtkWidget *menu; GtkWidget *image; + GtkWidget *banner; GtkWidget *label; - GtkWidget *frame; GtkWidget *scale; GtkWidget *curve; GtkWidget *menu_item; @@ -178,9 +179,6 @@ GtkWidget* ctk_color_correction_new(NvCtrlAttributeHandle *handle, ReturnStatus ret; gint val; - guint8 *image_buffer = NULL; - const nv_image_t *img; - /* check if the VidMode extension is present */ ret = NvCtrlGetAttribute(handle, NV_CTRL_ATTR_EXT_VM_PRESENT, &val); @@ -203,26 +201,8 @@ GtkWidget* ctk_color_correction_new(NvCtrlAttributeHandle *handle, * purposes. */ - alignment = gtk_alignment_new(0, 0, 0, 0); - gtk_box_pack_start(GTK_BOX(ctk_color_correction), - 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); - - img = &color_correction_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(&color_correction_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_color_correction), banner, FALSE, FALSE, 0); /* create the main hbox and the two main vboxes*/ diff --git a/src/gtk+-2.x/ctkconfig.c b/src/gtk+-2.x/ctkconfig.c index 669d1de..cf3abe6 100644 --- a/src/gtk+-2.x/ctkconfig.c +++ b/src/gtk+-2.x/ctkconfig.c @@ -32,6 +32,7 @@ #include "ctkhelp.h" #include "configuration_banner.h" +#include "ctkimage.h" #include <stdarg.h> #include <stdlib.h> @@ -122,16 +123,12 @@ GtkWidget* ctk_config_new(ConfigProperties *conf) CtkConfig *ctk_config; GtkWidget *hbox; GtkWidget *vbox; - GtkWidget *frame; - GtkWidget *image; + GtkWidget *banner; GtkWidget *label; GtkWidget *hseparator; GtkWidget *check_button; gboolean b; - guint8 *image_buffer = NULL; - const nv_image_t *img; - object = g_object_new(CTK_TYPE_CONFIG, NULL); ctk_config = CTK_CONFIG(object); @@ -160,25 +157,8 @@ GtkWidget* ctk_config_new(ConfigProperties *conf) /* banner */ - hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(ctk_config), 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 = &configuration_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(&configuration_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_config), banner, FALSE, FALSE, 0); /* "nvidia-settings Configuration" */ diff --git a/src/gtk+-2.x/ctkcursorshadow.c b/src/gtk+-2.x/ctkcursorshadow.c index 3f13256..2da653e 100644 --- a/src/gtk+-2.x/ctkcursorshadow.c +++ b/src/gtk+-2.x/ctkcursorshadow.c @@ -43,6 +43,7 @@ #include "NvCtrlAttributes.h" #include "cursor_banner.h" +#include "ctkimage.h" #include "ctkcursorshadow.h" #include "ctkscale.h" @@ -201,7 +202,7 @@ GtkWidget* ctk_cursor_shadow_new(NvCtrlAttributeHandle *handle, { GObject *object; CtkCursorShadow *ctk_cursor_shadow; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *alignment; GtkWidget *hbox; @@ -211,8 +212,6 @@ GtkWidget* ctk_cursor_shadow_new(NvCtrlAttributeHandle *handle, GdkColor color; ReturnStatus ret; gint enabled; - guint8 *image_buffer = NULL; - const nv_image_t *img; gint red, green, blue; char str[16]; @@ -237,25 +236,8 @@ GtkWidget* ctk_cursor_shadow_new(NvCtrlAttributeHandle *handle, /* banner */ - hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(ctk_cursor_shadow), 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(ctk_cursor_shadow), banner, FALSE, FALSE, 0); /* vbox */ diff --git a/src/gtk+-2.x/ctkdisplaydevice-crt.c b/src/gtk+-2.x/ctkdisplaydevice-crt.c index f208ab8..06e1a22 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-crt.c +++ b/src/gtk+-2.x/ctkdisplaydevice-crt.c @@ -26,6 +26,7 @@ #include <NvCtrlAttributes.h> #include "crt_banner.h" +#include "ctkimage.h" #include "ctkdisplaydevice-crt.h" @@ -71,15 +72,12 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, { GObject *object; CtkDisplayDeviceCrt *ctk_display_device_crt; - GtkWidget *image; - GtkWidget *frame; + GtkWidget *banner; GtkWidget *hbox; GtkWidget *label; GtkWidget *alignment; GtkWidget *edid; - guint8 *image_buffer = NULL; - const nv_image_t *img; char *s; object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_CRT, NULL); @@ -94,26 +92,8 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle, /* banner */ - 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); - - img = &crt_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(&crt_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); /* * create the reset button (which we need while creating the diff --git a/src/gtk+-2.x/ctkdisplaydevice-dfp.c b/src/gtk+-2.x/ctkdisplaydevice-dfp.c index d57cc15..f5fdcf6 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-dfp.c +++ b/src/gtk+-2.x/ctkdisplaydevice-dfp.c @@ -26,6 +26,7 @@ #include <NvCtrlAttributes.h> #include "dfp_banner.h" +#include "ctkimage.h" #include "ctkdisplaydevice-dfp.h" @@ -132,9 +133,9 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, { GObject *object; CtkDisplayDeviceDfp *ctk_display_device_dfp; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; - GtkWidget *hbox, *vbox; + GtkWidget *hbox, *vbox, *tmpbox; GtkWidget *label; GtkWidget *eventbox; @@ -149,8 +150,6 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, ReturnStatus ret; - guint8 *image_buffer = NULL; - const nv_image_t *img; gint val, i; object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_DFP, NULL); @@ -164,26 +163,9 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, gtk_box_set_spacing(GTK_BOX(object), 10); /* banner */ - - 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); - - img = &dfp_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(&dfp_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); /* * create the reset button (which we need while creating the @@ -215,7 +197,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, /* create the hbox to store dfp info, scaling and dithering */ hbox = gtk_hbox_new(FALSE, FRAME_PADDING); - gtk_box_pack_start(GTK_BOX(object), hbox, TRUE, TRUE, FRAME_PADDING); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, FRAME_PADDING); /* DFP info */ ret = NvCtrlGetDisplayAttribute(handle, display_device_mask, @@ -250,10 +232,20 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, } frame = gtk_frame_new("Flat Panel Information"); - gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); table = gtk_table_new(3, 2, FALSE); - gtk_container_add(GTK_CONTAINER(frame), table); + + /* + * 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); @@ -279,7 +271,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle, 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, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), eventbox, FALSE, FALSE, 0); ctk_config_set_tooltip(ctk_config, eventbox, __scaling_help); diff --git a/src/gtk+-2.x/ctkdisplaydevice-tv.c b/src/gtk+-2.x/ctkdisplaydevice-tv.c index ffe669c..e0b13f6 100644 --- a/src/gtk+-2.x/ctkdisplaydevice-tv.c +++ b/src/gtk+-2.x/ctkdisplaydevice-tv.c @@ -39,6 +39,7 @@ #include <NvCtrlAttributes.h> #include "tv_banner.h" +#include "ctkimage.h" #include "ctkdisplaydevice-tv.h" @@ -137,16 +138,13 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, { GObject *object; CtkDisplayDeviceTv *ctk_display_device_tv; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *hbox; GtkWidget *label; GtkWidget *alignment; GtkWidget *edid; - guint8 *image_buffer = NULL; - const nv_image_t *img; - char *str; ReturnStatus ret; @@ -161,27 +159,11 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle, gtk_box_set_spacing(GTK_BOX(object), 10); - hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); - /* banner */ - 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 = &tv_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)); + banner = ctk_banner_image_new(&tv_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(frame), image); /* NV_CTRL_STRING_TV_ENCODER_NAME */ diff --git a/src/gtk+-2.x/ctkdisplaydevice.c b/src/gtk+-2.x/ctkdisplaydevice.c index 6063a3e..a379f51 100644 --- a/src/gtk+-2.x/ctkdisplaydevice.c +++ b/src/gtk+-2.x/ctkdisplaydevice.c @@ -29,6 +29,7 @@ #include "crt.h" #include "dfp.h" #include "tv.h" +#include "ctkimage.h" #include "ctkdisplaydevice.h" @@ -67,6 +68,7 @@ GtkWidget* ctk_display_device_new(NvCtrlAttributeHandle *handle, GObject *object; CtkDisplayDevice *ctk_display_device; GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *hbox; GtkWidget *vbox; @@ -90,25 +92,8 @@ GtkWidget* ctk_display_device_new(NvCtrlAttributeHandle *handle, /* banner */ - 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); - - img = &display_device_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(&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 diff --git a/src/gtk+-2.x/ctkedid.c b/src/gtk+-2.x/ctkedid.c index e408681..6c625ea 100644 --- a/src/gtk+-2.x/ctkedid.c +++ b/src/gtk+-2.x/ctkedid.c @@ -172,7 +172,7 @@ static void button_clicked(GtkButton *button, gpointer user_data) &data, &len); if (ret != NvCtrlSuccess) { ctk_config_statusbar_message(ctk_edid->ctk_config, - "No EDID available for %s.\n", + "No EDID available for %s.", ctk_edid->name); } else { @@ -248,7 +248,7 @@ static gboolean write_edid_to_file(CtkConfig *ctk_config, const gchar *filename, close(fd); ctk_config_statusbar_message(ctk_config, - "EDID written to %s.\n", filename); + "EDID written to %s.", filename); return TRUE; fail: diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c index 4a1cfa6..30b77ff 100644 --- a/src/gtk+-2.x/ctkevent.c +++ b/src/gtk+-2.x/ctkevent.c @@ -51,7 +51,8 @@ static gboolean ctk_event_dispatch(GSource *, GSourceFunc, gpointer); /* List of who to contact on dpy events */ typedef struct __CtkEventNodeRec { CtkEvent *ctk_event; - int screen; + int target_type; + int target_id; struct __CtkEventNodeRec *next; } CtkEventNode; @@ -216,6 +217,12 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_SIGNAL(NV_CTRL_BUS_RATE); MAKE_SIGNAL(NV_CTRL_SHOW_SLI_HUD); 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_FRAMELOCK_SLAVES); + MAKE_SIGNAL(NV_CTRL_FRAMELOCK_MASTERABLE); + MAKE_SIGNAL(NV_CTRL_PROBE_DISPLAYS); + MAKE_SIGNAL(NV_CTRL_REFRESH_RATE); #undef MAKE_SIGNAL @@ -226,7 +233,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) * knows about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_XV_SYNC_TO_DISPLAY +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_REFRESH_RATE #warning "There are attributes that do not emit signals!" #endif @@ -254,7 +261,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) * is received, the dispatching function should then * emit a signal to every CtkEvent object that * requests event notification from the dpy for the - * given X screen. + * given target type/id (X screen, GPU etc). */ static void ctk_event_register_source(CtkEvent *ctk_event) { @@ -318,11 +325,25 @@ static void ctk_event_register_source(CtkEvent *ctk_event) return; } event_node->ctk_event = ctk_event; - event_node->screen = NvCtrlGetScreen(ctk_event->handle); + event_node->target_type = NvCtrlGetTargetType(ctk_event->handle); + event_node->target_id = NvCtrlGetTargetId(ctk_event->handle); event_node->next = event_source->ctk_events; event_source->ctk_events = event_node; + /* + * This next bit of code is to make sure that the randr_event_base + * for this event source is valid in the case where a NON X Screen + * target type handle is used to create the initial event source + * (Resulting in randr_event_base being == -1), followed by an + * X Screen target type handle registering itself to receive + * XRandR events on the existing dpy/event source. + */ + if (event_source->randr_event_base == -1 && + event_node->target_type == NV_CTRL_TARGET_TYPE_X_SCREEN) { + event_source->randr_event_base = + NvCtrlGetXrandrEventBase(ctk_event->handle); + } -} /* ctk_event_create_source() */ +} /* ctk_event_register_source() */ @@ -372,15 +393,16 @@ static gboolean ctk_event_check(GSource *source) } -#define CTK_EVENT_BROADCAST(ES, SIG, PTR, SCR) \ -do { \ - CtkEventNode *e = (ES)->ctk_events; \ - while (e) { \ - if (e->screen == (SCR)) { \ - g_signal_emit(e->ctk_event, SIG, 0, PTR); \ - } \ - e = e->next; \ - } \ +#define CTK_EVENT_BROADCAST(ES, SIG, PTR, TYPE, ID) \ +do { \ + CtkEventNode *e = (ES)->ctk_events; \ + while (e) { \ + if (e->target_type == (TYPE) && \ + e->target_id == (ID)) { \ + g_signal_emit(e->ctk_event, SIG, 0, PTR); \ + } \ + e = e->next; \ + } \ } while (0) static gboolean ctk_event_dispatch(GSource *source, @@ -397,7 +419,7 @@ static gboolean ctk_event_dispatch(GSource *source, */ XNextEvent(event_source->dpy, &event); - + /* * Handle the ATTRIBUTE_CHANGED_EVENT NV-CONTROL event */ @@ -417,26 +439,60 @@ static gboolean ctk_event_dispatch(GSource *source, event_struct.display_mask = nvctrlevent->display_mask; /* - * XXX Is emitting a signal like this really the "correct" - * way of dispatching the event? + * XXX Is emitting a signal with g_signal_emit() really + * the "correct" way of dispatching the event? */ CTK_EVENT_BROADCAST(event_source, signals[nvctrlevent->attribute], &event_struct, + NV_CTRL_TARGET_TYPE_X_SCREEN, nvctrlevent->screen); } } + /* + * Handle the TARGET_ATTRIBUTE_CHANGED_EVENT NV-CONTROL event + */ + + if (event.type == (event_source->event_base + +TARGET_ATTRIBUTE_CHANGED_EVENT)) { + XNVCtrlAttributeChangedEventTarget *nvctrlevent = + (XNVCtrlAttributeChangedEventTarget *) &event; + + /* make sure the attribute is in our signal array */ + + if ((nvctrlevent->attribute >= 0) && + (nvctrlevent->attribute <= NV_CTRL_LAST_ATTRIBUTE) && + (signals[nvctrlevent->attribute] != 0)) { + + event_struct.attribute = nvctrlevent->attribute; + event_struct.value = nvctrlevent->value; + event_struct.display_mask = nvctrlevent->display_mask; + + /* + * XXX Is emitting a signal with g_signal_emit() really + * the "correct" way of dispatching the event? + */ + + CTK_EVENT_BROADCAST(event_source, + signals[nvctrlevent->attribute], + &event_struct, + nvctrlevent->target_type, + nvctrlevent->target_id); + } + } + /* * Also handle XRandR events. */ - if (event.type == + if (event_source->randr_event_base != -1 && + event.type == (event_source->randr_event_base + RRScreenChangeNotify)) { XRRScreenChangeNotifyEvent *xrandrevent = (XRRScreenChangeNotifyEvent *)&event; int screen; - + /* Find the screen the window belongs to */ screen = XScreenCount(xrandrevent->display); screen--; @@ -451,6 +507,7 @@ static gboolean ctk_event_dispatch(GSource *source, CTK_EVENT_BROADCAST(event_source, signal_RRScreenChangeNotify, &event, + NV_CTRL_TARGET_TYPE_X_SCREEN, screen); } } diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c index 39b5c25..f820a19 100644 --- a/src/gtk+-2.x/ctkframelock.c +++ b/src/gtk+-2.x/ctkframelock.c @@ -22,2056 +22,2587 @@ * */ + #include <gtk/gtk.h> #include <NvCtrlAttributes.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <assert.h> #include "ctkframelock.h" #include "ctkhelp.h" +#include "ctkevent.h" +#include "ctkimage.h" #include "frame_lock_banner.h" + #include "led_green.h" #include "led_red.h" #include "led_grey.h" #include "rj45_input.h" #include "rj45_output.h" +#include "rj45_unused.h" + +#include "bnc_cable.h" #include "parse.h" #include "msg.h" -#define DEFAULT_UPDATE_STATUS_TIME_INTERVAL 1000 -#define DEFAULT_TEST_LINK_TIME_INTERVAL 2000 -#define DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL 10000 +#define DEFAULT_UPDATE_STATUS_TIME_INTERVAL 1000 +#define DEFAULT_TEST_LINK_TIME_INTERVAL 2000 +#define DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL 10000 -#define POLARITY_RISING 0x1 -#define POLARITY_FALLING 0x2 -#define POLARITY_BOTH 0x3 +#define POLARITY_RISING 0x1 +#define POLARITY_FALLING 0x2 +#define POLARITY_BOTH 0x3 -/* - * functions for the FrameLock Widget - */ +#define FRAME_PADDING 5 -static void ctk_framelock_class_init(CtkFramelockClass *ctk_framelock_class); -static gpointer add_x_screen(CtkFramelock *, const gchar *, gboolean); -static GtkWidget *create_add_x_screen_dialog(CtkFramelock *ctk_framelock); -static GtkWidget *create_remove_x_screen_dialog(CtkFramelock *ctk_framelock); -static GtkWidget *create_error_msg_dialog(CtkFramelock *ctk_framelock); -static GtkWidget *create_sync_state_button(CtkFramelock *ctk_framelock); +enum +{ + ENTRY_DATA_FRAMELOCK = 0, + ENTRY_DATA_GPU, + ENTRY_DATA_DISPLAY +}; -static gboolean update_status(gpointer user_data); -static gboolean check_for_ethernet(gpointer user_data); -static void test_link(GtkWidget *button, CtkFramelock *ctk_framelock); -static gint test_link_done(gpointer data); +typedef struct _nvListTreeRec nvListTreeRec, *nvListTreePtr; +typedef struct _nvListEntryRec nvListEntryRec, *nvListEntryPtr; -static void toggle_sync_state_button(GtkWidget *button, - CtkFramelock *ctk_framelock); +typedef struct _nvDisplayDataRec nvDisplayDataRec, *nvDisplayDataPtr; +typedef struct _nvGPUDataRec nvGPUDataRec, *nvGPUDataPtr; +typedef struct _nvFrameLockDataRec nvFrameLockDataRec, *nvFrameLockDataPtr; -static void show_remove_x_screen_dialog(GtkWidget *, CtkFramelock *); -static void error_msg(CtkFramelock *ctk_framelock, const gchar *fmt, ...); +struct _nvListEntryRec { + + nvListTreePtr tree; + GtkWidget *vbox; /* Holds all entry widgets and children */ -static void create_list_store(CtkFramelock *ctk_framelock); -static void add_member_to_list_store(CtkFramelock *ctk_framelock, - const gpointer handle); + GtkWidget *vp; /* Viewport used to set selected color */ + GtkWidget *parent_hbox; /* Holds expander button and data */ + GtkWidget *button; /* Expander button */ + gboolean expanded; + GtkWidget *button_image; -static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock, - ParsedAttribute *p); - -static GtkWidget *add_house_sync_controls(NvCtrlAttributeHandle *handle, CtkFramelock *ctk_framelock); -static void update_house_sync_controls(CtkFramelock *ctk_framelock); - -static void add_columns_to_treeview(CtkFramelock *ctk_framelock); - -static void sync_interval_entry_activate(GtkEntry *, gpointer); -static void house_sync_format_entry_activate(GtkEditable *, gpointer); - -static gboolean find_master(CtkFramelock *, GtkTreeIter *, - NvCtrlAttributeHandle **); - -enum -{ - COLUMN_HANDLE, - COLUMN_DISPLAY_MASK, - COLUMN_DISPLAY_NAME, - COLUMN_MASTER, - COLUMN_STEREO_SYNC, - COLUMN_TIMING, - COLUMN_SYNC_READY, - COLUMN_SYNC_RATE, - COLUMN_HOUSE, - COLUMN_RJ45_PORT0, - COLUMN_RJ45_PORT1, - COLUMN_POLARITY, - COLUMN_SYNC_SKEW, - COLUMN_SYNC_INTERVAL, - COLUMN_HOUSE_FORMAT, - NUM_COLUMNS -}; + GtkWidget *data_hbox; /* Holds entry data (after expander button) */ + GtkWidget *child_hbox; /* Holds padding and children */ + GtkWidget *child_vbox; + gpointer data; /* Data (used to render entry) */ + gint data_type; + CtkEvent *ctk_event; /* For receiving events on the entry */ + nvListEntryPtr parent; + nvListEntryPtr children; + int nchildren; -/* - * helper functions for displaying the correct thing in the columns of - * the tree view - */ - -static void led_renderer_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); - -static void rj45_renderer_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); - -static void rate_renderer_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); - -static void polarity_renderer_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); - -static void sync_skew_renderer_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data); - -/* callback functions */ - -static void master_toggled(GtkCellRendererToggle *cell, - gchar *path_str, - gpointer data); - -static void rising_edge_toggled(GtkCellRendererToggle *cell, - gchar *path_string, - gpointer user_data); - -static void falling_edge_toggled(GtkCellRendererToggle *cell, - gchar *path_string, - gpointer user_data); - -static void sync_skew_edited(GtkCellRendererText *cell, - const gchar *path_string, - const gchar *new_text, - gpointer data); + nvListEntryPtr next_sibling; +}; -static GObjectClass *parent_class; +struct _nvListTreeRec { + GtkWidget *vbox; /* Holds top level entries */ + CtkFramelock *ctk_framelock; /* XXX Too bad we need this here */ -/* - * ctk_framelock_get_type() - register the FrameLock class and - * return the unique type id. - */ + nvListEntryPtr entries; /* Top level entries */ + int nentries; -GType ctk_framelock_get_type( - void -) -{ - static GType ctk_framelock_type = 0; + nvListEntryPtr selected_entry; + nvListEntryPtr server_entry; +}; - if (!ctk_framelock_type) { - static const GTypeInfo ctk_framelock_info = { - sizeof (CtkFramelockClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) ctk_framelock_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (CtkFramelock), - 0, /* n_preallocs */ - NULL, /* instance_init */ - }; - - ctk_framelock_type = g_type_register_static - (GTK_TYPE_VBOX, "CtkFramelock", &ctk_framelock_info, 0); - } - return ctk_framelock_type; +struct _nvDisplayDataRec { + + gpointer handle; /* NV-CONTROL GPU Target */ -} /* ctk_framelock_get_type() */ + GtkWidget *label; + guint device_mask; + GtkWidget *server_label; + GtkWidget *server_checkbox; + gboolean masterable; + GtkWidget *client_label; + GtkWidget *client_checkbox; -/* - * ctk_framelock_class_init() - initialize the object structure - */ + GtkWidget *rate_label; + GtkWidget *rate_text; + guint rate; -static void ctk_framelock_class_init( - CtkFramelockClass *ctk_framelock_class -) -{ - GObjectClass *gobject_class; + GtkWidget *timing_label; + GtkWidget *timing_hbox; /* LED */ - gobject_class = (GObjectClass *) ctk_framelock_class; - parent_class = g_type_class_peek_parent(ctk_framelock_class); + GtkWidget *stereo_label; + GtkWidget *stereo_hbox; /* LED */ +}; -} /* ctk_framelock_class_init() */ +struct _nvGPUDataRec { + gpointer handle; /* NV-CONTROL GPU Target */ + guint server_mask; + guint clients_mask; + gboolean enabled; /* Sync enabled */ -/* - * ctk_framelock_new() - return a new instance of the FrameLock - * class. - */ + GtkWidget *label; +}; + +struct _nvFrameLockDataRec { + + gpointer handle; /* NV-CONTROL Frame Lock Target */ -GtkWidget* ctk_framelock_new(NvCtrlAttributeHandle *handle, - GtkWidget *parent_window, CtkConfig *ctk_config, - ParsedAttribute *p) -{ - GObject *object; - CtkFramelock *ctk_framelock; - GtkWidget *hbox; - GtkWidget *hbox2; GtkWidget *label; - GtkWidget *frame; - GtkWidget *image; - GtkWidget *sw; - GtkWidget *hseparator; - gint value; - guint8 *image_buffer = NULL; - const nv_image_t *img; + GtkWidget *receiving_label; + GtkWidget *receiving_hbox; /* LED */ - /* make sure we have a handle */ + GtkWidget *rate_label; + GtkWidget *rate_text; - g_return_val_if_fail(handle != NULL, NULL); + GtkWidget *delay_label; + GtkWidget *delay_text; - /* - * Only expose FrameLock if the current NV-CONTROL handle supports - * FrameLock. This isn't absolutely necessary, because the - * FrameLock control page does not have to include the current - * NV-CONTROL handle in the FrameLock Group. However, we don't - * want to expose the FrameLock page unconditionally (it would - * only confuse most users), so this is as good a condition as - * anything else. - */ - - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK, &value); - if (value != NV_CTRL_FRAMELOCK_SUPPORTED) return NULL; - - /* create a new instance of the object */ - - object = g_object_new(CTK_TYPE_FRAMELOCK, NULL); + GtkWidget *house_label; + GtkWidget *house_hbox; /* LED */ + + GtkWidget *port0_label; + GtkWidget *port0_hbox; /* IMAGE */ + guint port0_ethernet_error; + + GtkWidget *port1_label; + GtkWidget *port1_hbox; /* IMAGE */ + guint port1_ethernet_error; - ctk_framelock = CTK_FRAMELOCK(object); - ctk_framelock->attribute_handle = handle; - ctk_framelock->parent_window = GTK_WINDOW(parent_window); + GtkWidget *extra_info_hbox; +}; - gtk_box_set_spacing(GTK_BOX(ctk_framelock), 10); - /* banner */ +static gchar *houseFormatStrings[] = { + "Composite, Auto", /* VIDEO_MODE_COMPOSITE_AUTO */ + "TTL", /* VIDEO_MODE_TTL */ + "Composite, Bi-Level", /* VIDEO_MODE_COMPOSITE_BI_LEVEL */ + "Composite, Tri-Level", /* VIDEO_MODE_COMPOSITE_TRI_LEVEL */ + NULL + }; - hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); +static gchar *syncEdgeStrings[] = { + "", /* None */ + "Rising", /* NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE */ + "Falling", /* NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE */ + "Both", /* NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES */ + NULL + }; - 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 = &frame_lock_banner_image; +/* Tooltips */ - image_buffer = decompress_image_data(img); +static const char * __add_devices_button_help = +"The Add Devices button adds to the frame lock group all G-Sync devices found " +"on the specified X Server."; - 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)); +static const char * __remove_devices_button_help = +"The Remove Devices button allows you to remove G-Sync, GPU or display " +"devices from the frame lock group. Any device removed from the frame lock " +"group will no longer be controlled."; - gtk_container_add(GTK_CONTAINER(frame), image); +static const char * __show_extra_info_button_help = +"The Show Extra Info button displays extra information and settings " +"for various devices."; - /* scrollable list */ +static const char * __use_house_sync_button_help = +"The Use House Sync if Present checkbox tells the server G-Sync device to " +"generate the master frame lock signal from the incoming house sync signal " +"(if a house sync signal is detected) instead of using internal timing from " +"the server GPU/display device."; - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_box_pack_start(GTK_BOX(object), sw, TRUE, TRUE, 0); - - /* create the list store and treeview */ +static const char * __sync_interval_entry_help = +"The Sync Interval entry allows you to set the number of incoming house sync " +"pulses the master frame lock board recieves before generating an outgoing " +"frame lock sync pulse. A value of 0 means a frame lock sync pulse is sent " +"for every house sync pulse."; - create_list_store(ctk_framelock); +static const char * __sync_edge_combo_help = +"The Sync Edge drop-down allows you to select which edge the master " +"frame lock device will use to decode the incoming house sync signal."; - /* plug the treeview into the scrollable window */ - - gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(ctk_framelock->treeview)); - - hseparator = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(object), hseparator, FALSE, TRUE, 0); +static const char * __video_mode_combo_help = +"The Video Mode drop-down allows you to select which video mode the server " +"G-Sync device will use to decode the incoming house sync signal."; - /* Sync Interval and House Sync Format controls */ - - hbox = add_house_sync_controls(handle, ctk_framelock); - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, TRUE, 0); - - hseparator = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(object), hseparator, FALSE, TRUE, 0); +static const char * __detect_video_mode_button_help = +"The Detect Video Mode button will attempt to automatically detect the format " +"of the house sync signal by iterating through the list of known video modes."; - /* create any needed dialog windows */ +static const char * __test_link_button_help = +"The Test Link button will cause the master frame lock device to output a " +"test signal for a short amount of time. During this time, the Sync Signal " +"coming from the master frame lock device will be held high causing the rj45 " +"ports throughout the frame lock group to stop blinking."; - ctk_framelock->add_x_screen_dialog = - create_add_x_screen_dialog(ctk_framelock); +static const char * __sync_enable_button_help = +"The Enable/Disable Frame Lock button will enable/disable frame lock on all " +"devices listed in the G-Sync group. Enabling frame lock will lock the " +"refresh rates of all members in the frame lock group."; - ctk_framelock->remove_x_screen_dialog = - create_remove_x_screen_dialog(ctk_framelock); +static const char * __server_checkbox_help = +"The Server checkbox sets which display device the underlying frame lock " +"device should use to generate the frame lock sync signal. Only one display " +"device can be selected as server for a frame lock group. To select another " +"display device, the display device currently set as server should be " +"unselected."; - ctk_framelock->error_msg_dialog = - create_error_msg_dialog(ctk_framelock); +static const char * __client_checkbox_help = +"The Client checkbox allows you to set whether or not this display device " +"will be synchronized to the incoming frame lock sync signal."; - /* create buttons */ - - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, TRUE, 0); - - /* "Add X Screen..." button */ - label = gtk_label_new("Add X Screen..."); - hbox2 = gtk_hbox_new(FALSE, 0); - ctk_framelock->add_x_screen_button = gtk_button_new(); - - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15); - gtk_container_add(GTK_CONTAINER(ctk_framelock->add_x_screen_button), - hbox2); - - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->add_x_screen_button, - FALSE, TRUE, 0); - - g_signal_connect_swapped(G_OBJECT(ctk_framelock->add_x_screen_button), - "clicked", G_CALLBACK(gtk_widget_show_all), - (gpointer) ctk_framelock->add_x_screen_dialog); - /* "Remove X Screen..." button */ +static unsigned int add_framelock_devices(CtkFramelock *, gpointer); +static unsigned int add_gpu_devices(CtkFramelock *, nvListEntryPtr); +static unsigned int add_display_devices(CtkFramelock *, nvListEntryPtr); +static gint add_devices(CtkFramelock *, const gchar *, gboolean); - label = gtk_label_new("Remove X Screen..."); - hbox2 = gtk_hbox_new(FALSE, 0); - ctk_framelock->remove_x_screen_button = gtk_button_new(); +static GtkWidget *create_add_devices_dialog(CtkFramelock *); +static GtkWidget *create_remove_devices_dialog(CtkFramelock *); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15); - gtk_container_add(GTK_CONTAINER(ctk_framelock->remove_x_screen_button), - hbox2); +static void add_devices_response(GtkWidget *, gint, gpointer); +static void add_devices_repond_ok(GtkWidget *, gpointer); +static void remove_devices_response(GtkWidget *, gint, gpointer); - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->remove_x_screen_button, - FALSE, TRUE, 0); - gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, FALSE); - - g_signal_connect(G_OBJECT(ctk_framelock->remove_x_screen_button), - "clicked", G_CALLBACK(show_remove_x_screen_dialog), - GTK_OBJECT(ctk_framelock)); - - /* "Test Link" button */ +static void error_msg(CtkFramelock *, const gchar *, ...); - label = gtk_label_new("Test Link"); - hbox2 = gtk_hbox_new(FALSE, 0); - ctk_framelock->test_link_button = gtk_toggle_button_new(); - - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15); - gtk_container_add(GTK_CONTAINER(ctk_framelock->test_link_button), hbox2); +static void toggle_use_house_sync(GtkWidget *, gpointer); +static void toggle_extra_info(GtkWidget *, gpointer); +static void toggle_server(GtkWidget *, gpointer); +static void toggle_client(GtkWidget *, gpointer); +static void toggle_sync_enable(GtkWidget *, gpointer); +static void toggle_test_link(GtkWidget *, gpointer); +static void activate_sync_interval(GtkEntry *, gpointer); +static void changed_video_mode(GtkEditable *, gpointer); +static void toggle_detect_video_mode(GtkToggleButton *, gpointer); - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->test_link_button, - FALSE, TRUE, 0); - - gtk_widget_set_sensitive(ctk_framelock->test_link_button, FALSE); +static gboolean update_framelock_status(gpointer); +static gboolean check_for_ethernet(gpointer); - g_signal_connect(G_OBJECT(ctk_framelock->test_link_button), "toggled", - G_CALLBACK(test_link), GTK_OBJECT(ctk_framelock)); - - /* Sync State button */ +static void update_framelock_controls(CtkFramelock *); +static void update_house_sync_controls(CtkFramelock *); - ctk_framelock->sync_state_button = create_sync_state_button(ctk_framelock); +static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock, + ParsedAttribute *list); - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->sync_state_button, - FALSE, TRUE, 0); +static void gpu_state_received(GtkObject *object, + gpointer arg1, gpointer user_data); +static void framelock_state_received(GtkObject *object, + gpointer arg1, gpointer user_data); - gtk_widget_set_sensitive(ctk_framelock->sync_state_button, FALSE); - - g_signal_connect(G_OBJECT(ctk_framelock->sync_state_button), "toggled", - G_CALLBACK(toggle_sync_state_button), - GTK_OBJECT(ctk_framelock)); - - /* show the page */ - - gtk_widget_show_all(GTK_WIDGET(object)); - - /* register a timer callback to update the status of the page */ - ctk_config_add_timer(ctk_config, DEFAULT_UPDATE_STATUS_TIME_INTERVAL, - "FrameLock Connection Status", - (GSourceFunc) update_status, - (gpointer) ctk_framelock); - - /* register a timer callback to check the rj45 ports */ +#define SELECT_WIDGET(W, S) \ + gtk_widget_modify_fg(GTK_WIDGET(W), GTK_STATE_NORMAL, \ + &((GTK_WIDGET(W))->style->text[S])); \ + gtk_widget_modify_bg(GTK_WIDGET(W), GTK_STATE_NORMAL, \ + &((GTK_WIDGET(W))->style->base[S])); - ctk_config_add_timer(ctk_config, DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL, - "FrameLock RJ45 Check", - (GSourceFunc) check_for_ethernet, - (gpointer) ctk_framelock); - ctk_framelock->ctk_config = ctk_config; - /* create the watch cursor */ +/************************************************************************/ - ctk_framelock->wait_cursor = gdk_cursor_new(GDK_WATCH); +/* + * Widget creation hepher functions + */ + + +/** create_error_msg_dialog() **************************************** + * + * Creates the error message dialog. This dialog is used by various + * parts of the GUI to report errors. + * + */ +static GtkWidget *create_error_msg_dialog(CtkFramelock *ctk_framelock) +{ + GtkWidget *dialog; + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *alignment; + GdkPixbuf *pixbuf; - /* apply the parsed attribute list */ + + dialog = gtk_dialog_new_with_buttons("Error", + ctk_framelock->parent_window, + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT | + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); - apply_parsed_attribute_list(ctk_framelock, p); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_hide_all), + GTK_OBJECT(dialog)); + + gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + hbox = gtk_hbox_new(FALSE, 12); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - return GTK_WIDGET(object); + pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_ERROR, + GTK_ICON_SIZE_DIALOG, NULL); + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); -} /* ctk_framelock_new() */ + ctk_framelock->error_msg_label = gtk_label_new(NULL); + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), image); + gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), + ctk_framelock->error_msg_label); + gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0); -/**************************************************************************/ + return dialog; +} -static gchar *houseFormatStrings[] = { - "Composite, Auto", /* VIDEO_MODE_COMPOSITE_AUTO */ - "TTL", /* VIDEO_MODE_TTL */ - "Composite, Bi-Level", /* VIDEO_MODE_COMPOSITE_BI_LEVEL */ - "Composite, Tri-Level", /* VIDEO_MODE_COMPOSITE_TRI_LEVEL */ - }; -static void use_house_sync_released(GtkToggleButton *togglebutton, - gpointer user_data); -static void detect_house_sync_format_toggled(GtkToggleButton *togglebutton, - gpointer user_data); -/* - * House Sync autodetection scheme: a modal push button is used to - * request auto detection. When the button is pressed, we program the - * first format type and then start a timer. +/** create_sync_state_button() *************************************** + * + * Creates the enable/disable frame lock button. This button has + * two labels - one for each state it can be in such that an + * informative icon. * - * From the timer, we check if we are getting a house sync; if we are, - * then update the settings and unpress the button. If we are not, - * program the next format in the sequence and try again. */ +static GtkWidget *create_sync_state_button(CtkFramelock *ctk_framelock) +{ + GtkWidget *label; + GtkWidget *hbox, *hbox2; + GdkPixbuf *pixbuf; + GtkWidget *image = NULL; + GtkWidget *button; + button = gtk_toggle_button_new(); -/* - * detect_house_sync_format_timer() - - */ - -static gboolean detect_house_sync_format_timer(gpointer user_data) -{ - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - NvCtrlAttributeHandle *handle = NULL; - gint house; - GtkTreeIter iter; + /* create the enable syncing icon */ - if (!find_master(ctk_framelock, &iter, &handle)) { - goto done; - } + pixbuf = gtk_widget_render_icon(button, + GTK_STOCK_EXECUTE, + GTK_ICON_SIZE_BUTTON, + "enable frame lock"); + if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf); + label = gtk_label_new("Enable Frame Lock"); - /* check if we now have house sync */ - - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house); + hbox = gtk_hbox_new(FALSE, 2); - if (house) { - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - /* - * We found house sync; use the current_detect_format - */ + if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_HOUSE, house, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_HOUSE_FORMAT, - ctk_framelock->current_detect_format, -1); - - update_house_sync_controls(ctk_framelock); + hbox2 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15); - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "House Sync format detected as %s.", - houseFormatStrings - [ctk_framelock->current_detect_format]); - - goto done; - } + gtk_widget_show_all(hbox2); /* - * we did not find house sync, yet, so move to the next format + * XXX increment the reference count, so that when we do + * gtk_container_remove() later, it doesn't get destroyed */ + + gtk_object_ref(GTK_OBJECT(hbox2)); + + ctk_framelock->enable_syncing_label = hbox2; - switch (ctk_framelock->current_detect_format) { - case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO: - ctk_framelock->current_detect_format = - NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL; - break; - - case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL: - ctk_framelock->current_detect_format = - NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL; - break; - - case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL: - ctk_framelock->current_detect_format = - NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL; - break; + /* create the disable syncing icon */ + + pixbuf = gtk_widget_render_icon(button, + GTK_STOCK_STOP, + GTK_ICON_SIZE_BUTTON, + "disable frame lock"); + if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf); + label = gtk_label_new("Disable Frame Lock"); + + hbox = gtk_hbox_new(FALSE, 2); + + if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + hbox2 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15); - case NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL: - ctk_framelock->current_detect_format = - NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO; - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Unable to detect house sync format."); - goto done; - break; - } + gtk_widget_show_all(hbox2); /* - * Set the new video format + * XXX increment the reference count, so that when we do + * gtk_container_remove() later, it doesn't get destroyed */ - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, - ctk_framelock->current_detect_format); + gtk_object_ref(GTK_OBJECT(hbox2)); + + ctk_framelock->disable_syncing_label = hbox2; + + /* start with syncing disabled */ + + ctk_framelock->selected_syncing_label = + ctk_framelock->enable_syncing_label; + gtk_container_add(GTK_CONTAINER(button), + ctk_framelock->selected_syncing_label); - return TRUE; + return (button); +} - done: - /* untoggle the detect button */ + +/** create_add_devices_dialog() ************************************** + * + * Creates the dialog that will query for a server name from which + * frame lock/gpu/display devices will be added to the current + * frame lock group. + * + */ +static GtkWidget *create_add_devices_dialog(CtkFramelock *ctk_framelock) +{ + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label, *descr; + GtkWidget *image; + GdkPixbuf *pixbuf; + GtkWidget *alignment; + + dialog = gtk_dialog_new_with_buttons("Add X Screen", + ctk_framelock->parent_window, + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT | + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); + + g_signal_connect (GTK_OBJECT(dialog), "response", + G_CALLBACK(add_devices_response), + GTK_OBJECT(ctk_framelock)); + + gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - g_signal_handlers_block_by_func - (G_OBJECT(ctk_framelock->house_format_detect), - G_CALLBACK(detect_house_sync_format_toggled), - (gpointer) ctk_framelock); + hbox = gtk_hbox_new(FALSE, 12); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(ctk_framelock->house_format_detect), FALSE); + pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG, NULL); + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + + label = gtk_label_new("X Server:"); + descr = gtk_label_new("Please specify the X server to be added to the " + "frame lock group."); - g_signal_handlers_unblock_by_func - (G_OBJECT(ctk_framelock->house_format_detect), - G_CALLBACK(detect_house_sync_format_toggled), - (gpointer) ctk_framelock); + ctk_framelock->add_devices_entry = gtk_entry_new(); + + g_signal_connect(G_OBJECT(ctk_framelock->add_devices_entry), + "activate", G_CALLBACK(add_devices_repond_ok), + (gpointer) ctk_framelock); - /* do not call this timer any more */ + gtk_entry_set_text(GTK_ENTRY(ctk_framelock->add_devices_entry), + NvCtrlGetDisplayName + (ctk_framelock->attribute_handle)); - return FALSE; + gtk_entry_set_width_chars + (GTK_ENTRY(ctk_framelock->add_devices_entry), 16); + + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), image); + gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); + + vbox = gtk_vbox_new(FALSE, 12); + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), descr); + gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(FALSE, 12); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->add_devices_entry, + TRUE, TRUE, 0); -} /* detect_house_sync_format_timer() */ + return dialog; +} -/* - * detect_house_sync_format_toggled() - called when the house sync - * "detect" button is toggled. If the toggle button is active, then - * start the detect sequence by programming - * NV_CTRL_FRAMELOCK_VIDEO_MODE to COMPOSITE_AUTO + +/** create_remove_devices_dialog() *********************************** + * + * Creates the dialog that will query for a server name from which + * frame lock/gpu/display devices will be added to the current + * frame lock group. * - * XXX what happens if the master gets changed while we are doing - * this? */ - -static void detect_house_sync_format_toggled(GtkToggleButton *togglebutton, - gpointer user_data) +static GtkWidget *create_remove_devices_dialog(CtkFramelock *ctk_framelock) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - NvCtrlAttributeHandle *handle = NULL; + GtkWidget *dialog; + GtkWidget *hbox; + GtkWidget *image; + GdkPixbuf *pixbuf; + GtkWidget *alignment; - if (gtk_toggle_button_get_active(togglebutton)) { - - /* - * the toggle button is active: we now start scanning through - * the possible input video modes and enable the house sync - * format timer. - */ - - if (!find_master(ctk_framelock, NULL, &handle)) { - g_signal_handlers_block_by_func - (G_OBJECT(ctk_framelock->house_format_detect), - G_CALLBACK(detect_house_sync_format_toggled), - (gpointer) ctk_framelock); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(ctk_framelock->house_format_detect), FALSE); + dialog = gtk_dialog_new_with_buttons("Remove Device(s)", + ctk_framelock->parent_window, + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT | + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); - g_signal_handlers_unblock_by_func - (G_OBJECT(ctk_framelock->house_format_detect), - G_CALLBACK(detect_house_sync_format_toggled), - (gpointer) ctk_framelock); - - return; - } - - ctk_framelock->current_detect_format = - NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO; + g_signal_connect(GTK_OBJECT(dialog), "response", + G_CALLBACK(remove_devices_response), + GTK_OBJECT(ctk_framelock)); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, - ctk_framelock->current_detect_format); - - ctk_framelock->house_format_detect_timer = - g_timeout_add(500, detect_house_sync_format_timer, user_data); - - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Attempting to detect house sync..."); - } else { - - /* - * the toggle button is no longer active: disable the timer - */ - - g_source_remove(ctk_framelock->house_format_detect_timer); - ctk_framelock->house_format_detect_timer = 0; + gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + + hbox = gtk_hbox_new(FALSE, 12); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + + pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG, NULL); + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Aborted house sync detection."); - } + ctk_framelock->remove_devices_label = gtk_label_new(NULL); -} /* detect_house_sync_format_toggled() */ + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), image); + gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); -/* - * When the use_house_sync button is released, check to see if we - * have a house signal (if applicable) then try to set the state of - * the hardware (i.e. P294). We do this as a release instead of a toggler - * because if - * the hardware change is not successful, we must toggle the button - * back, which would end up triggering toggle function from the toggle function. - */ + alignment = gtk_alignment_new(0.0, 0.0, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), + ctk_framelock->remove_devices_label); + gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0); -static void use_house_sync_released(GtkToggleButton *togglebutton, - gpointer user_data) -{ - - NvCtrlAttributeHandle *handle = NULL; - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - gboolean enabled; - gint val; - + return dialog; +} - enabled = gtk_toggle_button_get_active(togglebutton); - if (find_master(ctk_framelock, NULL, &handle)) - { - if (enabled) - { - if (( NvCtrlGetAttribute( - handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &val)) != - NvCtrlSuccess) - { - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Framelock could not determine house sync status."); - gtk_toggle_button_set_active(togglebutton, !enabled); - return; - } - else if (!val) - { - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Framelock could not find house sync signal."); - gtk_toggle_button_set_active(togglebutton, !enabled); - return; - } - } - if (( NvCtrlSetAttribute(handle, NV_CTRL_USE_HOUSE_SYNC, enabled)) != - NvCtrlSuccess) - { - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Framelock could not %sable house sync.", - enabled ? "en" : "dis"); - gtk_toggle_button_set_active(togglebutton, !enabled); - return; - } - } - else - { - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Framelock could not establish master."); - gtk_toggle_button_set_active(togglebutton, !enabled); - return; - } - gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, enabled); - gtk_widget_set_sensitive(ctk_framelock->house_format_frame, enabled); - - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Framelock %s house sync.", - enabled ? "using" : "not using"); - -} /* use_house_sync_released() */ +/************************************************************************/ /* - * add_house_sync_controls() - + * Helper functions */ -static GtkWidget *add_house_sync_controls(NvCtrlAttributeHandle *handle, CtkFramelock *ctk_framelock) + + +/** my_button_new_with_label() *************************************** + * + * Creates a button with padding. + * + */ +GtkWidget *my_button_new_with_label(const gchar *txt, + gint hpad, + gint vpad) { - GtkWidget *hboxroot; + GtkWidget *btn; GtkWidget *hbox; GtkWidget *vbox; - GtkWidget *hbox2; GtkWidget *label; - GtkWidget *check_button; - GList *glist; - gint val = 0; - gboolean use_house_sync_option = FALSE; - ReturnStatus ret; - - hboxroot = gtk_vbox_new(FALSE, 5); + btn = gtk_button_new(); + hbox = gtk_hbox_new(FALSE, 0); + vbox = gtk_vbox_new(FALSE, 0); + label = gtk_label_new(txt); - ctk_framelock->house_sync_frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hboxroot), ctk_framelock->house_sync_frame, - FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, hpad); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, vpad); + gtk_container_add(GTK_CONTAINER(btn), vbox); - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ctk_framelock->house_sync_frame),vbox); + return btn; +} - ctk_framelock->use_house_sync_button = NULL; - ret = NvCtrlGetAttribute(handle, NV_CTRL_USE_HOUSE_SYNC, &val); - if (ret == NvCtrlSuccess) { - use_house_sync_option = TRUE; - - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5); +/** my_toggle_button_new_with_label() ******************************** + * + * Creates a toggle button with padding. + * + */ +GtkWidget *my_toggle_button_new_with_label(const gchar *txt, + gint hpad, + gint vpad) +{ + GtkWidget *btn; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + + btn = gtk_toggle_button_new(); + hbox = gtk_hbox_new(FALSE, 0); + vbox = gtk_vbox_new(FALSE, 0); + label = gtk_label_new(txt); - label = gtk_label_new("Use House Sync"); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, hpad); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, vpad); + gtk_container_add(GTK_CONTAINER(btn), vbox); - check_button = gtk_check_button_new(); - gtk_container_add(GTK_CONTAINER(check_button), label); - ctk_framelock->use_house_sync_button = check_button; + return btn; +} - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), val); - gtk_box_pack_start(GTK_BOX(hbox), check_button, FALSE, FALSE, 5); - - // see callback definition for why we use "released" - g_signal_connect(G_OBJECT(check_button), "released", - G_CALLBACK(use_house_sync_released), - (gpointer) ctk_framelock); - } - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 5); - - /* sync interval */ +/** update_image() *************************************************** + * + * Updates the container to hold a duplicate of the given image. + * + */ +void update_image(GtkWidget *container, GtkWidget *new_image) +{ + GList *list; - ctk_framelock->sync_interval_frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->sync_interval_frame, - FALSE, TRUE, 5); - - hbox2 = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_interval_frame),hbox2); - - label = gtk_label_new("Sync Interval:"); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, TRUE, 5); - - ctk_framelock->sync_interval_entry = gtk_entry_new(); - gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry), "0"); - gtk_entry_set_width_chars - (GTK_ENTRY(ctk_framelock->sync_interval_entry), 4); - gtk_box_pack_start - (GTK_BOX(hbox2), ctk_framelock->sync_interval_entry, FALSE, TRUE, 5); + list = gtk_container_get_children(GTK_CONTAINER(container)); + if (list) { + gtk_container_remove(GTK_CONTAINER(container), + (GtkWidget *)(list->data)); + g_list_free(list); + } + gtk_box_pack_start(GTK_BOX(container), + ctk_image_dupe(GTK_IMAGE(new_image)), + FALSE, FALSE, 0); + gtk_widget_show_all(container); +} - g_signal_connect(G_OBJECT(ctk_framelock->sync_interval_entry), - "activate", G_CALLBACK(sync_interval_entry_activate), - (gpointer) ctk_framelock); - - /* house format */ - ctk_framelock->house_format_frame = gtk_frame_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), - ctk_framelock->house_format_frame, FALSE, TRUE, 0); - - hbox2 = gtk_hbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(ctk_framelock->house_format_frame), hbox2); - - label = gtk_label_new("House Sync Format:"); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, TRUE, 5); - - ctk_framelock->house_format_combo = gtk_combo_new(); - glist = NULL; - - glist = g_list_append - (glist, - houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO]); - - glist = g_list_append - (glist, - houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL]); - - glist = g_list_append - (glist, - houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL]); - - glist = g_list_append - (glist, houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL]); - - gtk_combo_set_popdown_strings - (GTK_COMBO(ctk_framelock->house_format_combo), glist); - gtk_editable_set_editable - (GTK_EDITABLE(GTK_COMBO(ctk_framelock->house_format_combo)->entry), - FALSE); - - g_signal_connect - (G_OBJECT(GTK_EDITABLE - (GTK_COMBO(ctk_framelock->house_format_combo)->entry)), - "changed", G_CALLBACK(house_sync_format_entry_activate), - (gpointer) ctk_framelock); - - gtk_box_pack_start(GTK_BOX(hbox2), - ctk_framelock->house_format_combo, FALSE, TRUE, 5); - /* detect button */ +/** get_display_name() *********************************************** + * + * Returns the name of the given display device. + * + * If 'simple' is 0, then the display device type will be + * included in the name returned. + * + */ +static gchar *get_display_name(nvDisplayDataPtr data, gboolean simple) +{ + ReturnStatus ret; + char *display_name; + char *display_type; + char *name; + + ret = NvCtrlGetStringDisplayAttribute(data->handle, + data->device_mask, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &display_name); + if (ret != NvCtrlSuccess) { + display_name = NULL; + } - ctk_framelock->house_format_detect = - gtk_toggle_button_new_with_label("Detect"); - gtk_box_pack_start(GTK_BOX(hbox2), - ctk_framelock->house_format_detect, FALSE, TRUE, 5); + display_type = + display_device_mask_to_display_device_name(data->device_mask); - g_signal_connect(G_OBJECT(ctk_framelock->house_format_detect), "toggled", - G_CALLBACK(detect_house_sync_format_toggled), - ctk_framelock); + if (simple) { + name = g_strconcat(display_name?display_name:"Unknown Display", + NULL); + } else { + name = g_strconcat(display_name?display_name:"Unknown Display", + " (", display_type, ")", NULL); + } - /* disable these controls until use_house_sync is selected */ - if (use_house_sync_option) - { - gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, FALSE); - gtk_widget_set_sensitive(ctk_framelock->house_format_frame, FALSE); + if (display_name) { + free(display_name); } - return hboxroot; - -} /* add_house_sync_controls() */ + return name; +} -/* - * update_house_sync_controls() - update the gui with the current - * sw-state of the house sync control values. +/** get_gpu_name() *************************************************** + * + * Returns the name of the given GPU. + * + * If 'simple' is 0, then the GPU ID will be included in the name + * returned. + * */ - -static void update_house_sync_controls(CtkFramelock *ctk_framelock) +static gchar *get_gpu_name(nvGPUDataPtr data, gboolean simple) { - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - gboolean house = FALSE, sensitive, use_house; - gint sync_interval, house_format; - gchar str[32]; - GtkTreeIter iter; - - if (find_master(ctk_framelock, &iter, NULL)) { - gtk_tree_model_get(model, &iter, - COLUMN_HOUSE, &house, - COLUMN_SYNC_INTERVAL, &sync_interval, - COLUMN_HOUSE_FORMAT, &house_format, - -1); - - snprintf(str, 32, "%d", sync_interval); - gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry),str); - - if (house_format < NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE) - house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE; - if (house_format > NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV) - house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; - - gtk_entry_set_text - (GTK_ENTRY(GTK_COMBO(ctk_framelock->house_format_combo)->entry), - houseFormatStrings[house_format]); + ReturnStatus ret; + char *product_name; + char tmp[32]; + char *name; + + ret = NvCtrlGetStringAttribute(data->handle, + NV_CTRL_STRING_PRODUCT_NAME, + &product_name); + if (ret != NvCtrlSuccess) { + product_name = NULL; } - use_house = TRUE; - - if (ctk_framelock->use_house_sync_button) - { - use_house = - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync_button)); - } + snprintf(tmp, 32, " (GPU %d)", NvCtrlGetTargetId(data->handle)); - if (ctk_framelock->framelock_enabled) - { - sensitive = FALSE; + if (simple) { + name = g_strconcat(product_name?product_name:"Unknown GPU", + NULL); } else { - sensitive = TRUE; + name = g_strconcat(product_name?product_name:"Unknown GPU", + tmp, NULL); } - // This includes the checkbutton for selecting house sync - gtk_widget_set_sensitive(ctk_framelock->house_sync_frame, sensitive); - - if (ctk_framelock->framelock_enabled || !use_house) { - sensitive = FALSE; - } else { - sensitive = TRUE; + if (product_name) { + free(product_name); } - - gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, sensitive); - gtk_widget_set_sensitive(ctk_framelock->house_format_frame, sensitive); - -} /* update_house_sync_controls() */ + + return name; +} -static void sync_interval_entry_activate(GtkEntry *entry, gpointer user_data) +/** get_framelock_name() ********************************************* + * + * Returns the name of the given frame lock (G-Sync) device. + * + */ +static char *get_framelock_name(nvFrameLockDataPtr data, gboolean simple) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - NvCtrlAttributeHandle *handle = NULL; - const gchar *str = gtk_entry_get_text(entry); - gint interval; - - interval = strtol(str, NULL, 10); + char *server_name; + char tmp[32]; + char *name; + + /* NOTE: The display name of a non-X Screen target will + * return the server name and server # only. + * (ie, it does not return a screen #) + */ + server_name = NvCtrlGetDisplayName(data->handle); + + snprintf(tmp, 32, " (G-Sync %d)", NvCtrlGetTargetId(data->handle)); - if (find_master(ctk_framelock, NULL, &handle)) { - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL, interval); - } + name = g_strconcat(server_name?server_name:"Unknown X Server", tmp, NULL); + + return name; } -static void house_sync_format_entry_activate(GtkEditable *editable, - gpointer user_data) + + +/** get_entry_label() ************************************************ + * + * Returns the correct label for the given entry. + * + */ +static gchar *get_entry_label(nvListEntryPtr entry, gboolean simple) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - const gchar *str = gtk_entry_get_text - (GTK_ENTRY(GTK_COMBO(ctk_framelock->house_format_combo)->entry)); - NvCtrlAttributeHandle *handle = NULL; - gint mode; + char *str = NULL; - for (mode = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE; - mode <= NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; mode++) { - - if (strcmp(houseFormatStrings[mode], str) == 0) { + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + str = get_framelock_name((nvFrameLockDataPtr)(entry->data), simple); + + } else if (entry->data_type == ENTRY_DATA_GPU) { + str = get_gpu_name((nvGPUDataPtr)(entry->data), simple); + + } else if (entry->data_type == ENTRY_DATA_DISPLAY) { + str = get_display_name((nvDisplayDataPtr)(entry->data), simple); - if (find_master(ctk_framelock, NULL, &handle)) { - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, mode); - } - return; - } } -} /* house_sync_format_entry_activate() */ + + return str; +} -/* - * add_columns_to_treeview() - add the columns to the treeview, - * assigning renderer functions as necessary +/** update_entry_label() ********************************************* + * + * Sets the correct label for the given entry. + * */ - -static void add_columns_to_treeview(CtkFramelock *ctk_framelock) +static void update_entry_label(CtkFramelock *ctk_framelock, nvListEntryPtr entry) { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - /* column for display name */ - - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes("Display", - renderer, - "text", - COLUMN_DISPLAY_NAME, - NULL); - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - - /* column for master toggles */ - - renderer = gtk_cell_renderer_toggle_new(); - gtk_cell_renderer_toggle_set_radio((GtkCellRendererToggle*)renderer, TRUE); - g_signal_connect(renderer, "toggled", - G_CALLBACK(master_toggled), ctk_framelock); - - column = gtk_tree_view_column_new_with_attributes("Master", - renderer, - "active", - COLUMN_MASTER, - NULL); - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); + char *str = NULL; + gboolean simple; + + simple = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_framelock->short_labels_button)); + + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + str = get_framelock_name((nvFrameLockDataPtr)(entry->data), simple); + gtk_label_set_text(GTK_LABEL + (((nvFrameLockDataPtr)(entry->data))->label), + str?str:"Unknown G-Sync"); + + } else if (entry->data_type == ENTRY_DATA_GPU) { + str = get_gpu_name((nvGPUDataPtr)(entry->data), simple); + gtk_label_set_text(GTK_LABEL + (((nvGPUDataPtr)(entry->data))->label), + str?str:"Unknown GPU"); + + } else if (entry->data_type == ENTRY_DATA_DISPLAY) { + str = get_display_name((nvDisplayDataPtr)(entry->data), simple); + gtk_label_set_text(GTK_LABEL + (((nvDisplayDataPtr)(entry->data))->label), + str?str:"Unknown Display"); + } + if (str) { + g_free(str); + } +} - /* column for stereo */ - - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("Stereo Sync", - renderer, - NULL); - - gtk_tree_view_column_set_cell_data_func(column, - renderer, - led_renderer_func, - GINT_TO_POINTER - (COLUMN_STEREO_SYNC), - NULL); - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - /* column for timing */ - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("Timing", - renderer, - NULL); +/** error_msg() ****************************************************** + * + * Displays an error message dialog using the error message dialog. + * + */ +static void error_msg(CtkFramelock *ctk_framelock, const gchar *fmt, ...) +{ + gchar *msg; - /* - * led_renderer_func() needs the ctk_framelock, but only when - * dealing with the Timing column; so hook a pointer to - * ctk_framelock off of this ViewColumn widget. - */ - - g_object_set_data(G_OBJECT(column), "ctk_framelock", ctk_framelock); + NV_VSNPRINTF(msg, fmt); - gtk_tree_view_column_set_cell_data_func(column, - renderer, - led_renderer_func, - GINT_TO_POINTER(COLUMN_TIMING), - NULL); + gtk_label_set_line_wrap(GTK_LABEL(ctk_framelock->error_msg_label), TRUE); + gtk_label_set_use_markup(GTK_LABEL(ctk_framelock->error_msg_label), TRUE); + gtk_label_set_markup(GTK_LABEL(ctk_framelock->error_msg_label), msg); + gtk_widget_show_all(ctk_framelock->error_msg_dialog); - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); + free(msg); +} - /* column for sync_ready */ - - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("Sync Ready", - renderer, - NULL); - - gtk_tree_view_column_set_cell_data_func(column, - renderer, - led_renderer_func, - GINT_TO_POINTER(COLUMN_SYNC_READY), - NULL); - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - - /* column for sync_rate */ - - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes("Sync Rate", - renderer, - NULL); - gtk_tree_view_column_set_cell_data_func(column, - renderer, - rate_renderer_func, - GINT_TO_POINTER(COLUMN_SYNC_RATE), - NULL); - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); +/** show_remove_devices_dialog() ************************************* + * + * Displays the remove devices dialog. + * + */ +static void show_remove_devices_dialog(GtkWidget *button, + CtkFramelock *ctk_framelock) +{ + nvListTreePtr tree; + nvListEntryPtr entry; + gchar *str = NULL, *label; + + tree = (nvListTreePtr)(ctk_framelock->tree); + entry = tree->selected_entry; - /* column for house */ - - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("House", - renderer, - NULL); - - gtk_tree_view_column_set_cell_data_func(column, - renderer, - led_renderer_func, - GINT_TO_POINTER(COLUMN_HOUSE), - NULL); - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); + if (!entry) return; + + label = get_entry_label(entry, 0); + if (!label) { + str = g_strconcat("Would you like to remove the selected entry " + "from the group?" + "\n\nNOTE: This will also remove any entries " + "under this one.", + NULL); + } else if (entry->nchildren) { + str = g_strconcat("Would you like to remove the following entry " + "from the group?\n\n<span weight=\"bold\" " + "size=\"larger\">", label, "</span>", + "\n\nNOTE: This will also remove any entries " + "under this one.", + NULL); + g_free(label); + } else { + str = g_strconcat("Would you like to remove the following entry " + "from the group?\n\n<span weight=\"bold\" " + "size=\"larger\">", label, "</span>", + NULL); + g_free(label); + } - /* column for rj45 port0 */ + gtk_label_set_line_wrap(GTK_LABEL(ctk_framelock->remove_devices_label), + TRUE); + gtk_label_set_use_markup(GTK_LABEL(ctk_framelock->remove_devices_label), + TRUE); + if (str) { + gtk_label_set_markup(GTK_LABEL(ctk_framelock->remove_devices_label), + str); + g_free(str); + } - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("Port0", - renderer, - NULL); - gtk_tree_view_column_set_cell_data_func(column, - renderer, - rj45_renderer_func, - GINT_TO_POINTER(COLUMN_RJ45_PORT0), - NULL); + gtk_widget_show_all(ctk_framelock->remove_devices_dialog); +} - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - /* column for rj45 port1 */ - - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes("Port1", - renderer, - NULL); - - gtk_tree_view_column_set_cell_data_func(column, - renderer, - rj45_renderer_func, - GINT_TO_POINTER(COLUMN_RJ45_PORT1), - NULL); - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - - - /* column for rising edge */ - - renderer = gtk_cell_renderer_toggle_new(); +/** get_framelock_server_entry() ************************************* + * + * Retrieves the frame lock list entry that is related to the currently + * selected server (display) list entry, if any. + * + */ +static nvListEntryPtr get_framelock_server_entry(nvListTreePtr tree) +{ + nvListEntryPtr entry; - g_signal_connect(renderer, "toggled", - G_CALLBACK(rising_edge_toggled), ctk_framelock); + if (!tree || !tree->server_entry) { + return NULL; + } + entry = tree->server_entry; + while (entry) { + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + return entry; + } + entry = entry->parent; + } - column = gtk_tree_view_column_new_with_attributes("Rising", renderer, - NULL); - gtk_tree_view_column_set_cell_data_func(column, renderer, - polarity_renderer_func, - GUINT_TO_POINTER(POLARITY_RISING), - NULL); - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - - - /* column for falling edge */ - - renderer = gtk_cell_renderer_toggle_new(); + return NULL; +} - g_signal_connect(renderer, "toggled", - G_CALLBACK(falling_edge_toggled), ctk_framelock); - column = gtk_tree_view_column_new_with_attributes("Falling", - renderer, - NULL); - gtk_tree_view_column_set_cell_data_func(column, renderer, - polarity_renderer_func, - GUINT_TO_POINTER(POLARITY_FALLING), - NULL); - - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); - - /* column for sync skew */ - - renderer = gtk_cell_renderer_text_new(); +/** get_gpu_server_entry() ******************************************* + * + * Retrieves the GPU list entry that is related to the currently + * selected server (display) list entry, if any. + * + */ +static nvListEntryPtr get_gpu_server_entry(nvListTreePtr tree) +{ + nvListEntryPtr entry; - g_signal_connect(renderer, "edited", - G_CALLBACK(sync_skew_edited), ctk_framelock); - - column = gtk_tree_view_column_new_with_attributes("Sync Skew", - renderer, - "text", - COLUMN_SYNC_SKEW, - "editable", - TRUE, - NULL); - - gtk_tree_view_column_set_cell_data_func(column, - renderer, - sync_skew_renderer_func, - GINT_TO_POINTER(COLUMN_SYNC_SKEW), - NULL); - - gtk_tree_view_append_column(ctk_framelock->treeview, column); - gtk_tree_view_column_set_resizable(column, TRUE); + if (!tree || !tree->server_entry) { + return NULL; + } + entry = tree->server_entry; + while (entry) { + if (entry->data_type == ENTRY_DATA_GPU) { + return entry; + } + entry = entry->parent; + } -} /* add_columns_to_treeview() */ + return NULL; +} -/* - * led_renderer_func() - set the cell's pixbuf to either a green or a - * red LED, based on the value in the model for this iter. +/** get_display_server_entry() *************************************** + * + * Retrieves the display list entry that is the currently selected + * server. + * */ +static nvListEntryPtr get_display_server_entry(nvListTreePtr tree) +{ + return tree->server_entry; +} + + -static void led_renderer_func(GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) +/** list_entry_update_framelock_controls() *************************** + * + * Updates a G-Sync list entry's GUI controls based on the current + * frame lock status. + * + */ +static void list_entry_update_framelock_controls(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) { - static GdkPixbuf *led_green_pixbuf = NULL; - static GdkPixbuf *led_red_pixbuf = NULL; - static GdkPixbuf *led_grey_pixbuf = NULL; - gboolean value, master, framelock_enabled, use_house; - gpointer obj; - gint column, house = 0; + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + gboolean framelock_enabled = ctk_framelock->framelock_enabled; - /* - * we hooked a pointer to the ctk_framelock off the ViewColumn - * widget - */ + gboolean show_all = + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_framelock->extra_info_button)); - obj = g_object_get_data(G_OBJECT(tree_column), "ctk_framelock"); + /* Show/Hide frame lock widgets */ + if (show_all) { + gtk_widget_show(data->extra_info_hbox); + } else { + gtk_widget_hide(data->extra_info_hbox); + } - column = GPOINTER_TO_INT(data); + /* Activate Sync Rate when frame lock is enabled */ + gtk_widget_set_sensitive(data->rate_label, framelock_enabled); + gtk_widget_set_sensitive(data->rate_text, framelock_enabled); - gtk_tree_model_get(model, iter, column, &value, - COLUMN_MASTER, &master, -1); + /* Activate Sync Delay when frame lock is enabled */ + gtk_widget_set_sensitive(data->delay_label, framelock_enabled); + gtk_widget_set_sensitive(data->delay_text, framelock_enabled); +} + + - framelock_enabled = FALSE; - use_house = TRUE; - if (obj) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(obj); - if (ctk_framelock->framelock_enabled) framelock_enabled = TRUE; - if (ctk_framelock->use_house_sync_button) { - use_house = - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync_button)); +/** list_entry_update_display_controls() ***************************** + * + * Updates a display device list entry's GUI controls based on + * current frame lock status. + * + */ +static void list_entry_update_display_controls(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + nvDisplayDataPtr data = (nvDisplayDataPtr)(entry->data); + gboolean framelock_enabled = ctk_framelock->framelock_enabled; + gboolean server_checked; + gboolean client_checked; + gboolean sensitive; + + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr server_entry = get_display_server_entry(tree); + nvDisplayDataPtr server_data = NULL; + + + if (server_entry) { + server_data = (nvDisplayDataPtr)(server_entry->data); + if (!server_data) { + return; /* Oops */ } } - gtk_tree_model_get(model, iter, COLUMN_HOUSE, &house, -1); + server_checked = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(data->server_checkbox)); + client_checked = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(data->client_checkbox)); - /* - * make the master's Timing LED grey if framelock is enabled - * (otherwise, it will be red when framelock is enabled, which is - * confusing). - * - * If we are receiving house sync, then light the LED green, unless - * the user has opted to not use it (e.g. p294) + /* Server Checkbox is unavailable when framelock is disabled, + * this display is set as client, this display cannot be master + * (display is driven by GPU that is connected through a + * secondary connector.), or another server is already selected. */ - - if ((column == COLUMN_TIMING) && master && framelock_enabled && - (!house || !use_house)) { - if (!led_grey_pixbuf) - led_grey_pixbuf = gdk_pixbuf_new_from_xpm_data(led_grey_xpm); - g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", led_grey_pixbuf, NULL); - } else if (value || (house && framelock_enabled && master)) { - if (!led_green_pixbuf) - led_green_pixbuf = gdk_pixbuf_new_from_xpm_data(led_green_xpm); - g_object_set(GTK_CELL_RENDERER(cell), - "pixbuf", led_green_pixbuf, NULL); - } else { - if (!led_red_pixbuf) - led_red_pixbuf = gdk_pixbuf_new_from_xpm_data(led_red_xpm); - g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", led_red_pixbuf, NULL); + sensitive = (!framelock_enabled && + !client_checked && + data->masterable && + (!server_entry || data == server_entry->data)); + gtk_widget_set_sensitive(data->server_label, sensitive); + gtk_widget_set_sensitive(data->server_checkbox, sensitive); + + /* When a server is selected, this display can only become a + * client if its refresh rate matches that of the client. + */ + sensitive = (!framelock_enabled && + !server_checked && + (!server_data || data->rate == server_data->rate)); + gtk_widget_set_sensitive(data->client_label, sensitive); + gtk_widget_set_sensitive(data->client_checkbox, sensitive); + + /* Gray out the display device's refresh rate when it is not + * the same as the current server's. + */ + sensitive = (!server_data || data->rate == server_data->rate); + gtk_widget_set_sensitive(data->rate_label, sensitive); + gtk_widget_set_sensitive(data->rate_text, sensitive); + + /* Remove display device from clients list */ + if (!sensitive && gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(data->client_checkbox))) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(data->client_checkbox), + FALSE); + ((nvGPUDataPtr)(entry->parent->data))->clients_mask &= + data->device_mask; } -} /* led_renderer_func() */ +} -/* - * rj45_renderer_func() - set the cell's pixbuf either to the "input" - * rj45 pixbuf or the "output" rj45 pixbuf, based on the value in the - * model for this iter. +/** list_entry_update_controls() ************************************* + * + * Updates the controls in the given entry list to reflect frame lock + * sync status. This function is used to disable access to some + * widgets while frame lock sync is enabled. * - * XXX should there be an "unknown" state? */ +static void list_entry_update_controls(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + if (!entry) return; + + list_entry_update_controls(ctk_framelock, entry->children); + + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + list_entry_update_framelock_controls(ctk_framelock, entry); + + } else if (entry->data_type == ENTRY_DATA_GPU) { + /* Do nothing */ + + } else if (entry->data_type == ENTRY_DATA_DISPLAY) { + list_entry_update_display_controls(ctk_framelock, entry); + } -static void rj45_renderer_func(GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) + list_entry_update_controls(ctk_framelock, entry->next_sibling); +} + + + +/** update_framelock_controls() ************************************** + * + * Enable/disable access to various GUI controls on the frame lock + * page depending on the state of frame lock sync (frame lock + * enabled/disabled). Also validates on client refresh rates + * vs server refresh rate. + * + */ +static void update_framelock_controls(CtkFramelock *ctk_framelock) { - static GdkPixbuf *rj45_input_pixbuf = NULL; - static GdkPixbuf *rj45_output_pixbuf = NULL; - gboolean value; - gint column; + nvListTreePtr tree; + gboolean enabled; + + + tree = (nvListTreePtr)(ctk_framelock->tree); + enabled = ctk_framelock->framelock_enabled; - column = GPOINTER_TO_INT(data); + /* G-Sync Buttons */ + gtk_widget_set_sensitive(ctk_framelock->remove_devices_button, + tree->nentries); - gtk_tree_model_get (model, iter, column, &value, -1); + gtk_widget_set_sensitive(ctk_framelock->extra_info_button, + tree->nentries); - if (value == NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT) { - if (!rj45_input_pixbuf) - rj45_input_pixbuf = gdk_pixbuf_new_from_xpm_data(rj45_input_xpm); - g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", - rj45_input_pixbuf, NULL); + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->sync_state_button), + G_CALLBACK(toggle_sync_enable), + (gpointer) ctk_framelock); + + gtk_widget_set_sensitive(ctk_framelock->sync_state_button, + tree->nentries); + + gtk_container_remove + (GTK_CONTAINER(ctk_framelock->sync_state_button), + ctk_framelock->selected_syncing_label); + + if (tree->nentries && enabled) { + ctk_framelock->selected_syncing_label = + ctk_framelock->disable_syncing_label; + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->sync_state_button), TRUE); } else { - if (!rj45_output_pixbuf) - rj45_output_pixbuf = gdk_pixbuf_new_from_xpm_data(rj45_output_xpm); - g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", - rj45_output_pixbuf, NULL); + ctk_framelock->selected_syncing_label = + ctk_framelock->enable_syncing_label; + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->sync_state_button), FALSE); } -} /* rj45_renderer_func() */ + gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_state_button), + ctk_framelock->selected_syncing_label); + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->sync_state_button), + G_CALLBACK(toggle_sync_enable), + (gpointer) ctk_framelock); -/* - * rate_renderer_func() - set the cell's "text" attribute to a string - * representation of the rate in the model at this iter. - */ + gtk_widget_show_all(ctk_framelock->sync_state_button); -static void rate_renderer_func(GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - gint column = GPOINTER_TO_INT(data); - guint value; - gfloat fvalue; - gchar str[32]; + /* Test link */ + gtk_widget_set_sensitive(ctk_framelock->test_link_button, + (enabled && tree->server_entry)); + + /* Update the frame lock G-Sync frame */ + list_entry_update_controls(ctk_framelock, tree->entries); + + /* House Sync */ + update_house_sync_controls(ctk_framelock); +} - gtk_tree_model_get (model, iter, column, &value, -1); - fvalue = (float) value / 1000.0; - snprintf(str, 32, "%6.2f Hz", fvalue); +/** get_display_on_gpu() ********************************************* + * + * Returns the display list entry that matches the device mask and + * is connected to the gpu list entry. + * + */ +static nvListEntryPtr get_display_on_gpu(nvListEntryPtr gpu_entry, + guint device_mask) +{ + nvListEntryPtr display_entry; + nvDisplayDataPtr display_data; - g_object_set(GTK_CELL_RENDERER(cell), "text", str, NULL); + if (!device_mask) { + return NULL; + } -} /* rate_renderer_func() */ + /* Gather bitmask of server/clients */ + display_entry = gpu_entry->children; + for (display_entry = gpu_entry->children; display_entry; + display_entry = display_entry->next_sibling) { + if (display_entry->data_type != ENTRY_DATA_DISPLAY) { + continue; + } + + display_data = (nvDisplayDataPtr)(display_entry->data); + if (display_data->device_mask & device_mask) { + return display_entry; + } + } + return NULL; +} -/* - * polarity_renderer_func() - set the attribute "active" to either - * true or false, based on if the bit specified in mask is present in - * the model for this iter. - */ -static void polarity_renderer_func(GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) +/** any_gpu_enabled() ************************************************ + * + * Returns TRUE if any of the gpus have frame lock enabled. + * + */ +static gboolean any_gpu_enabled(nvListEntryPtr entry) { - guint value, mask = GPOINTER_TO_UINT(data); - - gtk_tree_model_get(model, iter, COLUMN_POLARITY, &value, -1); - - if (value & mask) { - g_object_set(GTK_CELL_RENDERER(cell), "active", TRUE, NULL); - } else { - g_object_set(GTK_CELL_RENDERER(cell), "active", FALSE, NULL); + if (!entry) return FALSE; + + if (entry->data_type == ENTRY_DATA_GPU && + ((nvGPUDataPtr)(entry->data))->enabled) { + return TRUE; } -} /* polarity_renderer_func() */ + if (any_gpu_enabled(entry->children)) { + return TRUE; + } + if (any_gpu_enabled(entry->next_sibling)) { + return TRUE; + } + + return FALSE; +} + + + +/************************************************************************/ /* - * sync_skew_renderer_func() - set the cell's "text" attribute to a - * string representation of the sync delay in the model at this iter. + * List Entry functions */ -static void sync_skew_renderer_func(GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) + +/** do_select_framelock_data() *************************************** + * + * This function defines how to set all the widgets in a frame lock + * row as "selected" or "not selected" + * + */ +static void do_select_framelock_data(nvFrameLockDataPtr data, gint select) { - gint column = GPOINTER_TO_INT(data); - guint value; - gchar str[32]; - gfloat delay; - - gtk_tree_model_get (model, iter, column, &value, -1); + if (!data) { + return; + } + SELECT_WIDGET(data->label, select); + SELECT_WIDGET(data->receiving_label, select); + SELECT_WIDGET(data->rate_label, select); + SELECT_WIDGET(data->rate_text, select); + SELECT_WIDGET(data->delay_label, select); + SELECT_WIDGET(data->delay_text, select); + SELECT_WIDGET(data->house_label, select); + SELECT_WIDGET(data->port0_label, select); + SELECT_WIDGET(data->port1_label, select); +} - delay = ((gfloat) value) * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR; - snprintf(str, 32, "%10.2f uS", delay); - - g_object_set (GTK_CELL_RENDERER(cell), "text", str, NULL); - -} /* sync_skew_renderer_func() */ +/** do_select_gpu_data() ********************************************* + * + * This function defines how to set all the widgets in a GPU + * row as "selected" or "not selected" + * + */ +static void do_select_gpu_data(nvGPUDataPtr data, gint select) +{ + if (!data) { + return; + } + SELECT_WIDGET(data->label, select); +} -/* - * master_toggled() - called whenever a master is assigned. + +/** do_select_display_data() ***************************************** + * + * This function defines how to set all the widgets in a display + * device row as "selected" or "not selected" + * */ +static void do_select_display_data(nvDisplayDataPtr data, gint select) +{ + if (!data) { + return; + } + SELECT_WIDGET(data->label, select); + SELECT_WIDGET(data->server_label, 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); +} + -static void master_toggled(GtkCellRendererToggle *cell, - gchar *path_str, - gpointer data) + +/** list_entry_set_select() ****************************************** + * + * This function sets which entry in the list is selected. If an + * entry is already selected, it is unselected recursively. + * + */ +static void list_entry_set_select(nvListEntryPtr entry, gint selected) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(data); - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - GtkTreeIter iter, walking_iter; - GtkTreePath *path = gtk_tree_path_new_from_string(path_str); - gboolean master, valid; - gchar *display_name; + gint state; + + if (!entry || !entry->tree) { + return; + } + + + /* Do the selection */ + if (selected) { + state = GTK_STATE_SELECTED; + if (entry->tree->selected_entry) { + /* Unselect previous entry */ + list_entry_set_select((nvListEntryPtr)(entry->tree->selected_entry), False); + } + entry->tree->selected_entry = (void *)entry; + } else { + state = GTK_STATE_NORMAL; + entry->tree->selected_entry = NULL; + } + + /* Update the state of the entry's widgets */ - NvCtrlAttributeHandle *handle; + SELECT_WIDGET(entry->vp, state); + + if (!entry->data) { + return; + } + switch (entry->data_type) { + case ENTRY_DATA_FRAMELOCK: + do_select_framelock_data((nvFrameLockDataPtr)(entry->data), state); + break; + case ENTRY_DATA_GPU: + do_select_gpu_data((nvGPUDataPtr)(entry->data), state); + break; + case ENTRY_DATA_DISPLAY: + do_select_display_data((nvDisplayDataPtr)(entry->data), state); + break; + default: + break; + } +} - /* do not change the master while framelock is enabled */ - if (ctk_framelock->framelock_enabled) { - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Cannot change master while " - "FrameLock is enabled."); + +/** list_entry_clicked() ********************************************* + * + * Called on the entry that the user clicked on. + * + */ +static void list_entry_clicked(GtkWidget *widget, GdkEventButton *event, + gpointer user_data) +{ + nvListEntryPtr entry = (nvListEntryPtr)(user_data); + + if (!entry || !entry->tree) { return; } + if (entry != entry->tree->selected_entry) { + list_entry_set_select(entry, True); + } +} - /* get toggled iter */ - - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_path_free(path); - - /* if we're already the master, do nothing */ - gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master, - COLUMN_DISPLAY_NAME, &display_name, -1); - - if (master) return; - - /* walk through the model, and turn off any other masters */ - valid = gtk_tree_model_get_iter_first(model, &walking_iter); - while (valid) { - gboolean walking_master; - gtk_tree_model_get(model, &walking_iter, - COLUMN_MASTER, &walking_master, -1); +/** expander_button_clicked() **************************************** + * + * - Handles button clicks on an nvListEntry's expantion button + * widget. + * + * This function either shows or hides the list entry's children + * based on the state of the expansion widget. + * + */ +static void expander_button_clicked(GtkWidget *widget, gpointer user_data) +{ + nvListEntryPtr entry = (nvListEntryPtr) user_data; + + + if (entry->expanded) { + /* Collapse */ + gtk_container_remove(GTK_CONTAINER(entry->button), + entry->button_image); + entry->button_image = + gtk_image_new_from_stock(GTK_STOCK_ADD, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_size_request(entry->button, 20, 20); - if (walking_master) { - gtk_tree_model_get(model, &walking_iter, - COLUMN_HANDLE, &handle, -1); - if (handle) { - gtk_list_store_set(GTK_LIST_STORE(model), &walking_iter, - COLUMN_MASTER, FALSE, -1); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER, - NV_CTRL_FRAMELOCK_MASTER_FALSE); - } - } + gtk_container_add(GTK_CONTAINER(entry->button), entry->button_image); + gtk_widget_show_all(entry->button); + gtk_widget_hide(entry->child_hbox); - valid = gtk_tree_model_iter_next(model, &walking_iter); + } else { + /* Expand */ + gtk_container_remove(GTK_CONTAINER(entry->button), + entry->button_image); + entry->button_image = + gtk_image_new_from_stock(GTK_STOCK_REMOVE, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_size_request(entry->button, 20, 20); + + gtk_container_add(GTK_CONTAINER(entry->button), entry->button_image); + gtk_widget_show_all(entry->button); + gtk_widget_show(entry->child_hbox); } - - /* set new value */ - gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_MASTER, - TRUE, -1); - - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER, - NV_CTRL_FRAMELOCK_MASTER_TRUE); - - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "X Screen '%s' assigned master.", - display_name); - update_house_sync_controls(ctk_framelock); - -} /* master_toggled() */ + entry->expanded = !(entry->expanded); +} + -static void polarity_toggled(GtkCellRendererToggle *cell, - CtkFramelock *ctk_framelock, - gchar *path_string, - guint mask) + +/** list_entry_add_expander_button() ********************************* + * + * - Adds a button to the left of a list entry's main data row. + * + * This button is used to show/hide the list entry's children. + * + */ +static void list_entry_add_expander_button(nvListEntryPtr entry) { - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - GtkTreePath *path; - GtkTreeIter iter; - gint polarity; - gboolean enabled; - NvCtrlAttributeHandle *handle; - gchar *polarity_str; + if (!entry || entry->button) { + return; + } - path = gtk_tree_path_new_from_string(path_string); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_path_free(path); + entry->button = gtk_button_new(); + entry->button_image = + gtk_image_new_from_stock(GTK_STOCK_REMOVE, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_set_size_request(entry->button, 20, 20); + entry->expanded = True; + + g_signal_connect(G_OBJECT(entry->button), "clicked", + G_CALLBACK(expander_button_clicked), + (gpointer) entry); - gtk_tree_model_get(model, &iter, COLUMN_POLARITY, &polarity, -1); + gtk_container_add(GTK_CONTAINER(entry->button), entry->button_image); + gtk_box_pack_start(GTK_BOX(entry->parent_hbox), entry->button, + FALSE, FALSE, 0); +} - g_object_get(GTK_CELL_RENDERER(cell), "active", &enabled, NULL); - enabled ^= 1; - if (enabled) polarity |= mask; - else polarity &= ~mask; - +/** list_entry_remove_expander_button() ****************************** + * + * - Removes the button that is to the left of a list entry's main + * data row. + * + * When a list entry has no more children, the expander button + * should be removed. + * + */ +static void list_entry_remove_expander_button(nvListEntryPtr entry) +{ + if (!entry || !entry->button) { + return; + } + + gtk_container_remove(GTK_CONTAINER(entry->parent_hbox), entry->button); + entry->button = NULL; +} + - /* if the last bit was turned off, turn back on the other bit */ - if (!polarity) { - if (mask == NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE) - polarity = NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE; - if (mask == NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE) - polarity = NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE; +/** list_entry_new() ************************************************* + * + * - Creates and returns a list entry. List entries are how rows of + * a tree keep their parent-child relationship. + * + */ +static nvListEntryPtr list_entry_new(void) +{ + nvListEntryPtr entry; + + entry = (nvListEntryPtr) calloc(1, sizeof(nvListEntryRec)); + if (!entry) { + return NULL; } - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_POLARITY, polarity, -1); - - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1); - - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_POLARITY, polarity); + /* Create the box that holds everything */ + entry->vbox = gtk_vbox_new(FALSE, 0); - switch (polarity) { - case NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE: - polarity_str = "rising"; - break; - case NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE: - polarity_str = "falling"; - break; - case NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES: - polarity_str = "rising and falling"; - break; - default: + /* Create the top row that holds the entry data */ + + entry->parent_hbox = gtk_hbox_new(FALSE, 0); + entry->data_hbox = gtk_hbox_new(FALSE, 0); + + entry->vp = gtk_event_box_new(); + SELECT_WIDGET(entry->vp, GTK_STATE_NORMAL); + gtk_container_add(GTK_CONTAINER(entry->vp), + GTK_WIDGET(entry->parent_hbox)); + + gtk_widget_set_events(entry->vp, GDK_BUTTON_PRESS_MASK); + g_signal_connect(G_OBJECT(entry->vp), "button_press_event", + G_CALLBACK(list_entry_clicked), + (gpointer) entry); + + gtk_box_pack_end(GTK_BOX(entry->parent_hbox), entry->data_hbox, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(entry->vbox), entry->vp, TRUE, TRUE, 0); + + return entry; +} + + + +/** list_entry_free() ************************************************ + * + * - Frees an existing list entry. + * + */ +static void list_entry_free(nvListEntryPtr entry) +{ + if (!entry) { return; } - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Set edge polarity to %s.", polarity_str); + /* XXX DON"T Need these? + gtk_widget_destroy(entry->vbox); + gtk_widget_destroy(entry->parent_hbox); + gtk_widget_destroy(entry->data_hbox); + gtk_widget_destroy(entry->vp); + */ + + free(entry); } -static void rising_edge_toggled(GtkCellRendererToggle *cell, - gchar *path_string, - gpointer user_data) + + +/** list_entry_add_child() ******************************************* + * + * - Adds the given child list entry to the parent list entry. + * If this is the first child to be added, an expansion button will + * be created for the parent. + * + */ +static void list_entry_add_child(nvListEntryPtr parent, nvListEntryPtr child) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListEntryPtr entry; + + if (!parent || !child) { + return; + } + + /* Add the child into the paren't child list */ - polarity_toggled(cell, ctk_framelock, path_string, POLARITY_RISING); + child->parent = parent; + child->tree = parent->tree; + if (!parent->children) { + parent->children = child; + } else { + entry = parent->children; + while (entry->next_sibling) { + entry = entry->next_sibling; + } + entry->next_sibling = child; + } + + /* If this is the parent's first child, create the expansion button + * and child box that will hold the children. + */ + + parent->nchildren++; + if (parent->nchildren == 1) { + GtkWidget *padding; + + /* Create the child box */ + + parent->child_hbox = gtk_hbox_new(FALSE, 0); + padding = gtk_hbox_new(FALSE, 0); + parent->child_vbox = gtk_vbox_new(FALSE, 5); + + gtk_widget_set_size_request(padding, 25, -1); + + gtk_box_pack_start(GTK_BOX(parent->child_hbox), + padding, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(parent->child_hbox), + parent->child_vbox, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(parent->vbox), + parent->child_hbox, FALSE, FALSE, 0); + gtk_widget_show(parent->child_hbox); + gtk_widget_show(parent->child_vbox); + gtk_widget_show(padding); + + /* Create the expansion button */ + + list_entry_add_expander_button(parent); + gtk_widget_show(parent->button); + } + + /* Pack the child into the parent's child box */ + + gtk_box_pack_start(GTK_BOX(parent->child_vbox), + child->vbox, FALSE, FALSE, 0); } -static void falling_edge_toggled(GtkCellRendererToggle *cell, - gchar *path_string, - gpointer user_data) + + +/** list_entry_associate() ******************************************* + * + * - Associates an entry (and all its children) to a tree (or no + * tree). Also makes sure that the tree being unassociated + * no longer references the entry (or any of its children). + * + * - Mainly, this is a helper function for adding and removing + * branches from trees. + * + */ +static void list_entry_associate(nvListEntryPtr entry, nvListTreePtr tree) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListEntryPtr child; + + if (!entry) { + return; + } - polarity_toggled(cell, ctk_framelock, path_string, POLARITY_FALLING); + /* Remove references to the entry from the old tree */ + if (entry->tree && entry->tree != tree) { + + /* Unselect ourself */ + if (entry == entry->tree->selected_entry) { + entry->tree->selected_entry = NULL; + } + + /* Remove master entry */ + if (entry == entry->tree->server_entry) { + entry->tree->server_entry = NULL; + } + } + + /* Associate entry's children to the new tree */ + entry->tree = tree; + child = entry->children; + while ( child ) { + list_entry_associate(child, tree); + child = child->next_sibling; + } } -static void sync_skew_edited(GtkCellRendererText *cell, - const gchar *path_string, - const gchar *new_text, - gpointer data) + +/** list_entry_unparent() ******************************************** + * + * - Removes the given child entry from its parent. If this is the + * last child to be removed, the parent's expansion button will be + * removed. + * + */ +static void list_entry_unparent(nvListEntryPtr child) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(data); - NvCtrlAttributeHandle *handle; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - gfloat delay; - gint value; + nvListEntryPtr entry; + nvListEntryPtr prev; + nvListEntryPtr parent; + + if (!child || !child->parent) { + return; + } + + /* Find the child in the parent list */ - delay = strtod(new_text, (char **)NULL); + parent = child->parent; + entry = parent->children; + prev = parent; + while (entry) { + if (entry == child) { + break; + } + prev = entry; + entry = entry->next_sibling; + } + if (!entry) { + return; /* Child not found! */ + } - value = (gint) (delay / NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR); + /* Remove the child from the parent list */ + if (prev == parent) { + parent->children = entry->next_sibling; + } else { + prev->next_sibling = entry->next_sibling; + } + list_entry_associate(child, NULL); + child->parent = NULL; - if (value < 0) value = 0; - if (value > NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX) - value = NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX; - - delay = ((gfloat) value) * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR; - - model = GTK_TREE_MODEL(ctk_framelock->list_store); - path = gtk_tree_path_new_from_string(path_string); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_path_free(path); + /* Unpack the child from the parent's child box */ - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_SYNC_SKEW, value, -1); - - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1); + gtk_container_remove(GTK_CONTAINER(parent->child_vbox), child->vbox); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_DELAY, value); + /* If this was the parent's last child, remove the expansion button + * and the child boxes used to hold children. + */ - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Sync delay set to %.2f uS", delay); + parent->nchildren--; + if (parent->nchildren == 0) { + gtk_container_remove(GTK_CONTAINER(parent->vbox), parent->child_hbox); + parent->child_hbox = NULL; + parent->child_vbox = NULL; + list_entry_remove_expander_button(parent); + } } -/************************************************************************/ -/* - * functions relating to add_x_screen_dialog +/** list_entry_remove_children() ************************************* + * + * - Removes all children from the given list entry. This call is + * recursive (children's children will also be removed) + * */ +static void list_entry_remove_children(nvListEntryPtr entry) +{ + while (entry->children) { + nvListEntryPtr child = entry->children; + /* Remove this child's children. */ + list_entry_remove_children(child); + + /* Unparent this child and free it */ + list_entry_unparent(child); + list_entry_free(child); + } +} -/* - * add_x_screen_response() - this function gets called in response to - * the "response" event from the "Add X Screen..." dialog box. - */ -static void add_x_screen_response(GtkWidget *button, gint response, - gpointer user_data) + +/** list_entry_new_with_framelock() ********************************** + * + * - Creates a new list entry that will hold the given frame lock + * data. + * + */ +static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - const gchar *display_name; + nvListEntryPtr entry = list_entry_new(); + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *vseparator; + GtkWidget *padding; + + if (!entry) { + return NULL; + } + entry->data = (gpointer)(data); + entry->data_type = ENTRY_DATA_FRAMELOCK; + + /* Pack the data's widgets into the list entry data hbox */ - /* hide the dialog box */ - - gtk_widget_hide_all(ctk_framelock->add_x_screen_dialog); + gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label, FALSE, FALSE, 5); + + hbox = gtk_hbox_new(FALSE, 5); + padding = gtk_hbox_new(FALSE, 0); - /* set the focus back to the text entry */ + frame = gtk_frame_new(NULL); + gtk_box_pack_end(GTK_BOX(entry->data_hbox), frame, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(entry->data_hbox), padding, FALSE, FALSE, 10); - gtk_widget_grab_focus(ctk_framelock->add_x_screen_entry); + gtk_container_set_border_width(GTK_CONTAINER(hbox), 2); + gtk_container_add(GTK_CONTAINER(frame), hbox); - /* if the response is not "OK" then we're done */ + gtk_box_pack_start(GTK_BOX(hbox), data->receiving_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->receiving_hbox, FALSE, FALSE, 0); + + vseparator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); - if (response != GTK_RESPONSE_OK) return; + gtk_box_pack_start(GTK_BOX(hbox), data->rate_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->rate_text, FALSE, FALSE, 0); + + vseparator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); - /* get the display name specified by the user */ + gtk_box_pack_start(GTK_BOX(hbox), data->house_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->house_hbox, FALSE, FALSE, 0); - display_name = - gtk_entry_get_text(GTK_ENTRY(ctk_framelock->add_x_screen_entry)); + vseparator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0); - add_x_screen(ctk_framelock, display_name, TRUE); + gtk_box_pack_start(GTK_BOX(hbox), data->port0_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->port0_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->port1_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->port1_hbox, FALSE, FALSE, 0); + + /* Extra Info Section */ + + gtk_box_pack_start(GTK_BOX(hbox), data->extra_info_hbox, 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->delay_label, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), data->delay_text, + FALSE, FALSE, 0); + + return entry; } -static gpointer add_x_screen(CtkFramelock *ctk_framelock, - const gchar *display_name, gboolean error_dialog) + +/** list_entry_new_with_gpu() **************************************** + * + * - Creates a new list entry that will hold the given gpu data. + * + */ +static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data) { - GtkTreeModel *model; - GtkTreeIter iter; - gpointer h; - Display *display; - gint screen, value; - gboolean valid; - const gchar *tmp; + nvListEntryPtr entry = list_entry_new(); - /* if no display name specified, print an error and return */ + if (!entry) { + return NULL; + } + entry->data = (gpointer)(data); + entry->data_type = ENTRY_DATA_GPU; - if (!display_name || (display_name[0] == '\0')) { + /* Pack the data's widgets into the list entry data hbox */ + + gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label, + FALSE, FALSE, 5); - if (error_dialog) { - error_msg(ctk_framelock, "<span weight=\"bold\" size=\"larger\">" - "Unable to add X screen to FrameLock group.</span>\n\n" - "No X Screen specified."); - } else { - nv_error_msg("Unable to add X screen to FrameLock group; " - "no X Screen specified."); - } + return entry; +} + + + +/** list_entry_new_with_display() ************************************ + * + * - Creates a new list entry that will hold the given display data. + * + */ +static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data) +{ + nvListEntryPtr entry = list_entry_new(); + + if (!entry) { return NULL; } + entry->data = (gpointer)(data); + entry->data_type = ENTRY_DATA_DISPLAY; - /* - * try to prevent users from adding the same X screen more than - * once XXX this is not an absolute check: this does not catch - * "localhost:0.0" versus ":0.0", for example. - */ + /* Pack the data's widgets into the list entry data hbox */ - model = GTK_TREE_MODEL(ctk_framelock->list_store); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_DISPLAY_NAME, &tmp, -1); - if (nv_strcasecmp(display_name, tmp)) { - if (error_dialog) { - error_msg(ctk_framelock, "<span weight=\"bold\" " - "size=\"larger\">Unable to add X screen " - "to FrameLock Group</span>\n\n" - "The X screen %s already belongs to the FrameLock " - "Group.", display_name); - } else { - nv_error_msg("Unable to add X screen to FrameLock Group; " - "the X screen %s already belongs to the " - "FrameLock Group.", display_name); - } - return NULL; - } - valid = gtk_tree_model_iter_next(model, &iter); + gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label, + FALSE, FALSE, 5); + + { + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *vseparator; + + 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->server_checkbox, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->server_label, 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->client_checkbox, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->client_label, 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->rate_label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), data->rate_text, 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->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); } - /* open an X Display connection to that X screen */ - - display = XOpenDisplay(display_name); - if (!display) { - if (error_dialog) { - error_msg(ctk_framelock, "<span weight=\"bold\" " - "size=\"larger\">Unable " - "to add X screen to FrameLock group</span>\n\nUnable to " - "connect to X Display '%s'.", display_name); - } else { - nv_error_msg("Unable to add X screen to FrameLock group; unable " - "to connect to X Display '%s'.", display_name); - } + return entry; +} + + + +/************************************************************************/ + +/* + * functions relating to List Trees + */ + + +/** list_tree_new() ************************************************** + * + * - Creates a new list tree that will hold list entries. + * + */ +static nvListTreePtr list_tree_new(CtkFramelock *ctk_framelock) +{ + nvListTreePtr tree; + + tree = (nvListTreePtr) calloc(1, sizeof(nvListTreeRec)); + if (!tree) { return NULL; } - - /* create a new NV-CONTROL handle */ - - screen = DefaultScreen(display); - - h = NvCtrlAttributeInit(display, screen, - NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); - - if (!h) { - if (error_dialog) { - error_msg(ctk_framelock, "<span weight=\"bold\" " - "size=\"larger\">Unable " - "to add X screen to FrameLock group</span>\n\nXXX need " - "descriptive message."); - } else { - nv_error_msg("Unable to add X screen to FrameLock group."); + + tree->vbox = gtk_vbox_new(FALSE, 0); + tree->ctk_framelock = ctk_framelock; + + return tree; +} + + + +/** list_tree_add_entry() ******************************************** + * + * - Adds a list entry to the tree list + * + */ +static void list_tree_add_entry(nvListTreePtr tree, nvListEntryPtr entry) +{ + nvListEntryPtr e; + + if (!tree || !entry || entry->tree) { + return; + } + entry->tree = tree; + entry->next_sibling = NULL; + + /* Add entry to the end of the list */ + if (!tree->entries) { + tree->entries = entry; + } else { + e = tree->entries; + while (e->next_sibling) { + e = e->next_sibling; } - return NULL; + e->next_sibling = entry; } + tree->nentries++; - /* does this NV-CONTROL handle support FrameLock? */ - - 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 FrameLock group</span>\n\n" - "This X Screen does not support FrameLock."); + list_entry_associate(entry, tree); + + gtk_box_pack_start(GTK_BOX(tree->vbox), entry->vbox, FALSE, FALSE, 5); + gtk_widget_show_all(GTK_WIDGET(entry->vbox)); +} + + + +/** list_tree_remove_entry() ***************************************** + * + * - Removes a list entry from the tree list. + * + */ +static void list_tree_remove_entry(nvListTreePtr tree, nvListEntryPtr entry) +{ + nvListEntryPtr parent; + + if (!tree || !entry) { + return; + } + + /* Remove all children from the entry */ + list_entry_remove_children(entry); + + /* Separate entry from its parent */ + parent = entry->parent; + if (parent) { + + /* + * This is not a top-level entry so just + * remove it from its parent + */ + + list_entry_unparent(entry); + + } else { + + /* + * This is a top-level entry, so remove it from + * the tree. + */ + + /* Find and remove entry from the list */ + if (tree->entries == entry) { + tree->entries = entry->next_sibling; } else { - nv_error_msg("Unable to add X screen to FrameLock group; " - "this X Screen does not support FrameLock."); + nvListEntryPtr e = tree->entries; + while (e && e->next_sibling != entry) { + e = e->next_sibling; + } + if (!e || e->next_sibling != entry) { + return; /* Entry not found in tree! */ + } + e->next_sibling = entry->next_sibling; } - NvCtrlAttributeClose(h); - return NULL; + entry->next_sibling = NULL; + tree->nentries--; + + list_entry_associate(entry, NULL); + + gtk_container_remove(GTK_CONTAINER(tree->vbox), entry->vbox); } - /* XXX need to check that the current modeline matches */ + /* Get rid of the entry */ + list_entry_free(entry); - /* add the screen to the list store */ - - add_member_to_list_store(ctk_framelock, h); + /* Remove parent if we were the last child */ + if (parent && !parent->children) { + list_tree_remove_entry(tree, parent); + } +} - /* update the house sync controls */ - update_house_sync_controls(ctk_framelock); - /* enable the "Test Link" and "Enable Framelock" buttons */ +/** find_server_by_name() ******************************************** + * + * - Looks in the list tree for a list entry with a handle to a + * server with the name 'server_name'. The first list entry found + * with a handle to the named server is returned. + * + */ +static nvListEntryPtr find_server_by_name(nvListTreePtr tree, + gchar *server_name) +{ + nvListEntryPtr entry; - gtk_widget_set_sensitive(ctk_framelock->sync_state_button, TRUE); + entry = tree->entries; + while (entry) { + gchar *name; - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Added X Screen '%s'", display_name); - return h; + switch (entry->data_type) { + case ENTRY_DATA_FRAMELOCK: + name = NvCtrlGetDisplayName(((nvFrameLockDataPtr)(entry->data))->handle); + break; + case ENTRY_DATA_GPU: + name = NvCtrlGetDisplayName(((nvGPUDataPtr)(entry->data))->handle); + break; + case ENTRY_DATA_DISPLAY: + name = NvCtrlGetDisplayName(((nvDisplayDataPtr)(entry->data))->handle); + break; + default: + name = NULL; + break; + } + + if (name && !strcasecmp(server_name, name)){ + free(name); + return entry; + } + free(name); + + entry = entry->next_sibling; + } + + return entry; } -static GtkWidget *create_add_x_screen_dialog(CtkFramelock *ctk_framelock) + + +/** find_entry_by_name() ********************************************* + * + * - Looks in the list tree for the first list entry to have a handle + * to the given server name with the given entry data type and + * target id. + * + */ +static nvListEntryPtr find_entry_by_name(nvListEntryPtr entry, + gchar *server_name, + int entry_type, + int entry_id + ) { - GtkWidget *dialog; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *label, *descr; - GtkWidget *image; - GdkPixbuf *pixbuf; - GtkWidget *alignment; - - dialog = gtk_dialog_new_with_buttons("Add X Screen", - ctk_framelock->parent_window, - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT | - GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); + nvListEntryPtr found_entry = NULL; - g_signal_connect (GTK_OBJECT(dialog), "response", - G_CALLBACK(add_x_screen_response), - GTK_OBJECT(ctk_framelock)); + if (!entry) return NULL; - gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - hbox = gtk_hbox_new(FALSE, 12); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + /* Check this entry */ - pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION, - GTK_ICON_SIZE_DIALOG, NULL); - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); + if ((entry->data_type == ENTRY_DATA_FRAMELOCK && + entry_type == NV_CTRL_TARGET_TYPE_FRAMELOCK) || + (entry->data_type == ENTRY_DATA_GPU && + entry_type == NV_CTRL_TARGET_TYPE_GPU)) { + gpointer handle; - label = gtk_label_new("X Screen:"); - descr = gtk_label_new("Please specify the X screen to be added to the " - "FrameLock group."); - - ctk_framelock->add_x_screen_entry = gtk_entry_new(); - - gtk_entry_set_text(GTK_ENTRY(ctk_framelock->add_x_screen_entry), - NvCtrlGetDisplayName - (ctk_framelock->attribute_handle)); - - gtk_entry_set_width_chars - (GTK_ENTRY(ctk_framelock->add_x_screen_entry), 16); + switch (entry->data_type) { + case ENTRY_DATA_FRAMELOCK: + handle = ((nvFrameLockDataPtr)(entry->data))->handle; + break; + case ENTRY_DATA_GPU: + handle = ((nvGPUDataPtr)(entry->data))->handle; + break; + default: + handle = NULL; + break; + } - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), image); - gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); + if (handle) { + gchar *name = NvCtrlGetDisplayName(handle); + int id = NvCtrlGetTargetId(handle); + + if (name && !strcasecmp(server_name, name) && + id == entry_id) { + free(name); + return entry; + } + free(name); + } + } - vbox = gtk_vbox_new(FALSE, 12); - gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + /* Check children */ - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), descr); - gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); + found_entry = find_entry_by_name(entry->children, + server_name, + entry_type, + entry_id); + if (found_entry) return found_entry; - hbox = gtk_hbox_new(FALSE, 12); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + /* Check siblings */ - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->add_x_screen_entry, - TRUE, TRUE, 0); - - return dialog; + found_entry = find_entry_by_name(entry->next_sibling, + server_name, + entry_type, + entry_id); + if (found_entry) return found_entry; -} /* create_add_x_screen_dialog() */ + /* Entry not found in this branch */ + return NULL; +} + + + +/**************************************************************************/ -/************************************************************************/ /* - * functions relating to remove_x_screen_dialog + * Widget event and helper functions */ -static void tree_selection_changed(GtkTreeSelection *selection, - gpointer user_data) +/** toggle_use_house_sync() ****************************************** + * + * Callback function for the 'use house sync' button. + * This button allows access to other house sync settings. + * + */ +static void toggle_use_house_sync(GtkWidget *widget, gpointer user_data) { CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListEntryPtr entry; + gboolean enabled; + nvFrameLockDataPtr data; - if (gtk_tree_selection_get_selected(selection, NULL, NULL)) { - gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, TRUE); - } else { - gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button,FALSE); - } -} + entry = get_framelock_server_entry((nvListTreePtr)(ctk_framelock->tree)); + if (!entry) return; + data = (nvFrameLockDataPtr)(entry->data); + enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); -static void remove_x_screen(GtkWidget *button, gint response, - gpointer user_data) -{ - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); - gboolean valid; - GtkTreeModel *model; - GtkTreeIter iter; - gchar *display_name; - - gtk_widget_hide_all(ctk_framelock->remove_x_screen_dialog); + NvCtrlSetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, enabled); - if (response != GTK_RESPONSE_OK) return; + update_house_sync_controls(ctk_framelock); - gtk_tree_model_get(GTK_TREE_MODEL(ctk_framelock->list_store), - &ctk_framelock->remove_x_screen_iter, - COLUMN_DISPLAY_NAME, &display_name, -1); + NvCtrlGetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, &enabled); ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Removed X Screen '%s'", display_name); - - /* XXX disable anything that we need to in the X server */ + "%s use of House Sync Signal.", + enabled?"Enabled":"Disabled"); +} + + + +/** toggle_extra_info() ********************************************** + * + * Callback function for the 'show all info' button. + * This button shows/hides extra information from the + * frame lock list entries. + * + */ +static void toggle_extra_info(GtkWidget *widget, gpointer data) +{ + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(data); + gboolean enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - gtk_list_store_remove(GTK_LIST_STORE(ctk_framelock->list_store), - &ctk_framelock->remove_x_screen_iter); + gtk_button_set_label(GTK_BUTTON(widget), + enabled?"Hide Extra Info":"Show Extra Info"); + + update_framelock_controls(ctk_framelock); - /* - * if there are no entries left, then disable the "Test Link" and - * "Enable FrameLock" buttons. - */ + update_framelock_status(ctk_framelock); - model = GTK_TREE_MODEL(ctk_framelock->list_store); - valid = gtk_tree_model_get_iter_first(model, &iter); - if (!valid) { - // Nothing to house sync to - if (ctk_framelock->use_house_sync_button) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( - ctk_framelock->use_house_sync_button), FALSE); - } - gtk_widget_set_sensitive(ctk_framelock->sync_state_button, FALSE); - update_house_sync_controls (ctk_framelock); + ctk_config_statusbar_message(ctk_framelock->ctk_config, + " extra information.", + enabled?"Showing":"Hiding"); +} + + + +/** toggle_server() ************************************************** + * + * Callback function when a user toggles the 'server' checkbox of + * a display device. + * + */ +static void toggle_server(GtkWidget *widget, gpointer data) +{ + nvListEntryPtr entry = (nvListEntryPtr)data; + nvDisplayDataPtr display_data = (nvDisplayDataPtr)(entry->data); + nvGPUDataPtr gpu_data = (nvGPUDataPtr)(entry->parent->data); + gboolean server_checked; + + if (entry->data_type != ENTRY_DATA_DISPLAY) { + return; } + + server_checked = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox)); + + entry->tree->server_entry = (server_checked ? entry : NULL); + gpu_data->server_mask = (server_checked ? display_data->device_mask : 0); + + /* Update GUI state */ + update_framelock_controls(entry->tree->ctk_framelock); + + /* Update server state */ + NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_MASTER, + gpu_data->server_mask); + + ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config, + " frame lock server device.", + server_checked?"Selected":"Unselected"); } -static void show_remove_x_screen_dialog(GtkWidget *button, - CtkFramelock *ctk_framelock) + + +/** toggle_client() ************************************************** + * + * Callback function when a user toggles the 'client' checkbox of + * a display device. + * + */ +static void toggle_client(GtkWidget *widget, gpointer data) { - GtkTreeIter iter; - GtkTreeSelection *selection; - gchar *str, *display_name; + nvListEntryPtr entry = (nvListEntryPtr)data; + nvDisplayDataPtr display_data = (nvDisplayDataPtr)(entry->data); + nvGPUDataPtr gpu_data = (nvGPUDataPtr)(entry->parent->data); + gboolean client_checked; - selection = gtk_tree_view_get_selection(ctk_framelock->treeview); - - if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return; - - gtk_tree_model_get(GTK_TREE_MODEL(ctk_framelock->list_store), &iter, - COLUMN_DISPLAY_NAME, &display_name, -1); - - str = g_strconcat("Remove X Screen '", display_name, "'?", NULL); - gtk_label_set_text(GTK_LABEL(ctk_framelock->remove_x_screen_label), str); - g_free(str); - - ctk_framelock->remove_x_screen_iter = iter; + if (entry->data_type != ENTRY_DATA_DISPLAY) { + return; + } + + client_checked = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox)); - gtk_widget_show_all(ctk_framelock->remove_x_screen_dialog); + if (client_checked) { + gpu_data->clients_mask |= display_data->device_mask; + } else { + gpu_data->clients_mask &= ~(display_data->device_mask); + } + + /* Update GUI state */ + update_framelock_controls(entry->tree->ctk_framelock); + + /* Update server state */ + NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SLAVES, + gpu_data->clients_mask); + + ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config, + " frame lock client device.", + client_checked?"Selected":"Unselected"); } -static GtkWidget *create_remove_x_screen_dialog( - CtkFramelock *ctk_framelock -) +/** set_enable_sync_server() ***************************************** + * + * Function to enable/disable frame lock sync on the server gpu + * device. + * + * This function returns TRUE if something was enabled. + * + */ +static gboolean set_enable_sync_server(nvListTreePtr tree, gboolean enable) { - GtkWidget *dialog; - GtkWidget *hbox; - GtkWidget *image; - GdkPixbuf *pixbuf; - GtkWidget *alignment; - + nvListEntryPtr entry = get_gpu_server_entry(tree); + nvGPUDataPtr data; + ReturnStatus ret; - dialog = gtk_dialog_new_with_buttons("Remove X Screen", - ctk_framelock->parent_window, - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT | - GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); + if (!entry) return FALSE; - g_signal_connect(GTK_OBJECT(dialog), "response", - G_CALLBACK(remove_x_screen), - GTK_OBJECT(ctk_framelock)); + data = (nvGPUDataPtr)(entry->data); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - - hbox = gtk_hbox_new(FALSE, 12); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - - pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION, - GTK_ICON_SIZE_DIALOG, NULL); - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); + ret = NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, enable); + if (ret != NvCtrlSuccess) return FALSE; + + ret = NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, &enable); + if (ret != NvCtrlSuccess) return FALSE; + + data->enabled = enable; + + return enable; +} - ctk_framelock->remove_x_screen_label = gtk_label_new(NULL); + + +/** set_enable_sync_client() ***************************************** + * + * Function to enable/disable frame lock sync on a client gpu device. + * + * This function returns TRUE if something was enabled. + * + */ +static gboolean set_enable_sync_clients(nvListEntryPtr entry_list, + gboolean enable) +{ + nvListEntryPtr entry; + nvListEntryPtr server_gpu_entry; + + gint framelock_enabled = 0; + gint something_enabled = 0; + ReturnStatus ret; + + + if (!entry_list) return FALSE; + + /* Get the server GPU entry */ + + server_gpu_entry = get_gpu_server_entry(entry_list->tree); + + /* Go through all entries and activate/disable all entries that + * aren't the server. + */ - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), image); - gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); + for (entry = entry_list; entry; entry = entry->next_sibling) { + nvGPUDataPtr data; - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), - ctk_framelock->remove_x_screen_label); - gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0); + if (entry->children) { + something_enabled = set_enable_sync_clients(entry->children, + enable); + framelock_enabled = (framelock_enabled || something_enabled); + } + + if (entry == server_gpu_entry || entry->data_type != ENTRY_DATA_GPU) { + continue; + } - return dialog; + data = (nvGPUDataPtr)(entry->data); + + /* Only send protocol if there is something to enable */ + if (!data->clients_mask) continue; -} /* create_remove_x_screen_dialog() */ + ret = NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, enable); + if (ret != NvCtrlSuccess) continue; + ret = NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, + &(something_enabled)); + if (ret != NvCtrlSuccess) continue; + data->enabled = something_enabled; + framelock_enabled = framelock_enabled ? 1 : something_enabled; + } -/************************************************************************/ -/* - * function for updating the status - */ + return framelock_enabled?TRUE:FALSE; +} -/* - * update_status() - query the following from each member of the sync - * group: + +/** toggle_sync_enable() ********************************************* * - * NV_CTRL_FRAMELOCK_STEREO_SYNC - * NV_CTRL_FRAMELOCK_TIMING - * NV_CTRL_FRAMELOCK_SYNC_READY - * NV_CTRL_FRAMELOCK_SYNC_RATE - * NV_CTRL_FRAMELOCK_HOUSE_STATUS - * NV_CTRL_FRAMELOCK_PORT0_STATUS - * NV_CTRL_FRAMELOCK_PORT1_STATUS + * Callback function when a user toggles the 'Enable Frame Lock' + * button. * - * XXX maybe rather than have a button to do this, the app could be - * set to poll (and auto update the gui) periodically? */ +static void toggle_sync_enable(GtkWidget *button, gpointer data) +{ + CtkFramelock *ctk_framelock = (CtkFramelock *) data; + guint val; + gboolean enabled; + gboolean something_enabled; + gboolean framelock_enabled = FALSE; + nvListTreePtr tree = (nvListTreePtr) ctk_framelock->tree; + nvListEntryPtr entry; + + + enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + if (enabled) val = NV_CTRL_FRAMELOCK_SYNC_ENABLE; + else val = NV_CTRL_FRAMELOCK_SYNC_DISABLE; + + /* If we are enabling frame lock, enable the master first */ + if (enabled) { + something_enabled = set_enable_sync_server(tree, val); + framelock_enabled = (framelock_enabled || something_enabled); + } -static gboolean update_status(gpointer user_data) + /* Enable/Disable slaves */ + something_enabled = set_enable_sync_clients(tree->entries, val); + framelock_enabled = (framelock_enabled || something_enabled); + + /* If we are disabling frame lock, disable the master first */ + if (!enabled) { + something_enabled = set_enable_sync_server(tree, val); + framelock_enabled = (framelock_enabled || something_enabled); + } + + /* + * toggle the TEST_SIGNAL, to guarantee accuracy of the universal + * frame count (as returned by the glXQueryFrameCountNV() function + * in the GLX_NV_swap_group extension) + */ + + entry = get_gpu_server_entry(tree); + if (enabled && entry && framelock_enabled) { + nvGPUDataPtr data = (nvGPUDataPtr)(entry->data); + NvCtrlSetAttribute(data->handle, + NV_CTRL_FRAMELOCK_TEST_SIGNAL, + NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE); + NvCtrlSetAttribute(data->handle, + NV_CTRL_FRAMELOCK_TEST_SIGNAL, + NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE); + } + + ctk_framelock->framelock_enabled = framelock_enabled; + + update_framelock_controls(ctk_framelock); + + update_framelock_status(ctk_framelock); + + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Frame lock %s.", + enabled ? "enabled" : "disabled"); +} + + + +/** test_link_done() ************************************************* + * + * Callback function for the frame lock test signal functionality. + * This function is called once the test signal has finished. + * + */ +static gint test_link_done(gpointer data) { - gboolean valid; - GtkTreeIter iter; - gint stereo_sync, timing, sync_ready, sync_rate, house, port0, port1; - GtkTreeModel *model; - NvCtrlAttributeHandle *handle; CtkFramelock *ctk_framelock; + nvListEntryPtr entry; - ctk_framelock = CTK_FRAMELOCK(user_data); + ctk_framelock = CTK_FRAMELOCK(data); + + entry = get_gpu_server_entry((nvListTreePtr)ctk_framelock->tree); - model = GTK_TREE_MODEL(ctk_framelock->list_store); + if (!entry) return FALSE; - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1); - if (!handle) break; - - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, &stereo_sync); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_TIMING, &timing); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_READY, &sync_ready); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &sync_rate); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT0_STATUS, &port0); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT1_STATUS, &port1); + /* Test signal already disabled? */ + + if (!ctk_framelock->test_link_enabled) return FALSE; + + /* Disable the test signal */ + + ctk_framelock->test_link_enabled = FALSE; + + NvCtrlSetAttribute(((nvGPUDataPtr)(entry->data))->handle, + NV_CTRL_FRAMELOCK_TEST_SIGNAL, + NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE); + + gtk_grab_remove(ctk_framelock->test_link_button); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_STEREO_SYNC, stereo_sync, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_TIMING, timing, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_SYNC_READY, sync_ready, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_SYNC_RATE, sync_rate, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_HOUSE, house, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_RJ45_PORT0, port0, -1); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - COLUMN_RJ45_PORT1, port1, -1); - - valid = gtk_tree_model_iter_next(model, &iter); - } + gdk_window_set_cursor((GTK_WIDGET(ctk_framelock->parent_window))->window, + NULL); - return TRUE; + /* un-press the testlink button */ + + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); -} /* update_status() */ + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), FALSE); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Test Link complete."); + return FALSE; +} -/* - * test_link() - tell the master to enable the test signal, update - * everyone's status, and then disable the test signal. +/** toggle_test_link() *********************************************** + * + * Callback function for the 'test link' button. This button + * activates the frame lock test signal. + * */ - -static void test_link(GtkWidget *button, CtkFramelock *ctk_framelock) +static void toggle_test_link(GtkWidget *button, gpointer data) { - gboolean valid, master, enabled; - GtkTreeIter iter; - NvCtrlAttributeHandle *handle; - GtkTreeModel *model; + CtkFramelock *ctk_framelock; + gboolean enabled = FALSE; + nvListEntryPtr entry; + + ctk_framelock = CTK_FRAMELOCK(data); + + if (!ctk_framelock->framelock_enabled) goto fail; + + /* User cancels the test signal */ + if (ctk_framelock->test_link_enabled) { + test_link_done(ctk_framelock); + return; + } + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button)); - - if (!enabled) return; - - model = GTK_TREE_MODEL(ctk_framelock->list_store); - /* find the master handle */ + if (!enabled) goto fail; - handle = NULL; + entry = get_gpu_server_entry((nvListTreePtr)ctk_framelock->tree); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master, -1); - if (master) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, - &handle, -1); - break; - } - valid = gtk_tree_model_iter_next(model, &iter); + if (!entry) { + enabled = FALSE; + goto fail; } - if (!handle) return; - /* enable the test signal */ + ctk_framelock->test_link_enabled = TRUE; + gdk_window_set_cursor ((GTK_WIDGET(ctk_framelock->parent_window))->window, ctk_framelock->wait_cursor); gtk_grab_add(button); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_TEST_SIGNAL, + NvCtrlSetAttribute(((nvGPUDataPtr)(entry->data))->handle, + NV_CTRL_FRAMELOCK_TEST_SIGNAL, NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE); ctk_config_statusbar_message(ctk_framelock->ctk_config, @@ -2081,711 +2612,2406 @@ static void test_link(GtkWidget *button, CtkFramelock *ctk_framelock) g_timeout_add(DEFAULT_TEST_LINK_TIME_INTERVAL, test_link_done, (gpointer) ctk_framelock); + + return; + + fail: + + /* Reset the button */ + g_signal_handlers_block_by_func(G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), enabled); -} /* test_link() */ + g_signal_handlers_unblock_by_func(G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); +} -static gint test_link_done(gpointer data) + +/** activate_sync_interval() ***************************************** + * + * Callback function for when the user changes the house sync + * interval. + * + */ +static void activate_sync_interval(GtkEntry *widget, gpointer user_data) { - CtkFramelock *ctk_framelock = (CtkFramelock *) data; - gboolean valid, master; - GtkTreeIter iter; - NvCtrlAttributeHandle *handle; - GtkTreeModel *model; + CtkFramelock *ctk_framelock = (CtkFramelock *)user_data; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = get_framelock_server_entry(tree); + nvFrameLockDataPtr data; + const gchar *str = gtk_entry_get_text(widget); + gint interval; + + if (!entry || !str) return; - model = GTK_TREE_MODEL(ctk_framelock->list_store); + interval = strtol(str, NULL, 10); - /* find the master handle */ + data = (nvFrameLockDataPtr)(entry->data); - handle = NULL; + NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL, + interval); +} - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master, -1); - if (master) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, - &handle, -1); - break; + + +/** changed_sync_edge() ********************************************** + * + * Callback function for when the user changes a frame lock device's + * sync edge. + * + */ +static void changed_sync_edge(GtkEditable *editable, gpointer user_data) +{ + CtkFramelock *ctk_framelock = (CtkFramelock *)user_data; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = get_framelock_server_entry(tree); + nvFrameLockDataPtr data; + const gchar *str = gtk_entry_get_text(GTK_ENTRY(editable)); + gint edge; + + if (!entry || !str) return; + + data = (nvFrameLockDataPtr) entry->data; + + for (edge = NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE; + edge <= NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES; edge++) { + if (strcmp(syncEdgeStrings[edge], str) == 0) { + NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_POLARITY, edge); + return; } - valid = gtk_tree_model_iter_next(model, &iter); } +} - if (!handle) return FALSE; - /* disable the test signal */ - - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_TEST_SIGNAL, - NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE); - - gtk_grab_remove(ctk_framelock->test_link_button); + +/** changed_video_mode() ********************************************* + * + * Callback function for when the user changes the house sync video + * mode. + * + */ +static void changed_video_mode(GtkEditable *editable, gpointer user_data) +{ + CtkFramelock *ctk_framelock = (CtkFramelock *)user_data; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = get_framelock_server_entry(tree); + nvFrameLockDataPtr data; + const gchar *str = gtk_entry_get_text(GTK_ENTRY(editable)); + gint mode; + + if (!entry || !str) return; + + data = (nvFrameLockDataPtr) entry->data; + + for (mode = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE; + mode <= NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; mode++) { - gdk_window_set_cursor((GTK_WIDGET(ctk_framelock->parent_window))->window, - NULL); + if (strcmp(houseFormatStrings[mode], str) == 0) { + NvCtrlSetAttribute(data->handle, + NV_CTRL_FRAMELOCK_VIDEO_MODE, mode); + return; + } + } +} - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "Test Link complete."); - /* un-press the testlink button */ + +/** detect_video_mode_time() ***************************************** + * + * Callback function called every time the video mode detection + * timer goes off. + * + * see toggle_detect_video_mode() for details. + * + */ +static gboolean detect_video_mode_timer(gpointer user_data) +{ + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = get_framelock_server_entry(tree); + nvFrameLockDataPtr data; + gint house; + + /* Master gone... oops */ + if (!entry) { + goto done; + } + + /* check if we now have house sync */ + + data = (nvFrameLockDataPtr)(entry->data); + + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house); + + if (house) { + + /* + * We found house sync; use the current_detect_format + */ + + update_house_sync_controls(ctk_framelock); + + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "House Sync format detected as %s.", + houseFormatStrings + [ctk_framelock->current_detect_format]); + goto done; + } + + + /* + * we did not find house sync, yet, so move to the next format + */ + + switch (ctk_framelock->current_detect_format) { + + case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO: + ctk_framelock->current_detect_format = + NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL; + break; + + case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL: + ctk_framelock->current_detect_format = + NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL; + break; + + case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL: + ctk_framelock->current_detect_format = + NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL; + break; + + case NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL: + ctk_framelock->current_detect_format = + NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO; + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Unable to detect house sync format."); + goto done; + break; + } + /* + * Set the new video format + */ + + NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, + ctk_framelock->current_detect_format); + + return TRUE; + + + done: + + /* untoggle the detect button */ g_signal_handlers_block_by_func - (G_OBJECT(ctk_framelock->test_link_button), - G_CALLBACK(test_link), + (G_OBJECT(ctk_framelock->video_mode_detect), + G_CALLBACK(toggle_detect_video_mode), (gpointer) ctk_framelock); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), FALSE); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->video_mode_detect), FALSE); + g_signal_handlers_unblock_by_func - (G_OBJECT(ctk_framelock->test_link_button), - G_CALLBACK(test_link), + (G_OBJECT(ctk_framelock->video_mode_detect), + G_CALLBACK(toggle_detect_video_mode), (gpointer) ctk_framelock); - + return FALSE; } -static GtkWidget *create_sync_state_button(CtkFramelock *ctk_framelock) -{ - GtkWidget *label; - GtkWidget *hbox, *hbox2; - GdkPixbuf *pixbuf; - GtkWidget *image = NULL; - GtkWidget *button; - button = gtk_toggle_button_new(); +/** toggle_detect_video_mode() *************************************** + * + * Callback function for when the user clicks on the 'Detect' (video + * mode) button. + * + * House Sync autodetection scheme: a modal push button is used to + * request auto detection. When the button is pressed, we program the + * first format type and then start a timer. + * + * From the timer, we check if we are getting a house sync; if we are, + * then update the settings and unpress the button. If we are not, + * program the next format in the sequence and try again. + * + * XXX what happens if the master gets changed while we are doing + * this? + * + */ +static void toggle_detect_video_mode(GtkToggleButton *button, gpointer user_data) +{ + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = get_framelock_server_entry(tree); + nvFrameLockDataPtr data; - /* create the enable syncing icon */ - pixbuf = gtk_widget_render_icon(button, - GTK_STOCK_EXECUTE, - GTK_ICON_SIZE_BUTTON, - "enable framelock"); - if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf); - label = gtk_label_new("Enable FrameLock"); + if (!gtk_toggle_button_get_active(button)) { + g_source_remove(ctk_framelock->video_mode_detect_timer); + ctk_framelock->video_mode_detect_timer = 0; - hbox = gtk_hbox_new(FALSE, 2); + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Aborted house sync detection."); + return; + } - if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + if (!entry) return; - hbox2 = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15); + data = (nvFrameLockDataPtr)(entry->data); + + ctk_framelock->current_detect_format = + NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO; - gtk_widget_show_all(hbox2); + NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, + ctk_framelock->current_detect_format); - /* - * XXX increment the reference count, so that when we do - * gtk_container_remove() later, it doesn't get destroyed - */ + ctk_framelock->video_mode_detect_timer = + g_timeout_add(500, detect_video_mode_timer, user_data); + + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Attempting to detect house sync..."); +} - gtk_object_ref(GTK_OBJECT(hbox2)); - ctk_framelock->enable_syncing_label = hbox2; - - /* create the disable syncing icon */ - - pixbuf = gtk_widget_render_icon(button, - GTK_STOCK_STOP, - GTK_ICON_SIZE_BUTTON, - "disable framelock"); - if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf); - label = gtk_label_new("Disable FrameLock"); - - hbox = gtk_hbox_new(FALSE, 2); +/** list_entry_update_framelock_status() ***************************** + * + * Updates the state of the GUI for a frame lock list entry by + * querying the current state of the X Server. + * + */ +void list_entry_update_framelock_status(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + gint rate, delay, house, port0, port1; + gchar str[32]; + gfloat fvalue; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr server_entry = get_framelock_server_entry(tree); + gboolean use_house_sync; + gboolean framelock_enabled; + gboolean is_server; - if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - hbox2 = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15); + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &rate); + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_DELAY, &delay); + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house); + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_PORT0_STATUS, &port0); + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_PORT1_STATUS, &port1); - gtk_widget_show_all(hbox2); - - /* - * XXX increment the reference count, so that when we do - * gtk_container_remove() later, it doesn't get destroyed + use_house_sync = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync)); + + framelock_enabled = ctk_framelock->framelock_enabled; + + is_server = (server_entry && (server_entry->data == data)); + + /* Receiving Sync */ + if (!framelock_enabled || (is_server && !use_house_sync)) { + gtk_widget_set_sensitive(data->receiving_label, FALSE); + update_image(data->receiving_hbox, ctk_framelock->led_grey); + } else { + gint receiving; + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_READY, + &receiving); + gtk_widget_set_sensitive(data->receiving_label, TRUE); + update_image(data->receiving_hbox, + receiving ? ctk_framelock->led_green : + ctk_framelock->led_red); + } + + /* Sync Rate */ + gtk_widget_set_sensitive(data->rate_label, framelock_enabled); + gtk_widget_set_sensitive(data->rate_text, framelock_enabled); + fvalue = (float) rate / 1000.0; + snprintf(str, 32, "%.2f Hz", fvalue); // 6.2f + gtk_label_set_text(GTK_LABEL(data->rate_text), str); + + /* Sync Delay (Skew) */ + gtk_widget_set_sensitive(data->delay_label, framelock_enabled); + gtk_widget_set_sensitive(data->delay_text, framelock_enabled); + fvalue = ((gfloat) delay) * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR; + snprintf(str, 32, "%.2f uS", fvalue); // 10.2f + gtk_label_set_text(GTK_LABEL(data->delay_text), str); + + /* House Sync and Ports are always active */ + update_image(data->house_hbox, + house?ctk_framelock->led_green:ctk_framelock->led_red); + if ( !data->port0_ethernet_error ) { + update_image(data->port0_hbox, + (port0==NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT)? + ctk_framelock->rj45_input:ctk_framelock->rj45_output); + } else { + update_image(data->port0_hbox, ctk_framelock->rj45_unused); + } + if ( !data->port1_ethernet_error ) { + update_image(data->port1_hbox, + (port1==NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT)? + ctk_framelock->rj45_input:ctk_framelock->rj45_output); + } else { + update_image(data->port1_hbox, ctk_framelock->rj45_unused); + } +} + + + +/** list_entry_update_gpu_status() *********************************** + * + * Updates the state of the GUI for a gpu list entry by querying the + * current state of the X Server. + * + */ +void list_entry_update_gpu_status(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + /* Do nothing */ +} + + + +/** list_entry_update_display_status() ******************************* + * + * Updates the state of the GUI for a display list entry by querying + * the current state of the X Server. + * + */ +void list_entry_update_display_status(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + nvDisplayDataPtr data = (nvDisplayDataPtr)(entry->data); + gboolean framelock_enabled; + gboolean is_server; + gboolean is_client; + gboolean gpu_is_server; + gboolean use_house_sync; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr gpu_server_entry = get_gpu_server_entry(tree); + + framelock_enabled = ctk_framelock->framelock_enabled; + + use_house_sync = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync)); + + is_server = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(data->server_checkbox)); + + is_client = gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(data->client_checkbox)); + + 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); + } - gtk_object_ref(GTK_OBJECT(hbox2)); - - ctk_framelock->disable_syncing_label = hbox2; - - /* start with syncing disabled */ - - gtk_container_add(GTK_CONTAINER(button), - ctk_framelock->enable_syncing_label); + /* 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. + */ + if (!framelock_enabled || + (!is_server && !is_client) || + (is_server && gpu_is_server && !use_house_sync)) { + gtk_widget_set_sensitive(data->stereo_label, FALSE); + update_image(data->stereo_hbox, ctk_framelock->led_grey); + } else { + gint stereo_sync; + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, + &stereo_sync); + gtk_widget_set_sensitive(data->stereo_label, TRUE); + update_image(data->stereo_hbox, + stereo_sync ? ctk_framelock->led_green : + ctk_framelock->led_red); + } +} + + + +/** list_entry_update_status() *************************************** + * + * Updates the (GUI) state of a list entry, its children and siblings + * by queryin ghte X Server. + * + */ +void list_entry_update_status(CtkFramelock *ctk_framelock, + nvListEntryPtr entry) +{ + if (!entry) return; + + list_entry_update_status(ctk_framelock, entry->children); + + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + list_entry_update_framelock_status(ctk_framelock, entry); + } else if (entry->data_type == ENTRY_DATA_GPU) { + list_entry_update_gpu_status(ctk_framelock, entry); + } else if (entry->data_type == ENTRY_DATA_DISPLAY) { + list_entry_update_display_status(ctk_framelock, entry); + } + + list_entry_update_status(ctk_framelock, entry->next_sibling); +} + + + +/** update_framelock_status() **************************************** + * + * Updates the (GUI) state of all the frame lock list entries status + * fields by querying the X Server. + * + */ +static gboolean update_framelock_status(gpointer user_data) +{ + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + + list_entry_update_status(ctk_framelock, + ((nvListTreePtr)(ctk_framelock->tree))->entries); + + return TRUE; +} + + + +/** check_for_ethernet() ********************************************* + * + * Queries ethernet status for all frame lock devices and reports + * on any error. + * + * XXX This assumes that the frame lock (G-Sync) devices are + * top-level list entries, such that they are all siblings. + * + */ +static gboolean check_for_ethernet(gpointer user_data) +{ + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + static gboolean first_error = TRUE; + nvListEntryPtr entry; + nvFrameLockDataPtr error_data = NULL; - return (button); + + /* Look through the framelock entries and check the + * ethernet status on each one + */ + entry = ((nvListTreePtr)(ctk_framelock->tree))->entries; + while (entry) { + if (entry->data_type == ENTRY_DATA_FRAMELOCK) { + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + gint val; + + NvCtrlGetAttribute(data->handle, + NV_CTRL_FRAMELOCK_ETHERNET_DETECTED, + &val); + + if (val & NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT0) { + data->port0_ethernet_error = TRUE; + error_data = data; + } else { + data->port0_ethernet_error = 0; + } + if (val & NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT1) { + data->port1_ethernet_error = TRUE; + error_data = data; + } else { + data->port1_ethernet_error = 0; + } + } + entry = entry->next_sibling; + } + + + if (error_data) { + if (first_error) { + error_msg(ctk_framelock, "<span weight=\"bold\" " + "size=\"larger\">Frame lock RJ45 error</span>\n\n" + "Either an Ethernet LAN cable is connected to the " + "frame lock board on X Server '%s' or the linked " + "PC is not turned on. Either disconnect the LAN " + "cable or turn on the linked PC for proper " + "operation.", + NvCtrlGetDisplayName(error_data->handle) + ); + } + first_error = FALSE; + } else { + first_error = TRUE; + } + + return TRUE; } -static void toggle_sync_state_button(GtkWidget *button, - CtkFramelock *ctk_framelock) + +/** update_house_sync_controls() ************************************* + * + * Queries the X Server for hosue sync status information for the + * currently selected frame lock server and updates the GUI. + * + */ +static void update_house_sync_controls(CtkFramelock *ctk_framelock) { - gboolean valid; - GtkTreeIter iter; - NvCtrlAttributeHandle *handle; - guint display_mask, val; + nvListEntryPtr entry; gboolean enabled; - GtkTreeSelection *selection; - - GtkTreeModel *model; - - enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); + gboolean use_house; + gboolean sensitive; - if (enabled) val = NV_CTRL_FRAMELOCK_SYNC_ENABLE; - else val = NV_CTRL_FRAMELOCK_SYNC_DISABLE; + entry = get_framelock_server_entry((nvListTreePtr)(ctk_framelock->tree)); + enabled = ctk_framelock->framelock_enabled; + + /* Get the current use house sync state from the X Server */ + if (entry) { + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + + NvCtrlGetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, &use_house); + } else { + use_house = FALSE; + } - /* - * set the NV_CTRL_FRAMELOCK_SYNC status on each member of the - * FrameLock group - */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->use_house_sync), + G_CALLBACK(toggle_use_house_sync), + (gpointer) ctk_framelock); - handle = NULL; - model = GTK_TREE_MODEL(ctk_framelock->list_store); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, - COLUMN_DISPLAY_MASK, &display_mask, -1); - if (!handle) return; /* XXX */ - - NvCtrlSetDisplayAttribute(handle, display_mask, - NV_CTRL_FRAMELOCK_SYNC, val); - valid = gtk_tree_model_iter_next(model, &iter); - } + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync), use_house); - /* - * toggle the TEST_SIGNAL, to guarantee accuracy of the universal - * frame count (as returned by the glXQueryFrameCountNV() function - * in the GLX_NV_swap_group extension) - */ + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->use_house_sync), + G_CALLBACK(toggle_use_house_sync), + (gpointer) ctk_framelock); + + sensitive = (entry && !enabled); + gtk_widget_set_sensitive(ctk_framelock->house_sync_frame, sensitive); + sensitive = (entry && !enabled && use_house); + gtk_widget_set_sensitive(ctk_framelock->house_sync_hbox, sensitive); + + if (entry && sensitive) { + gint sync_interval; + gint sync_edge; + gint house_format; + gchar str[32]; + + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + + /* Query current house sync settings from master frame lock device */ + + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL, + &sync_interval); + + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_POLARITY, + &sync_edge); + + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, + &house_format); + + /* Update GUI to reflect server settings */ + + snprintf(str, 32, "%d", sync_interval); + gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry), + str); + + if (sync_edge < NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE) + sync_edge = NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE; + if (sync_edge > NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES) + sync_edge = NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES; + + gtk_entry_set_text + (GTK_ENTRY(GTK_COMBO(ctk_framelock->sync_edge_combo)->entry), + syncEdgeStrings[sync_edge]); + + if (house_format < NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE) + house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE; + if (house_format > NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV) + house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; + + gtk_entry_set_text + (GTK_ENTRY(GTK_COMBO(ctk_framelock->video_mode_combo)->entry), + houseFormatStrings[house_format]); - if (enabled && find_master(ctk_framelock, NULL, &handle)) { - NvCtrlSetAttribute(handle, - NV_CTRL_FRAMELOCK_TEST_SIGNAL, - NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE); - NvCtrlSetAttribute(handle, - NV_CTRL_FRAMELOCK_TEST_SIGNAL, - NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE); } +} - /* alter the button */ - if (enabled) { - if (!ctk_framelock->framelock_enabled) { + +/** gpu_state_received() ********************************************* + * + * Signal handler for gpu target events. + * + */ +static void gpu_state_received(GtkObject *object, + gpointer arg1, gpointer user_data) +{ + CtkEventStruct *event = (CtkEventStruct *) arg1; + nvListEntryPtr gpu_entry = (nvListEntryPtr) user_data; + nvGPUDataPtr gpu_data = (nvGPUDataPtr) gpu_entry->data; + + nvListEntryPtr display_entry = NULL; + nvDisplayDataPtr display_data = NULL; + + CtkFramelock *ctk_framelock = gpu_entry->tree->ctk_framelock; + gboolean sensitive; + gboolean checked; + + + switch (event->attribute) { + case NV_CTRL_FRAMELOCK_MASTER: + + /* Unset the previous master */ + display_entry = get_display_server_entry(gpu_entry->tree); + if (display_entry) { + display_data = (nvDisplayDataPtr)(display_entry->data); + + /* Clear the server checkbox */ + g_signal_handlers_block_by_func + (G_OBJECT(display_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); - gtk_container_remove - (GTK_CONTAINER(ctk_framelock->sync_state_button), - ctk_framelock->enable_syncing_label); - gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_state_button), - ctk_framelock->disable_syncing_label); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox), 0); + + g_signal_handlers_unblock_by_func + (G_OBJECT(display_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); + + /* If the server display device is on another gpu, tell the + * X Server we are unsetting it. + */ + if (display_entry->parent != gpu_entry) { + NvCtrlSetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_MASTER, 0); + } + ((nvGPUDataPtr)(display_entry->parent->data))->server_mask = 0; + gpu_entry->tree->server_entry = NULL; + } + + /* Set the new master */ + display_entry = get_display_on_gpu(gpu_entry, event->value); + if (display_entry) { + display_data = (nvDisplayDataPtr)(display_entry->data); + + /* Clear the server checkbox */ + g_signal_handlers_block_by_func + (G_OBJECT(display_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox), 1); + + g_signal_handlers_unblock_by_func + (G_OBJECT(display_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); + + gpu_entry->tree->server_entry = display_entry; } - /* - * disable the "Add Screen" and "Remove Screen" buttons; - * enable the "Test Link" button + gpu_data->server_mask = event->value; + + update_framelock_controls(gpu_entry->tree->ctk_framelock); + break; + + case NV_CTRL_FRAMELOCK_SLAVES: + + /* Set all client devices on this GPU. If a client is found + * to not match the selected server's refresh rate, unselect + * the server. The user will have to reselect the server. */ + for (display_entry = gpu_entry->children; display_entry; + display_entry = display_entry->next_sibling) { + display_data = + (nvDisplayDataPtr)(display_entry->data); + + sensitive = + GTK_WIDGET_IS_SENSITIVE(display_data->client_checkbox); + checked = ((display_data->device_mask) & event->value); + + /* Update the display list entry gui */ + + g_signal_handlers_block_by_func + (G_OBJECT(display_data->client_checkbox), + G_CALLBACK(toggle_client), + (gpointer) display_entry); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), checked); + + g_signal_handlers_unblock_by_func + (G_OBJECT(display_data->client_checkbox), + G_CALLBACK(toggle_client), + (gpointer) display_entry); + + /* If there is an inconsistensy, unselect the server */ - gtk_widget_set_sensitive(ctk_framelock->add_x_screen_button, FALSE); - gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, FALSE); - gtk_widget_set_sensitive(ctk_framelock->test_link_button, TRUE); + if (checked && !sensitive && gpu_entry->tree->server_entry) { + + nvListEntryPtr server_entry = + get_display_server_entry(gpu_entry->tree); + nvDisplayDataPtr server_data = + (nvDisplayDataPtr)(server_entry->data); + + /* Clear the server checkbox */ + g_signal_handlers_block_by_func + (G_OBJECT(server_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(server_data->server_checkbox), 0); + + g_signal_handlers_unblock_by_func + (G_OBJECT(server_data->server_checkbox), + G_CALLBACK(toggle_server), + (gpointer) display_entry); + + NvCtrlSetAttribute(server_data->handle, + NV_CTRL_FRAMELOCK_MASTER, 0); + ((nvGPUDataPtr)(server_entry->parent->data))->server_mask = 0; + gpu_entry->tree->server_entry = NULL; + } + } + + /* Save the client state */ + gpu_data->clients_mask = event->value; + + update_framelock_controls(gpu_entry->tree->ctk_framelock); + break; - } else { - if (ctk_framelock->framelock_enabled) { - gtk_container_remove - (GTK_CONTAINER(ctk_framelock->sync_state_button), - ctk_framelock->disable_syncing_label); - gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_state_button), - ctk_framelock->enable_syncing_label); + + case NV_CTRL_FRAMELOCK_SYNC: + /* Cache the enable/disable state of the gpu sync */ + gpu_data->enabled = event->value; + + /* Look to see if any gpu is enabled/disabled */ + ctk_framelock->framelock_enabled = + any_gpu_enabled(gpu_entry->tree->entries); + + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->sync_state_button), + G_CALLBACK(toggle_sync_enable), + (gpointer) ctk_framelock); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctk_framelock->sync_state_button), + ctk_framelock->framelock_enabled ? 1 : 0); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->sync_state_button), + G_CALLBACK(toggle_sync_enable), + (gpointer) ctk_framelock); + + update_framelock_controls(gpu_entry->tree->ctk_framelock); + break; + + + case NV_CTRL_FRAMELOCK_TEST_SIGNAL: + switch (event->value) { + case NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE: + ctk_framelock->test_link_enabled = TRUE; + gdk_window_set_cursor + ((GTK_WIDGET(ctk_framelock->parent_window))->window, + ctk_framelock->wait_cursor); + gtk_grab_add(ctk_framelock->test_link_button); + break; + case NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE: + ctk_framelock->test_link_enabled = FALSE; + gtk_grab_remove(ctk_framelock->test_link_button); + gdk_window_set_cursor + ((GTK_WIDGET(ctk_framelock->parent_window))->window, + NULL); + break; + default: + /* Unknwon state, ignore */ + break; } - /* enable the "Add Screen" button; disable the "Test Link" button */ + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), + ctk_framelock->test_link_enabled); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->test_link_button), + G_CALLBACK(toggle_test_link), + (gpointer) ctk_framelock); - gtk_widget_set_sensitive(ctk_framelock->add_x_screen_button, TRUE); - gtk_widget_set_sensitive(ctk_framelock->test_link_button, FALSE); + ctk_config_statusbar_message(ctk_framelock->ctk_config, + ctk_framelock->test_link_enabled ? + "Test Link started." : + "Test Link complete."); + break; - /* check if the "Remove Screen" button should be enabled */ - selection = gtk_tree_view_get_selection(ctk_framelock->treeview); - tree_selection_changed(selection, GTK_OBJECT(ctk_framelock)); + default: + /* Oops */ + break; } + +} /* gpu_state_received() */ - ctk_framelock->framelock_enabled = enabled; - update_house_sync_controls (ctk_framelock); - ctk_config_statusbar_message(ctk_framelock->ctk_config, - "FrameLock %s.", - enabled ? "enabled" : "disabled"); +/** framelock_state_received() *************************************** + * + * Signal handler for frame lock target events. + * + */ +static void framelock_state_received(GtkObject *object, + gpointer arg1, gpointer user_data) +{ + CtkEventStruct *event = (CtkEventStruct *) arg1; + nvListEntryPtr entry = (nvListEntryPtr) user_data; + CtkFramelock *ctk_framelock = entry->tree->ctk_framelock; -} /* toggle_sync_state_button() */ + nvListEntryPtr server_entry = + get_framelock_server_entry(entry->tree); + char str[32]; + gint sync_edge; + gint house_format; + + if (server_entry && entry != server_entry) { + /* Setting is being made to a non-server frame lock device, ignore */ + return; + } + + /* Process the new frame lock device setting */ + + switch (event->attribute) { + case NV_CTRL_USE_HOUSE_SYNC: + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->use_house_sync), + G_CALLBACK(toggle_use_house_sync), + (gpointer) ctk_framelock); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync), + event->value); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->use_house_sync), + G_CALLBACK(toggle_use_house_sync), + (gpointer) ctk_framelock); + break; + + case NV_CTRL_FRAMELOCK_SYNC_INTERVAL: + g_signal_handlers_block_by_func + (G_OBJECT(ctk_framelock->sync_interval_entry), + G_CALLBACK(activate_sync_interval), + (gpointer) ctk_framelock); + + snprintf(str, 32, "%d", event->value); + gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry), + str); + + g_signal_handlers_unblock_by_func + (G_OBJECT(ctk_framelock->sync_interval_entry), + G_CALLBACK(activate_sync_interval), + (gpointer) ctk_framelock); + break; + + case NV_CTRL_FRAMELOCK_POLARITY: + sync_edge = event->value; + if (sync_edge < NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE) + sync_edge = NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE; + if (sync_edge > NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES) + sync_edge = NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES; + + g_signal_handlers_block_by_func + (G_OBJECT(GTK_COMBO(ctk_framelock->sync_edge_combo)->entry), + G_CALLBACK(changed_sync_edge), + (gpointer) ctk_framelock); + + gtk_entry_set_text + (GTK_ENTRY(GTK_COMBO(ctk_framelock->sync_edge_combo)->entry), + syncEdgeStrings[sync_edge]); + + g_signal_handlers_unblock_by_func + (G_OBJECT(GTK_COMBO(ctk_framelock->sync_edge_combo)->entry), + G_CALLBACK(changed_sync_edge), + (gpointer) ctk_framelock); + + break; + + case NV_CTRL_FRAMELOCK_VIDEO_MODE: + house_format = event->value; + if (house_format < NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE) + house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE; + if (house_format > NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV) + house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; + + g_signal_handlers_block_by_func + (G_OBJECT(GTK_COMBO(ctk_framelock->video_mode_combo)->entry), + G_CALLBACK(changed_video_mode), + (gpointer) ctk_framelock); + + gtk_entry_set_text + (GTK_ENTRY(GTK_COMBO(ctk_framelock->video_mode_combo)->entry), + houseFormatStrings[house_format]); + + g_signal_handlers_unblock_by_func + (G_OBJECT(GTK_COMBO(ctk_framelock->video_mode_combo)->entry), + G_CALLBACK(changed_video_mode), + (gpointer) ctk_framelock); + break; + + default: + /* Oops */ + break; + } + + + update_house_sync_controls(ctk_framelock); +} + + + + +/**************************************************************************/ -/************************************************************************/ /* - * functions relating to the error_msg_dialog + * Main Frame Lock Page Widget */ -static GtkWidget *create_error_msg_dialog(CtkFramelock *ctk_framelock) -{ - GtkWidget *dialog; - GtkWidget *hbox; - GtkWidget *image; - GtkWidget *alignment; - GdkPixbuf *pixbuf; - - - dialog = gtk_dialog_new_with_buttons("Error", - ctk_framelock->parent_window, - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT | - GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", - G_CALLBACK(gtk_widget_hide_all), - GTK_OBJECT(dialog)); +static GObjectClass *parent_class; - gtk_container_set_border_width(GTK_CONTAINER(dialog), 6); - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - hbox = gtk_hbox_new(FALSE, 12); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - - pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_ERROR, - GTK_ICON_SIZE_DIALOG, NULL); - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - - ctk_framelock->error_msg_label = gtk_label_new(NULL); - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), image); - gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2); +/** ctk_framelock_class_init() *************************************** + * + * Initialize the object structure + * + */ +static void ctk_framelock_class_init( + CtkFramelockClass *ctk_framelock_class +) +{ + GObjectClass *gobject_class; - alignment = gtk_alignment_new(0.0, 0.0, 0, 0); - gtk_container_add(GTK_CONTAINER(alignment), - ctk_framelock->error_msg_label); - gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0); + gobject_class = (GObjectClass *) ctk_framelock_class; + parent_class = g_type_class_peek_parent(ctk_framelock_class); - return dialog; } -static void error_msg(CtkFramelock *ctk_framelock, const gchar *fmt, ...) + + +/** ctk_framelock_get_type() ***************************************** + * + * registers the frame lock class and return the unique type id. + * + */ +GType ctk_framelock_get_type( + void +) { - gchar *msg; + static GType ctk_framelock_type = 0; + + if (!ctk_framelock_type) { + static const GTypeInfo ctk_framelock_info = { + sizeof (CtkFramelockClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ctk_framelock_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CtkFramelock), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_framelock_type = g_type_register_static + (GTK_TYPE_VBOX, "CtkFramelock", &ctk_framelock_info, 0); + } + + return ctk_framelock_type; - NV_VSNPRINTF(msg, fmt); - - gtk_label_set_line_wrap(GTK_LABEL(ctk_framelock->error_msg_label), TRUE); - gtk_label_set_use_markup(GTK_LABEL(ctk_framelock->error_msg_label), TRUE); - gtk_label_set_markup(GTK_LABEL(ctk_framelock->error_msg_label), msg); - gtk_widget_show_all(ctk_framelock->error_msg_dialog); - - free(msg); } -/************************************************************************/ -/* - * Functions for manipulating the List Store +/** ctk_framelock_new() ********************************************** + * + * returns a new instance of the frame lock class. + * */ +GtkWidget* ctk_framelock_new(NvCtrlAttributeHandle *handle, + GtkWidget *parent_window, CtkConfig *ctk_config, + ParsedAttribute *p) +{ + GObject *object; + CtkFramelock *ctk_framelock; + GtkWidget *banner; + ReturnStatus ret; + unsigned int num_framelocks; -static void create_list_store(CtkFramelock *ctk_framelock) -{ - GtkTreeSelection *selection; + GtkWidget *frame; + GtkWidget *padding; + GtkWidget *sw; /* Scrollable window */ + GtkWidget *vp; /* Viewport */ + + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *combo; + GList *glist; + GtkWidget *button; + GtkWidget *image; + + - ctk_framelock->list_store = - gtk_list_store_new(NUM_COLUMNS, - G_TYPE_POINTER, /* HANDLE */ - G_TYPE_UINT, /* DISPLAY_MASK */ - G_TYPE_STRING, /* DISPLAY_NAME */ - G_TYPE_BOOLEAN, /* MASTER */ - G_TYPE_BOOLEAN, /* STEREO_SYNC */ - G_TYPE_BOOLEAN, /* TIMING */ - G_TYPE_BOOLEAN, /* SYNC_READY */ - G_TYPE_UINT, /* SYNC_RATE */ - G_TYPE_BOOLEAN, /* HOUSE */ - G_TYPE_BOOLEAN, /* RJ45_PORT0 */ - G_TYPE_BOOLEAN, /* RJ45_PORT1 */ - G_TYPE_UINT, /* POLARITY */ - G_TYPE_UINT, /* SYNC_SKEW */ - G_TYPE_UINT, /* SYNC_INTERVAL */ - G_TYPE_UINT); /* HOUSE_FORMAT */ + /* make sure we have a handle */ + + g_return_val_if_fail(handle != NULL, NULL); + + /* Only expose frame lock if there are frame lock boards in + * the system. This isn't absolutely necessary, because the + * frame lock control page does not have to include the current + * NV-CONTROL handle in the frame lock group. However, we don't + * want to expose the frame lock page unconditionally (it would + * only confuse most users), so this is as good a condition as + * anything else. + * + * XXX We could also add yet another checkbox in the nvidia-settings + * Options page. + */ - /* create the treeview */ + ret = NvCtrlQueryTargetCount(handle, + NV_CTRL_TARGET_TYPE_FRAMELOCK, + &num_framelocks); + if (ret != NvCtrlSuccess) return NULL; + if (!num_framelocks) return NULL; - ctk_framelock->treeview = - GTK_TREE_VIEW(gtk_tree_view_new_with_model - (GTK_TREE_MODEL(ctk_framelock->list_store))); + /* 1. - Create the frame lock widgets */ + + /* create the frame lock page object */ - gtk_tree_view_set_rules_hint(ctk_framelock->treeview, TRUE); + object = g_object_new(CTK_TYPE_FRAMELOCK, NULL); - g_object_unref(ctk_framelock->list_store); + ctk_framelock = CTK_FRAMELOCK(object); + ctk_framelock->attribute_handle = handle; + ctk_framelock->ctk_config = ctk_config; + ctk_framelock->parent_window = GTK_WINDOW(parent_window); - /* watch for selection changes to the treeview */ - - selection = gtk_tree_view_get_selection(ctk_framelock->treeview); + /* create the watch cursor */ + + ctk_framelock->wait_cursor = gdk_cursor_new(GDK_WATCH); + + /* create dialog windows */ + + ctk_framelock->add_devices_dialog = + create_add_devices_dialog(ctk_framelock); + + ctk_framelock->remove_devices_dialog = + create_remove_devices_dialog(ctk_framelock); + + ctk_framelock->error_msg_dialog = + create_error_msg_dialog(ctk_framelock); + + /* create buttons */ + + button = my_button_new_with_label("Add Devices...", 15, 0); + g_signal_connect_swapped(G_OBJECT(button), + "clicked", G_CALLBACK(gtk_widget_show_all), + (gpointer) ctk_framelock->add_devices_dialog); + ctk_config_set_tooltip(ctk_config, button, __add_devices_button_help); + ctk_framelock->add_devices_button = button; + + button = my_button_new_with_label("Remove Devices...", 15, 0); + g_signal_connect(G_OBJECT(button), + "clicked", G_CALLBACK(show_remove_devices_dialog), + GTK_OBJECT(ctk_framelock)); + ctk_config_set_tooltip(ctk_config, button, + __remove_devices_button_help); + ctk_framelock->remove_devices_button = button; + + button = my_toggle_button_new_with_label("Short Names", 15, 0); + // g_signal_connect(G_OBJECT(button), + // "toggled", G_CALLBACK(toggle_short_names), + // GTK_OBJECT(ctk_framelock)); + ctk_framelock->short_labels_button = button; + + button = my_toggle_button_new_with_label("Show Extra Info", 15, 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); + g_signal_connect(G_OBJECT(button), + "toggled", G_CALLBACK(toggle_extra_info), + (gpointer) ctk_framelock); + ctk_config_set_tooltip(ctk_config, button, + __show_extra_info_button_help); + ctk_framelock->extra_info_button = button; + + + button = gtk_check_button_new_with_label("Use House Sync if Present"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); + g_signal_connect(G_OBJECT(button), + "toggled", G_CALLBACK(toggle_use_house_sync), + (gpointer) ctk_framelock); + ctk_config_set_tooltip(ctk_config, button, + __use_house_sync_button_help); + ctk_framelock->use_house_sync = button; + + + button = my_toggle_button_new_with_label("Detect", 15, 0); + g_signal_connect(G_OBJECT(button), + "toggled", G_CALLBACK(toggle_detect_video_mode), + GTK_OBJECT(ctk_framelock)); + ctk_config_set_tooltip(ctk_config, button, + __detect_video_mode_button_help); + ctk_framelock->video_mode_detect = button; + + + button = my_toggle_button_new_with_label("Test Link", 15, 0); + gtk_widget_set_sensitive(button, FALSE); + g_signal_connect(G_OBJECT(button), "toggled", + G_CALLBACK(toggle_test_link), + GTK_OBJECT(ctk_framelock)); + ctk_config_set_tooltip(ctk_config, button, + __test_link_button_help); + ctk_framelock->test_link_button = button; - g_signal_connect(selection, "changed", - G_CALLBACK(tree_selection_changed), + + button = create_sync_state_button(ctk_framelock); + gtk_widget_set_sensitive(button, FALSE); + g_signal_connect(G_OBJECT(button), "toggled", + G_CALLBACK(toggle_sync_enable), GTK_OBJECT(ctk_framelock)); + ctk_config_set_tooltip(ctk_config, button, __sync_enable_button_help); + ctk_framelock->sync_state_button = button; + + /* Create combo boxes */ - /* add columns to the tree view */ + combo = gtk_combo_new(); + glist = NULL; + glist = g_list_append + (glist, + houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO]); + glist = g_list_append + (glist, + houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL]); + glist = g_list_append + (glist, + houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL]); + glist = g_list_append + (glist, houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL]); - add_columns_to_treeview(ctk_framelock); + gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); + gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE); + g_signal_connect(G_OBJECT(GTK_EDITABLE(GTK_COMBO(combo)->entry)), + "changed", G_CALLBACK(changed_video_mode), + (gpointer) ctk_framelock); + ctk_config_set_tooltip(ctk_config, combo, + __video_mode_combo_help); + ctk_framelock->video_mode_combo = combo; -} /* create_list_store() */ + combo = gtk_combo_new(); + glist = NULL; + glist = g_list_append(glist, + syncEdgeStrings[NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE]); + glist = g_list_append(glist, + syncEdgeStrings[NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE]); + glist = g_list_append(glist, + syncEdgeStrings[NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES]); + + gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); + gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE); + g_signal_connect(G_OBJECT(GTK_EDITABLE(GTK_COMBO(combo)->entry)), + "changed", G_CALLBACK(changed_sync_edge), + (gpointer) ctk_framelock); + ctk_config_set_tooltip(ctk_config, combo, + __sync_edge_combo_help); + ctk_framelock->sync_edge_combo = combo; -/* - * add_member_to_list_store() - */ + /* Cache images */ -static void add_member_to_list_store(CtkFramelock *ctk_framelock, - const gpointer handle) -{ - GtkTreeIter iter; - GtkTreeModel *model; - gint master, stereo_sync, timing, sync_ready, sync_rate; - gint house, port0, port1, polarity, sync_skew, display_mask; - gint sync_interval, house_format; - gboolean valid, have_master; - gchar *display_name; + ctk_framelock->led_grey = ctk_image_new(&led_grey); + ctk_framelock->led_green = ctk_image_new(&led_green); + ctk_framelock->led_red = ctk_image_new(&led_red); - /* - * If we don't have a master already, make this the master; if we - * do have a master already, make sure this isn't the master. - */ + ctk_framelock->rj45_input = ctk_image_new(&rj45_input); + ctk_framelock->rj45_output = ctk_image_new(&rj45_output); + ctk_framelock->rj45_unused = ctk_image_new(&rj45_unused); - have_master = FALSE; - model = GTK_TREE_MODEL(ctk_framelock->list_store); + g_object_ref(ctk_framelock->led_grey); + g_object_ref(ctk_framelock->led_green); + g_object_ref(ctk_framelock->led_red); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_MASTER, &have_master, -1); - if (have_master) break; - valid = gtk_tree_model_iter_next(model, &iter); - } + g_object_ref(ctk_framelock->rj45_input); + g_object_ref(ctk_framelock->rj45_output); + g_object_ref(ctk_framelock->rj45_unused); + + /* create the custom tree */ - master = !have_master; + ctk_framelock->tree = (gpointer)(list_tree_new(ctk_framelock)); - NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER, master); + + /* 2. - Pack frame lock widgets */ + + gtk_box_set_spacing(GTK_BOX(ctk_framelock), 10); + + /* banner */ + + banner = ctk_banner_image_new(&frame_lock_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_framelock), banner, FALSE, FALSE, 0); + + /* G-Sync Frame */ + + frame = gtk_frame_new(NULL); + gtk_frame_set_label(GTK_FRAME(frame), "G-Sync Devices"); + gtk_box_pack_start(GTK_BOX(ctk_framelock), frame, TRUE, TRUE, 0); + + /* scrollable window */ - /* query all the other fields */ + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + padding = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(padding), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(padding), sw); + gtk_container_add(GTK_CONTAINER(frame), padding); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, &stereo_sync); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_TIMING, &timing); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_READY, &sync_ready); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &sync_rate); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT0_STATUS, &port0); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT1_STATUS, &port1); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_POLARITY, &polarity); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_DELAY, &sync_skew); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL,&sync_interval); - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, &house_format); + /* create a viewport so we can have a white background */ - NvCtrlGetAttribute(handle, NV_CTRL_ENABLED_DISPLAYS, &display_mask); + vp = gtk_viewport_new(NULL, NULL); + SELECT_WIDGET(vp, GTK_STATE_NORMAL); + gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(vp)); + /** XXX **/gtk_widget_set_size_request(sw, 850, 200);/** XXX **/ - gtk_list_store_append(ctk_framelock->list_store, &iter); + /* add the custom tree & buttons */ + + vbox = ((nvListTreePtr)(ctk_framelock->tree))->vbox; - display_name = NvCtrlGetDisplayName(handle); + gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(vp), vbox); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->extra_info_button, + FALSE, FALSE, 0); + // XXX Add me later.... + // + // gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->short_labels_button, + // FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->remove_devices_button, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->add_devices_button, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(padding), hbox, FALSE, FALSE, 0); + + /* add the house sync frame */ - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_HANDLE, handle, - COLUMN_DISPLAY_MASK, display_mask, - COLUMN_DISPLAY_NAME, display_name, - COLUMN_MASTER, master, - COLUMN_STEREO_SYNC, stereo_sync, - COLUMN_TIMING, timing, - COLUMN_SYNC_READY, sync_ready, - COLUMN_SYNC_RATE, sync_rate, - COLUMN_HOUSE, house, - COLUMN_RJ45_PORT0, port0, - COLUMN_RJ45_PORT1, port1, - COLUMN_POLARITY, polarity, - COLUMN_SYNC_SKEW, sync_skew, - COLUMN_SYNC_INTERVAL, sync_interval, - COLUMN_HOUSE_FORMAT, house_format, - -1); + frame = gtk_frame_new(NULL); + ctk_framelock->house_sync_frame = frame; + gtk_frame_set_label(GTK_FRAME(frame), "House Sync"); + gtk_box_pack_start(GTK_BOX(ctk_framelock), frame, FALSE, FALSE, 0); -} /* add_member_to_list_store() */ + padding = gtk_hbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(padding), FRAME_PADDING); + gtk_container_add(GTK_CONTAINER(frame), padding); + /* add house sync BNC connector image */ + image = ctk_image_new(&bnc_cable); + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), image, FALSE, FALSE, 0); -static gboolean check_for_ethernet(gpointer user_data) -{ - CtkFramelock *ctk_framelock; - GtkTreeIter iter; - GtkTreeModel *model; + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(padding), hbox, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->use_house_sync, + FALSE, FALSE, 0); - NvCtrlAttributeHandle *handle; - gchar *display_name; - gboolean valid; - gint val; + padding = gtk_hbox_new(FALSE, 5); + ctk_framelock->house_sync_hbox = padding; + gtk_box_pack_start(GTK_BOX(vbox), padding, FALSE, FALSE, 0); - static gboolean first_error = TRUE; + /* add the house sync interval */ + { + GtkWidget *frame2 = gtk_frame_new(NULL); + hbox = gtk_hbox_new(FALSE, 5); + label = gtk_label_new("Sync Interval:"); + entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(entry), "0"); + gtk_entry_set_width_chars(GTK_ENTRY(entry), 4); + g_signal_connect(G_OBJECT(entry), + "activate", G_CALLBACK(activate_sync_interval), + (gpointer) ctk_framelock); + ctk_config_set_tooltip(ctk_config, entry, __sync_interval_entry_help); + ctk_framelock->sync_interval_frame = frame2; + ctk_framelock->sync_interval_entry = entry; + + gtk_box_pack_start(GTK_BOX(padding), frame2, FALSE, FALSE, 0); + + gtk_entry_set_text(GTK_ENTRY(entry), "0"); + gtk_entry_set_width_chars(GTK_ENTRY(entry), 4); + + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 5); + + gtk_container_add(GTK_CONTAINER(frame2), hbox); + } + + /* add the house sync video mode & detect */ + { + GtkWidget *frame2 = gtk_frame_new(NULL); + hbox = gtk_hbox_new(FALSE, 5); + label = gtk_label_new("Sync Edge:"); + + ctk_framelock->sync_edge_frame = frame2; + + gtk_box_pack_start(GTK_BOX(padding), frame2, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame2), hbox); + + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->sync_edge_combo, + FALSE, FALSE, 5); + } + + /* add the house sync video mode & detect */ + { + GtkWidget *frame2 = gtk_frame_new(NULL); + hbox = gtk_hbox_new(FALSE, 5); + label = gtk_label_new("Video Mode:"); + + ctk_framelock->video_mode_frame = frame2; + + gtk_box_pack_start(GTK_BOX(padding), frame2, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame2), hbox); + + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->video_mode_combo, + FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->video_mode_detect, + FALSE, TRUE, 5); + } + + /* add main buttons */ + + hbox = gtk_hbox_new(FALSE, 5); + + gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->sync_state_button, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox), ctk_framelock->test_link_button, + FALSE, FALSE, 0); - ctk_framelock = CTK_FRAMELOCK(user_data); - model = GTK_TREE_MODEL(ctk_framelock->list_store); + gtk_box_pack_start(GTK_BOX(ctk_framelock), hbox, FALSE, FALSE, 0); + + /* show everything */ + + gtk_widget_show_all(GTK_WIDGET(object)); + + /* apply the parsed attribute list */ + + apply_parsed_attribute_list(ctk_framelock, p); - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, - COLUMN_DISPLAY_NAME, &display_name, -1); - if (!handle) break; + /* update state of frame lock controls */ - NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_ETHERNET_DETECTED, &val); + update_framelock_controls(ctk_framelock); + + /* register a timer callback to update the status of the page */ + + ctk_config_add_timer(ctk_config, DEFAULT_UPDATE_STATUS_TIME_INTERVAL, + "Frame Lock Connection Status", + (GSourceFunc) update_framelock_status, + (gpointer) ctk_framelock); - if (val != NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_NONE) { + /* register a timer callback to check the rj45 ports */ - if (first_error) { - error_msg(ctk_framelock, "<span weight=\"bold\" " - "size=\"larger\">FrameLock RJ45 Error</span>\n\n" - "Either an Ethernet LAN cable is connected to the " - "framelock board on X Screen '%s' or the linked " - "PC is not turned on. Either disconnect the LAN " - "cable or turn on the linked PC for proper " - "operation.", - display_name); - } - first_error = FALSE; + ctk_config_add_timer(ctk_config, DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL, + "Frame Lock RJ45 Check", + (GSourceFunc) check_for_ethernet, + (gpointer) ctk_framelock); - return TRUE; - } + return GTK_WIDGET(object); + +} /* ctk_framelock_new() */ - valid = gtk_tree_model_iter_next(model, &iter); - } - first_error = TRUE; - return TRUE; +/************************************************************************/ + +/* + * functions relating to add_devices_dialog + */ + + +/** add_devices_respond_ok() ***************************************** + * + * Callback function used to allow user to press the <RETURN> key + * when entering the name of the X Server to add to the frame lock + * group in the add_devices_dialog. + * + */ +static void add_devices_repond_ok(GtkWidget *entry, gpointer data) +{ + add_devices_response(entry, GTK_RESPONSE_OK, data); } -static gboolean find_master(CtkFramelock *ctk_framelock, - GtkTreeIter *return_iter, - NvCtrlAttributeHandle **return_handle) +/** add_devices_response() ******************************************* + * + * Callback function for the "response" event of the "Add X Server" + * dialog box. + * + */ +static void add_devices_response(GtkWidget *button, gint response, + gpointer user_data) { - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - NvCtrlAttributeHandle *handle = NULL; - gboolean master = FALSE, valid; - GtkTreeIter iter; + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + const gchar *display_name; + gint devices_added; + + /* hide the dialog box */ + + gtk_widget_hide_all(ctk_framelock->add_devices_dialog); + + /* set the focus back to the text entry */ + + gtk_widget_grab_focus(ctk_framelock->add_devices_entry); + + /* if the response is not "OK" then we're done */ + + if (response != GTK_RESPONSE_OK) return; + + /* get the display name specified by the user */ - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { - gtk_tree_model_get(model, &iter, - COLUMN_MASTER, &master, - COLUMN_HANDLE, &handle, - -1); - if (master) break; + display_name = + gtk_entry_get_text(GTK_ENTRY(ctk_framelock->add_devices_entry)); - valid = gtk_tree_model_iter_next(model, &iter); + /* Add all devices found on the server */ + + devices_added = add_devices(ctk_framelock, display_name, TRUE); + if (!devices_added) { + /* Nothing was added, nothing to update */ + return; } - if (return_iter) *return_iter = iter; - if (return_handle) *return_handle = handle; + /* Update frame lock controls */ - return master; + update_framelock_controls(ctk_framelock); + + /* Update frame lock status */ + + update_framelock_status(ctk_framelock); + + /* Update status bar */ + + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Added X Server '%s'", display_name); } -/* - * ctk_framelock_config_file_attributes() - add to the ParsedAttribute - * list any attributes that we want saved in the config file. +/** remove_devices_response() **************************************** + * + * Callback function for the "response" event of the "Remove Devices" + * dialog box. + * */ - -void ctk_framelock_config_file_attributes(GtkWidget *w, ParsedAttribute *head) +static void remove_devices_response(GtkWidget *button, gint response, + gpointer user_data) { - CtkFramelock *ctk_framelock = CTK_FRAMELOCK(w); - GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store); - GtkTreeIter iter; - gboolean master, valid; - gchar *display_name; - guint polarity, display_mask; - gint delay, sync_interval, house_format; - ParsedAttribute a; + CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data); + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); + nvListEntryPtr entry = tree->selected_entry; + gchar *label; - valid = gtk_tree_model_get_iter_first(model, &iter); - while (valid) { + gtk_widget_hide_all(ctk_framelock->remove_devices_dialog); - /* - * XXX is it sufficient to use sw state, or should we query - * the hw? - */ + if (response != GTK_RESPONSE_OK) return; - gtk_tree_model_get(model, &iter, - COLUMN_DISPLAY_NAME, &display_name, - COLUMN_MASTER, &master, - COLUMN_POLARITY, &polarity, - COLUMN_SYNC_SKEW, &delay, - COLUMN_DISPLAY_MASK, &display_mask, - COLUMN_SYNC_INTERVAL,&sync_interval, - COLUMN_HOUSE_FORMAT, &house_format, - -1); - -#define __ADD_ATTR(x,y,z) \ - a.display = display_name; \ - a.attr = (x); \ - a.val = (y); \ - a.display_device_mask = (z); \ - nv_parsed_attribute_add(head, &a); + if (!entry) return; - __ADD_ATTR(NV_CTRL_FRAMELOCK_MASTER, master, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_POLARITY, polarity, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_DELAY, delay, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC, - ctk_framelock->framelock_enabled, display_mask); + label = get_entry_label(entry, 0); - if (master) { - __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_INTERVAL, sync_interval, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_VIDEO_MODE, house_format, 0); - } + /* Remove entry from list */ + list_tree_remove_entry(tree, entry); -#undef __ADD_ATTR + /* If there are no entries left, Update the frame lock GUI */ + if (!tree->nentries) { - valid = gtk_tree_model_iter_next(model, &iter); + /* Nothing to house sync to */ + if (ctk_framelock->use_house_sync) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_framelock->use_house_sync), FALSE); + } + + /* Force frame lock state to OFF if it was on */ + ctk_framelock->framelock_enabled = FALSE; } -} /* ctk_framelock_config_file_attributes() */ + update_framelock_controls(ctk_framelock); -/* - * apply_parsed_attribute_list() - given a list of parsed attributes - * from the config file, apply the FrameLock settings contained - * therein. - */ + /* Update status bar */ -static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock, - ParsedAttribute *p) + ctk_config_statusbar_message(ctk_framelock->ctk_config, + "Removed '%s' from the frame lock group.", + label); + g_free(label); +} + + + +/** add_display_devices() ******************************************** + * + * Adds (as children list entries) all enabled display devices that + * are bound to the given GPU List Entry. + * + */ +static unsigned int add_display_devices(CtkFramelock *ctk_framelock, + nvListEntryPtr gpu_entry) { - GtkTreeModel *model; - GtkTreeIter iter; - gpointer h, h_tmp; - gboolean valid, enable = FALSE; - gchar *display_name, *display_name_tmp; + unsigned int displays_added = 0; + nvDisplayDataPtr display_data = NULL; + + nvGPUDataPtr gpu_data; + nvListEntryPtr entry; + ReturnStatus ret; - while (p) { - - if (!p->next) goto next_attribute; + unsigned int enabled_displays; + unsigned int display_mask; + + unsigned int master_mask; + unsigned int slaves_mask; + gfloat fvalue; /* To print the refresh rate */ + gchar str[32]; - if (!(p->flags & NV_PARSER_TYPE_FRAMELOCK)) goto next_attribute; - - /* - * canonicalize the display name, so that we have a better - * chance of finding matches when we compare them below - */ - - display_name = nv_standardize_screen_name(p->display, -1); - - /* - * find the NvCtrlAttributeHandle associated with this display - * name; either there is already an entry in the model with - * the same display name, and we can use its handle; or we add - * this display to the model and get a new handle. As a side - * effect, we should end up with an iter that points into the - * correct entry in the model. - */ - - h = NULL; - - model = GTK_TREE_MODEL(ctk_framelock->list_store); - valid = gtk_tree_model_get_iter_first(model, &iter); - - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_DISPLAY_NAME, - &display_name_tmp, -1); - if (nv_strcasecmp(display_name_tmp, display_name)) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &h, -1); - break; - } - - valid = gtk_tree_model_iter_next(model, &iter); + nvListEntryPtr server_entry = NULL; + nvDisplayDataPtr server_data = NULL; + + + if (!gpu_entry || gpu_entry->data_type != ENTRY_DATA_GPU) { + goto fail; + } + + server_entry = get_display_server_entry((nvListTreePtr)(ctk_framelock->tree)); + if (server_entry) { + server_data = (nvDisplayDataPtr)(server_entry->data); + } + + gpu_data = (nvGPUDataPtr)(gpu_entry->data); + + /* Query list of devices on this GPU. */ + ret = NvCtrlGetAttribute(gpu_data->handle, + NV_CTRL_ENABLED_DISPLAYS, + &enabled_displays); + if (ret != NvCtrlSuccess || !enabled_displays) { + goto fail; + } + + /* Query master device */ + ret = NvCtrlGetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_MASTER, + &master_mask); + if (ret != NvCtrlSuccess) { + goto fail; + } + + /* Query slave devices */ + ret = NvCtrlGetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_SLAVES, + &slaves_mask); + if (ret != NvCtrlSuccess) { + goto fail; + } + + /* If the tree already has a master and this display is also set + * as master, unset this entry and make it a slave. */ + if (server_entry && master_mask) { + + /* XXXvm What if this GPU has Sync enabled? */ + + ret = NvCtrlSetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_MASTER, 0); + if (ret != NvCtrlSuccess) { + goto fail; + } + slaves_mask |= master_mask; + master_mask = 0; + ret = NvCtrlSetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_SLAVES, slaves_mask); + if (ret != NvCtrlSuccess) { + goto fail; } + } + + /* Cache the server/clients masks */ + gpu_data->server_mask = master_mask; + gpu_data->clients_mask = slaves_mask; - if (!h) { - h = add_x_screen(ctk_framelock, display_name, FALSE); + + /* Add all enabled displays found on the GPU */ + display_mask = 1; + while (display_mask) { + if (display_mask & enabled_displays) { + + /* Create the display structure */ + display_data = + (nvDisplayDataPtr) calloc(1, sizeof(nvDisplayDataRec)); + if (!display_data) { + goto fail; + } - if (!h) goto next_attribute; + /* Setup the display information */ + display_data->handle = gpu_data->handle; + display_data->device_mask = display_mask; + + ret = NvCtrlGetDisplayAttribute(gpu_data->handle, + display_mask, + NV_CTRL_FRAMELOCK_MASTERABLE, + &(display_data->masterable)); + if (ret != NvCtrlSuccess) { + goto fail; + } + + ret = NvCtrlGetDisplayAttribute(gpu_data->handle, + display_mask, + NV_CTRL_REFRESH_RATE, + &(display_data->rate)); + if (ret != NvCtrlSuccess) { + goto fail; + } + + display_data->label = gtk_label_new(""); + + display_data->server_label = gtk_label_new("Server"); + display_data->server_checkbox = gtk_check_button_new(); + ctk_config_set_tooltip(ctk_framelock->ctk_config, + display_data->server_checkbox, + __server_checkbox_help); + + display_data->client_label = gtk_label_new("Client"); + display_data->client_checkbox = gtk_check_button_new(); + ctk_config_set_tooltip(ctk_framelock->ctk_config, + display_data->client_checkbox, + __client_checkbox_help); + + display_data->rate_label = gtk_label_new("Refresh:"); + 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); + + /* Create the display entry */ + entry = list_entry_new_with_display(display_data); - model = GTK_TREE_MODEL(ctk_framelock->list_store); - valid = gtk_tree_model_get_iter_first(model, &iter); + update_entry_label(ctk_framelock, entry); + list_entry_update_status(ctk_framelock, entry); + + /* Add display to GPU entry */ + list_entry_add_child(gpu_entry, entry); - while (valid) { - gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &h_tmp, -1); + /* Setup state */ + if (!display_data->masterable) { + gtk_widget_set_sensitive(display_data->server_label, FALSE); + gtk_widget_set_sensitive(display_data->server_checkbox, FALSE); + + } else if (master_mask & display_mask) { - if (h == h_tmp) break; - valid = gtk_tree_model_iter_next(model, &iter); + /* If this entry is the new master, make the tree point + * point to it so other displays that may have the master + * mask aren't added as masters too by mistake. + * + * NOTE: At this point the entry will not actually + * be in the tree. This gets resolved since + * by adding this display device the parent + * GPU and frame lock devices will also be + * added. If this changes (display device + * gets added but for some reason the GPU/ + * frame lock device get thrown out), then + * more code will be required to make sure + * the tree->selected_entry is set to NULL + * (if it was NULL before.) + */ + ((nvListTreePtr)(ctk_framelock->tree))->server_entry = + entry; + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox), TRUE); + gtk_widget_set_sensitive(display_data->client_label, FALSE); + gtk_widget_set_sensitive(display_data->client_checkbox, FALSE); + } + + /* Set display device as slave */ + if (slaves_mask & display_mask) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), TRUE); + gtk_widget_set_sensitive(display_data->server_label, FALSE); + gtk_widget_set_sensitive(display_data->server_checkbox, FALSE); } - } - - /* - * now that we have an NvCtrlAttributeHandle and iter, apply - * the setting; note that this only really updates the gui, - * but the attributes have already been sent to the X server - * by the config file parser. - */ - - switch (p->attr) { - case NV_CTRL_FRAMELOCK_MASTER: - /* XXX only allow one master */ + /* Connect signals */ + g_signal_connect(G_OBJECT(display_data->server_checkbox), + "toggled", + G_CALLBACK(toggle_server), + (gpointer) entry); - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_MASTER, p->val, -1); - break; + g_signal_connect(G_OBJECT(display_data->client_checkbox), + "toggled", + G_CALLBACK(toggle_client), + (gpointer) entry); - case NV_CTRL_FRAMELOCK_POLARITY: - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_POLARITY, p->val, -1); - break; + displays_added++; + } + display_mask <<= 1; + } + + return displays_added; + + + /* Handle failures */ + fail: + if (display_data) { + free(display_data); + } + return displays_added; +} + + + +/** add_gpu_devices() ************************************************ + * + * Adds (as children list entries) all GPU devices that are bound to + * the given frame lock list entry. + * + */ +static unsigned int add_gpu_devices(CtkFramelock *ctk_framelock, + nvListEntryPtr framelock_entry) +{ + unsigned int num_gpus; + unsigned int gpus_added = 0; + unsigned int gpu_id; + unsigned int gpu_idx; + nvGPUDataPtr gpu_data = NULL; + nvFrameLockDataPtr framelock_data; + nvListEntryPtr entry; + ReturnStatus ret; + + unsigned char *data = NULL; + int len = 0; + int *gpus; + + + if (!framelock_entry || + framelock_entry->data_type != ENTRY_DATA_FRAMELOCK) { + goto fail; + } + + /* Get number of GPU devices connected to this frame lock board */ + framelock_data = (nvFrameLockDataPtr)(framelock_entry->data); + ret = NvCtrlGetBinaryAttribute(framelock_data->handle, + 0, + NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, + &data, + &len); + if (ret != NvCtrlSuccess) { + goto fail; + } + + gpus = (int *)data; + num_gpus = gpus[0]; + for (gpu_idx = 0; gpu_idx < num_gpus; gpu_idx++) { + int displays_added = 0; + + gpu_id = gpus[gpu_idx +1]; + + /* Create the GPU data structure */ + gpu_data = (nvGPUDataPtr) calloc(1, sizeof(nvGPUDataRec)); + if (!gpu_data) { + goto fail; + } + + /* Create the GPU handle and label */ + gpu_data->handle = + NvCtrlAttributeInit(NvCtrlGetDisplayPtr(framelock_data->handle), + NV_CTRL_TARGET_TYPE_GPU, + gpu_id, + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + gpu_data->label = gtk_label_new(""); + + /* Create the GPU list entry */ + entry = list_entry_new_with_gpu(gpu_data); + + update_entry_label(ctk_framelock, entry); + list_entry_update_status(ctk_framelock, entry); + + /* Add Displays tied to this GPU */ + displays_added = add_display_devices(ctk_framelock, entry); + if (displays_added) { + list_entry_add_child(framelock_entry, entry); + + /* Check to see if we should reflect in the GUI that + * frame lock is enabled. This should happen if we are + * adding a gpu that has FRAMELOCK_SYNC set to enable. + */ + if (!ctk_framelock->framelock_enabled) { + NvCtrlGetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_SYNC, + &(ctk_framelock->framelock_enabled)); + } + + entry->ctk_event = CTK_EVENT(ctk_event_new(gpu_data->handle)); - case NV_CTRL_FRAMELOCK_SYNC_DELAY: - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_SYNC_SKEW, p->val, -1); - break; + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_MASTER), + G_CALLBACK(gpu_state_received), + (gpointer) entry); - case NV_CTRL_FRAMELOCK_SYNC: - if (p->val) enable = TRUE; - break; + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SLAVES), + G_CALLBACK(gpu_state_received), + (gpointer) entry); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SYNC), + G_CALLBACK(gpu_state_received), + (gpointer) entry); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_TEST_SIGNAL), + G_CALLBACK(gpu_state_received), + (gpointer) entry); + + gpus_added++; + } else { + /* No Displays found, don't add this GPU device */ + list_entry_free(entry); + } + } - case NV_CTRL_FRAMELOCK_SYNC_INTERVAL: - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_SYNC_INTERVAL, p->val, -1); - break; + return gpus_added; - case NV_CTRL_FRAMELOCK_VIDEO_MODE: - gtk_list_store_set(ctk_framelock->list_store, &iter, - COLUMN_HOUSE_FORMAT, p->val, -1); - break; + + /* Handle failures */ + fail: + if (gpu_data) { + if (gpu_data->handle) { + NvCtrlAttributeClose(gpu_data->handle); } + free(gpu_data); + } + return gpus_added; +} + + + +/** add_framelock_devices() ****************************************** + * + * Adds all frame lock devices found on the given server handle to + * the frame lock group, + * + */ +static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock, + gpointer handle) +{ + unsigned int num_framelocks; + unsigned int framelocks_added = 0; + unsigned int framelock_id; + nvFrameLockDataPtr framelock_data = NULL; + nvListEntryPtr entry; + ReturnStatus ret; + + + /* 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); + if (ret != NvCtrlSuccess) { + goto fail; + } + + /* Add frame lock devices found */ + for (framelock_id = 0; framelock_id < num_framelocks; framelock_id++) { + int gpus_added = 0; + + /* Create the frame lock data structure */ + framelock_data = + (nvFrameLockDataPtr) calloc(1, sizeof(nvFrameLockDataRec)); + if (!framelock_data) { + goto fail; + } + + /* Create the frame lock handle and label */ + framelock_data->handle = + NvCtrlAttributeInit(NvCtrlGetDisplayPtr(handle), + NV_CTRL_TARGET_TYPE_FRAMELOCK, + framelock_id, + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + + framelock_data->label = gtk_label_new(""); - next_attribute: + framelock_data->receiving_label = gtk_label_new("Receiving:"); + framelock_data->receiving_hbox = gtk_hbox_new(FALSE, 0); + + framelock_data->rate_label = gtk_label_new("Rate:"); + framelock_data->rate_text = gtk_label_new(""); + + framelock_data->delay_label = gtk_label_new("Delay:"); + framelock_data->delay_text = gtk_label_new(""); + + framelock_data->house_label = gtk_label_new("House:"); + framelock_data->house_hbox = gtk_hbox_new(FALSE, 0); + + framelock_data->port0_label = gtk_label_new("Port 0:"); + framelock_data->port0_hbox = gtk_hbox_new(FALSE, 0); + + framelock_data->port1_label = gtk_label_new("Port 1:"); + framelock_data->port1_hbox = gtk_hbox_new(FALSE, 0); + + framelock_data->extra_info_hbox = gtk_hbox_new(FALSE, 5); + + /* Create the frame lock list entry */ + entry = list_entry_new_with_framelock(framelock_data); + + update_entry_label(ctk_framelock, entry); + list_entry_update_status(ctk_framelock, entry); - p = p->next; + /* Add GPUs tied to this G-Sync */ + gpus_added = add_gpu_devices(ctk_framelock, entry); + if (gpus_added) { + list_tree_add_entry((nvListTreePtr)(ctk_framelock->tree), + entry); + + entry->ctk_event = + CTK_EVENT(ctk_event_new(framelock_data->handle)); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_USE_HOUSE_SYNC), + G_CALLBACK(framelock_state_received), + (gpointer) entry); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SYNC_INTERVAL), + G_CALLBACK(framelock_state_received), + (gpointer) entry); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_POLARITY), + G_CALLBACK(framelock_state_received), + (gpointer) entry); + + g_signal_connect(G_OBJECT(entry->ctk_event), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_VIDEO_MODE), + G_CALLBACK(framelock_state_received), + (gpointer) entry); + + framelocks_added++; + } else { + /* No GPUs found, don't add this frame lock device */ + list_entry_free(entry); + } + } + + return framelocks_added; + + + /* Handle failures */ + fail: + if (framelock_data) { + if (framelock_data->handle) { + NvCtrlAttributeClose(framelock_data->handle); + } + free(framelock_data); + } + return framelocks_added; +} + + + +/** add_devices() **************************************************** + * + * Adds all frame lock devices found on the given server to the + * frame lock group, + * + */ +static gint add_devices(CtkFramelock *ctk_framelock, + const gchar *display_name, + gboolean error_dialog) +{ + gpointer handle = NULL; + Display *display; + gint devices_added = 0; + char *server_name = NULL; + char *ptr; + + /* if no display name specified, print an error and return */ + + if (!display_name || (display_name[0] == '\0')) { + if (error_dialog) { + error_msg(ctk_framelock, "<span weight=\"bold\" size=\"larger\">" + "Unable to add X Server to frame lock group.</span>\n\n" + "No X Server specified."); + } else { + nv_error_msg("Unable to add X Server to frame lock group; " + "no X Server specified."); + } + goto done; } /* - * set the state of the toggle button appropriately; this will - * trigger toggle_sync_state_button() + * build the server name from the display name by removing any extra + * server number and assuming ":0" if no server id is given */ - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(ctk_framelock->sync_state_button), enable); + /* +2 extra characters in case we need to append ":0" */ + server_name = (char *) malloc(strlen(display_name) +3); + if (!server_name) { + goto done; + } + + sprintf(server_name, "%s", display_name); + ptr = strchr(server_name, ':'); + if (ptr) { + /* Remove screen number information from server name */ + ptr = strchr(ptr, '.'); + if (ptr) *ptr = '\0'; + } else { + /* Assume sever id 0 if none given */ + sprintf(server_name + strlen(server_name), ":0"); + } + + /* + * try to prevent users from adding the same X server more than + * once. + * + * XXX This is not an absolute check: this does not catch + * "localhost:0" versus ":0", for example, nor does it + * catch entering an IP vs entering a hostname. + */ + + if (find_server_by_name(ctk_framelock->tree, server_name)) { + if (error_dialog) { + error_msg(ctk_framelock, "<span weight=\"bold\" " + "size=\"larger\">Unable to add X server " + "to frame lock Group</span>\n\n" + "The X server %s already belongs to the frame lock " + "Group.", server_name); + } else { + nv_error_msg("Unable to add X server to frame lock group; " + "the X server %s already belongs to the " + "frame lock group.", server_name); + } + goto done; + } + + /* open an X Display connection to that X server */ + + display = XOpenDisplay(server_name); + if (!display) { + if (error_dialog) { + error_msg(ctk_framelock, "<span weight=\"bold\" " + "size=\"larger\">Unable " + "to add devices to frame lock group</span>\n\nUnable to " + "connect to X Display '%s'.", server_name); + } else { + nv_error_msg("Unable to add devices to frame lock group; unable " + "to connect to X Display '%s'.", server_name); + } + goto done; + } -} /* apply_parsed_attribute_list () */ + /* create a new NV-CONTROL handle */ + + handle = NvCtrlAttributeInit(display, NV_CTRL_TARGET_TYPE_X_SCREEN, + DefaultScreen(display), + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + if (!handle) { + if (error_dialog) { + error_msg(ctk_framelock, "<span weight=\"bold\" " + "size=\"larger\">Unable " + "to add devices to frame lock group</span>\n\nUnable to " + "create NV-CONTROL handle."); + } else { + nv_error_msg("Unable to add devices to frame lock group; unable " + "create NV-CONTROL handle."); + } + goto done; + } + + /* Add frame lock devices found on server */ + + devices_added = add_framelock_devices(ctk_framelock, handle); + if (!devices_added) { + if (error_dialog) { + error_msg(ctk_framelock, "<span weight=\"bold\" " + "size=\"larger\">No frame lock devices " + "found on server.</span>\n\n" + "This X Server does not support frame lock or " + "no frame lock devices were available."); + } else { + nv_error_msg("No frame lock devices found on server; " + "This X Server does not support frame lock or " + "no frame lock devices were available."); + } + goto done; + } + + /* Fall through */ + done: + if (server_name) { + free(server_name); + } + if (handle) { + NvCtrlAttributeClose(handle); + } + + return devices_added; +} +/** add_entry_to_parsed_attributes() ********************************* + * + * Adds information reguarding a list entry (GPU or Frame Lock + * device) to the parsed attribute list. + * + */ +#define __ADD_ATTR(x,y,z) \ + a.display = display_name; \ + a.target_type = target_type; \ + a.target_id = target_id; \ + a.attr = (x); \ + a.val = (y); \ + a.display_device_mask = (z); \ + a.flags |= NV_PARSER_HAS_TARGET; \ + nv_parsed_attribute_add(head, &a); + +static void add_entry_to_parsed_attributes(nvListEntryPtr entry, + ParsedAttribute *head) +{ + ParsedAttribute a; + char *display_name = NULL; + int target_type = 0; + int target_id = 0; + + if (!entry) return; + + switch (entry->data_type) { + + case ENTRY_DATA_FRAMELOCK: + { + int use_house_sync; + nvFrameLockDataPtr data = (nvFrameLockDataPtr)(entry->data); + display_name = NvCtrlGetDisplayName(data->handle); + target_type = NV_CTRL_TARGET_TYPE_FRAMELOCK; + target_id = NvCtrlGetTargetId(data->handle); + + NvCtrlGetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, + &use_house_sync); + + __ADD_ATTR(NV_CTRL_USE_HOUSE_SYNC, use_house_sync, 0); + + /* If use house sync is enabled, also save other house sync info */ + if (use_house_sync) { + int sync_interval; + int sync_edge; + int video_mode; + + NvCtrlGetAttribute(data->handle, + NV_CTRL_FRAMELOCK_SYNC_INTERVAL, + &sync_interval); + NvCtrlGetAttribute(data->handle, + NV_CTRL_FRAMELOCK_POLARITY, + &sync_edge); + NvCtrlGetAttribute(data->handle, + NV_CTRL_FRAMELOCK_VIDEO_MODE, + &video_mode); + + __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_INTERVAL, sync_interval, 0); + __ADD_ATTR(NV_CTRL_FRAMELOCK_POLARITY, sync_edge, 0); + __ADD_ATTR(NV_CTRL_FRAMELOCK_VIDEO_MODE, video_mode, 0); + } + + if (display_name) { + free(display_name); + } + } + break; + + case ENTRY_DATA_GPU: + { + nvGPUDataPtr data = (nvGPUDataPtr)(entry->data); + display_name = NvCtrlGetDisplayName(data->handle); + target_type = NV_CTRL_TARGET_TYPE_GPU; + target_id = NvCtrlGetTargetId(data->handle); + + __ADD_ATTR(NV_CTRL_FRAMELOCK_MASTER, data->server_mask, 0); + __ADD_ATTR(NV_CTRL_FRAMELOCK_SLAVES, data->clients_mask, 0); + + if (display_name) { + free(display_name); + } + } + break; + + case ENTRY_DATA_DISPLAY: + /* Nothign to save */ + break; + + default: + /* Oops */ + break; + } +} + +#undef __ADD_ATTR + + + +/** add_entries_to_parsed_attributes() ******************************* + * + * Adds GPU settings for server/clients to the parsed attribute + * list. + * + */ +static void add_entries_to_parsed_attributes(nvListEntryPtr entry, + ParsedAttribute *head) +{ + if (!entry) return; + + /* Add GPU entries to parsed attributes list */ + if (entry->data_type == ENTRY_DATA_GPU) { + add_entry_to_parsed_attributes(entry, head); + } + + /* add children */ + add_entries_to_parsed_attributes(entry->children, head); + + /* add siblings */ + add_entries_to_parsed_attributes(entry->next_sibling, head); +} + + + +/* ctk_framelock_config_file_attributes() **************************** + * + * Add to the ParsedAttribute list any attributes that we want saved + * in the config file. + * + * This includes all the clients/server bitmasks for all GPUs and + * the house sync settings of the selected master frame lock device. + * + */ +void ctk_framelock_config_file_attributes(GtkWidget *w, + ParsedAttribute *head) +{ + CtkFramelock *ctk_framelock = (CtkFramelock *) w; + + /* Add attributes from all the list entries */ + add_entries_to_parsed_attributes + (((nvListTreePtr)(ctk_framelock->tree))->entries, head); + + /* Save the frame lock server's hous esync settings */ + add_entry_to_parsed_attributes + (get_framelock_server_entry((nvListTreePtr)(ctk_framelock->tree)), + head); +} + + + +/** apply_parsed_attribute_list() *********************************** + * + * Given a list of parsed attributes from the config file, add all + * X Servers (and their devices) that have to do with frame lock + * to the current frame lock group. + * + */ +static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock, + ParsedAttribute *list) +{ + ParsedAttribute *p; + char *server_name = NULL; + + /* Add frame lock devices for all servers */ + + for (p = list; p && p->next; p = p->next) { + if (server_name) { + free(server_name); + } + server_name = nv_standardize_screen_name(p->display, -2); + if (!server_name) continue; + + /* Not a frame lock attribute */ + if (!(p->flags & NV_PARSER_TYPE_FRAMELOCK)) continue; + + /* Server already added */ + if (find_server_by_name + ((nvListTreePtr)(ctk_framelock->tree), server_name)) continue; + + /* Add all the devices from this attribute's server */ + add_devices(ctk_framelock, server_name, FALSE); + } + + if (server_name) { + free(server_name); + } +} + + + +/** ctk_framelock_create_help() ************************************** + * + * Function to create the frame lock help page. + * + */ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table) { GtkTextIter i; @@ -2795,91 +5021,129 @@ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table) gtk_text_buffer_get_iter_at_offset(b, &i, 0); - ctk_help_title(b, &i, "FrameLock Help"); + ctk_help_title(b, &i, "Frame Lock Help"); - ctk_help_para(b, &i, "The FrameLock control page provides a way to " - "manage an entire cluster of workstations in a FrameLock " + ctk_help_para(b, &i, "The frame lock control page provides a way to " + "manage an entire cluster of workstations in a frame lock " "group."); - - ctk_help_heading(b, &i, "Add X Screen..."); - ctk_help_para(b, &i, "Use this button to add an X Screen to the " - "FrameLock group. If the X Screen is remote, be sure " - "you have configured remote access (via `xhost`, " - "for example) such that you are allowed to establish " - "a connection."); - - ctk_help_heading(b, &i, "Remove X Screen..."); - ctk_help_para(b, &i, "Use this button to remove the currently selected " - "X Screen from the FrameLock group. If no X Screen is " - "currently selected, then this button is greyed out."); + + /* G-Sync Frame Help */ + + ctk_help_heading(b, &i, "G-Sync Section"); + ctk_help_para(b, &i, "The G-Sync section allows you to configure the " + "individual devices that make up the frame lock group."); + + ctk_help_heading(b, &i, "G-Sync Device Entry Information"); + ctk_help_para(b, &i, "G-Sync (frame lock board) device entries display " + "the following information:"); + ctk_help_para(b, &i, "The X server name and G-Sync board ID."); + ctk_help_para(b, &i, "Receiving LED: This indicates whether the frame " + "lock board is receiving a sync pulse. Green means a " + "signal is detected; red means a signal is not detected. " + "The sync pulse can come from one of the following sources: " + "The House Sync signal, an external signal from another " + "frame lock device coming into Port0/Port1, or the internal " + "timing from the primary GPU's display device"); + ctk_help_para(b, &i, "Rate Information: This is the sync rate that the " + "frame lock board is receiving."); + ctk_help_para(b, &i, "House LED: This indicates whether the frame lock " + "board is receiving synchronization from the house (BNC) " + "connector. This LED mirrors the status of the LED on the " + "backplane of the frame lock board."); + ctk_help_para(b, &i, "Port0, Port1 Images: These indicate the status of " + "the RJ45 ports on the backplane of the frame lock board. " + "Green LEDs indicate that the port is configured for " + "input, while yellow LEDs indicate that the port is " + "configured for output."); + ctk_help_para(b, &i, "Delay Information: The sync delay (in microseconds) " + "between the frame lock pulse and the GPU pulse."); + + ctk_help_heading(b, &i, "GPU Device Entry Information"); + 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_heading(b, &i, "Display Device Entry Information"); + ctk_help_para(b, &i, "Display Device entries display information and " + "configuration options for configuring how the dislay " + "device should behave in the frame lock group. Setting of " + "options is only available while frame lock is disabled. " + "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 " + "devices set as clients when frame lock is enabled."); + + ctk_help_heading(b, &i, "Adding Devices"); + ctk_help_para(b, &i, __add_devices_button_help); + ctk_help_para(b, &i, "If the X Server is remote, be sure you have " + "configured remote access (via `xhost`, for example) " + "such that you are allowed to establish a connection."); + + ctk_help_heading(b, &i, "Removing Devices"); + ctk_help_para(b, &i, __remove_devices_button_help); + + /* House Sync Frame Help */ + + ctk_help_heading(b, &i, "House Sync Section"); + ctk_help_para(b, &i, "The House Sync section allows you to configure " + "the selected server G-Sync board for using an incoming " + "house sync signal instead of internal GPU timings. This " + "section is only accesible by selecting a server display " + "device (See Display Device Information above."); + + ctk_help_heading(b, &i, "Use House Sync on Server"); + ctk_help_para(b, &i, __use_house_sync_button_help); + ctk_help_para(b, &i, "If this option is checked and no house signal " + "is detected (House LED is red), the G-Sync device will " + "fall back to using internal timings from the primary GPU."); + + ctk_help_heading(b, &i, "Sync Interval"); + ctk_help_para(b, &i, __sync_interval_entry_help); + + ctk_help_heading(b, &i, "Sync Edge"); + ctk_help_para(b, &i, __sync_edge_combo_help); + ctk_help_para(b, &i, "Syncing to the rising (leading) edge should be " + "suitable for bi-level and TTL signals. Syncing to the " + "falling edge should be used for tri-level signals. " + "Syncing to both edges should only be needed for TTL " + "signals that have problems syncing to the rising edge " + "only."); + + ctk_help_heading(b, &i, "Video Mode"); + ctk_help_para(b, &i, __video_mode_combo_help); + + ctk_help_heading(b, &i, "Video Mode Detect"); + ctk_help_para(b, &i, __detect_video_mode_button_help); + + /* Button Help */ ctk_help_heading(b, &i, "Test Link"); ctk_help_para(b, &i, "Use this toggle button to enable testing of " - "the cabling between all members of the FrameLock group. " - "This will cause all FrameLock boards to receive a sync " - "pulse, but the GPUs will not lock to the FrameLock " + "the cabling between all members of the frame lock group. " + "This will cause all frame lock boards to receive a sync " + "pulse, but the GPUs will not lock to the frame lock " "pulse. When Test Link is enabled, no other settings may " "be changed until you disable Test Link."); - ctk_help_heading(b, &i, "Enable FrameLock"); - ctk_help_para(b, &i, "This will lock the refresh rates of all members " - "in the FrameLock group. When FrameLock is enabled, " - "you cannot add or remove any X screens from the FrameLock " - "group, nor can you enable the Test Link."); - - ctk_help_heading(b, &i, "Display"); - ctk_help_para(b, &i, "The 'Display' column lists the name of each X " - "Screen in the FrameLock group."); - - ctk_help_heading(b, &i, "Master"); - ctk_help_para(b, &i, "This radio button indicates which X Screen in the " - "FrameLock group will emit the master sync pulse to which " - "all other group members will latch."); - - ctk_help_heading(b, &i, "Stereo Sync"); - ctk_help_para(b, &i, "This indicates that the GPU stereo signal is in " - "sync with the framelock stereo signal."); - - ctk_help_heading(b, &i, "Timing"); - ctk_help_para(b, &i, "This indicates that the FrameLock board is " - "receiving a timing input."); - - ctk_help_heading(b, &i, "Sync Ready"); - ctk_help_para(b, &i, "This indicates whether the FrameLock board is " - "receiving sync pulses. Green means syncing; red " - "means not syncing."); - - ctk_help_heading(b, &i, "Sync Rate"); - ctk_help_para(b, &i, "This is the sync rate that the FrameLock board " - "is receiving."); - - ctk_help_heading(b, &i, "House"); - ctk_help_para(b, &i, "This indicates whether the FrameLock board is " - "receiving synchronization from the house (BNC) connector."); - - ctk_help_heading(b, &i, "Port0, Port1"); - ctk_help_para(b, &i, "These indicate the status of the RJ45 ports on " - "the backplane of the FrameLock board. Green LEDs " - "indicate that the port is configured for input, while " - "yellow LEDs indicate that the port is configured for " - "output."); - - ctk_help_heading(b, &i, "Rising/Falling"); - ctk_help_para(b, &i, "These control which edge(s) of the sync pulse " - "are latched to."); - - ctk_help_heading(b, &i, "Sync Delay"); - ctk_help_para(b, &i, "The delay (in microseconds) between the FrameLock " - "pulse and the GPU pulse."); - + ctk_help_heading(b, &i, "Enable Frame Lock"); + ctk_help_para(b, &i, __sync_enable_button_help); + ctk_help_para(b, &i, "Only devices selected as clients or server will be " + "enabled."); + + /* Misc Help */ + ctk_help_heading(b, &i, "Miscellaneous"); - ctk_help_para(b, &i, "The FrameLock control page registers several timers " - "that are executed periodically; these are listed " + ctk_help_para(b, &i, "The frame lock control page registers several " + "timers that are executed periodically; these are listed " "in the 'Active Timers' section of the 'nvidia-settings " - "Configuration' page. Most notably is the " - "'FrameLock Connection Status' " - "timer: this will poll all members of the FrameLock group " - "for status information."); + "Configuration' page. Most notably is the 'Frame Lock " + "Connection Status' timer: this will poll all members of " + "the frame lock group for status information."); ctk_help_finish(b); @@ -2887,28 +5151,42 @@ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table) } + +/** ctk_framelock_select() ******************************************* + * + * Callback function for when the frame lock page is being displayed + * in the control panel. + * + */ void ctk_framelock_select(GtkWidget *w) { CtkFramelock *ctk_framelock = CTK_FRAMELOCK(w); - /* Start the framelock timers */ + /* Start the frame lock timers */ ctk_config_start_timer(ctk_framelock->ctk_config, - (GSourceFunc) update_status); - + (GSourceFunc) update_framelock_status); + ctk_config_start_timer(ctk_framelock->ctk_config, (GSourceFunc) check_for_ethernet); } + +/** ctk_framelock_unselect() ***************************************** + * + * Callback function for when the frame lock page is no longer being + * displayed by the control panel. (User clicked on another page.) + * + */ void ctk_framelock_unselect(GtkWidget *w) { CtkFramelock *ctk_framelock = CTK_FRAMELOCK(w); - /* Stop the framelock timers */ + /* Stop the frame lock timers */ ctk_config_stop_timer(ctk_framelock->ctk_config, - (GSourceFunc) update_status); + (GSourceFunc) update_framelock_status); ctk_config_stop_timer(ctk_framelock->ctk_config, (GSourceFunc) check_for_ethernet); diff --git a/src/gtk+-2.x/ctkframelock.h b/src/gtk+-2.x/ctkframelock.h index 11d7984..46b011e 100644 --- a/src/gtk+-2.x/ctkframelock.h +++ b/src/gtk+-2.x/ctkframelock.h @@ -61,47 +61,65 @@ struct _CtkFramelock GtkVBox parent; NvCtrlAttributeHandle *attribute_handle; + CtkConfig *ctk_config; GtkWindow *parent_window; + GdkCursor *wait_cursor; + + + /* Device tree & buttons */ + gpointer tree; + GtkWidget *add_devices_button; + GtkWidget *remove_devices_button; + GtkWidget *short_labels_button; + GtkWidget *extra_info_button; + + /* House sync */ GtkWidget *house_sync_frame; - GtkWidget *use_house_sync_button; - GtkWidget *sync_interval_entry; + GtkWidget *house_sync_hbox; + GtkWidget *use_house_sync; GtkWidget *sync_interval_frame; + GtkWidget *sync_interval_entry; + GtkWidget *sync_edge_frame; + GtkWidget *sync_edge_combo; + GtkWidget *video_mode_frame; + GtkWidget *video_mode_combo; + GtkWidget *video_mode_detect; - GtkWidget *house_format_combo; - GtkWidget *house_format_frame; - GtkWidget *house_format_detect; gint current_detect_format; - guint house_format_detect_timer; + guint video_mode_detect_timer; - GtkWidget *add_x_screen_dialog; - GtkWidget *add_x_screen_entry; + /* Dialogs */ + GtkWidget *add_devices_dialog; + GtkWidget *add_devices_entry; - GtkWidget *remove_x_screen_dialog; - GtkWidget *remove_x_screen_label; - GtkTreeIter remove_x_screen_iter; + GtkWidget *remove_devices_dialog; + GtkWidget *remove_devices_label; + GtkTreeIter remove_devices_iter; GtkWidget *error_msg_dialog; GtkWidget *error_msg_label; - GtkListStore *list_store; - GtkTreeView *treeview; + /* Buttons */ - GtkWidget *add_x_screen_button; - GtkWidget *remove_x_screen_button; GtkWidget *test_link_button; - GtkWidget *enable_syncing; + gboolean test_link_enabled; GtkWidget *sync_state_button; GtkWidget *enable_syncing_label; GtkWidget *disable_syncing_label; + GtkWidget *selected_syncing_label; + gboolean framelock_enabled; - CtkConfig *ctk_config; - - GdkCursor *wait_cursor; + /* Images */ + GtkWidget *led_grey; + GtkWidget *led_green; + GtkWidget *led_red; - gboolean framelock_enabled; + GtkWidget *rj45_input; + GtkWidget *rj45_output; + GtkWidget *rj45_unused; }; struct _CtkFramelockClass diff --git a/src/gtk+-2.x/ctkglx.c b/src/gtk+-2.x/ctkglx.c index f1dbe29..cd09875 100644 --- a/src/gtk+-2.x/ctkglx.c +++ b/src/gtk+-2.x/ctkglx.c @@ -31,6 +31,7 @@ #include "glxinfo.h" /* xxx_abbrev functions */ #include "glx_banner.h" +#include "ctkimage.h" #include "ctkglx.h" #include "ctkconfig.h" #include "ctkhelp.h" @@ -198,21 +199,16 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle, GObject *object; CtkGLX *ctk_glx; GtkWidget *label; - GtkWidget *image; - GtkWidget *frame; + GtkWidget *banner; GtkWidget *hseparator; GtkWidget *hbox; GtkWidget *vbox, *vbox2; - GtkWidget *alignment; GtkWidget *table; GtkWidget *scrollWin; GtkWidget *event; /* For setting the background color to white */ ReturnStatus ret; - guint8 *image_buffer = NULL; - const nv_image_t *img; - char * glx_info_str = NULL; /* Test if GLX supported */ GLXFBConfigAttr *fbconfig_attribs = NULL; /* FBConfig data */ int i; /* Iterator */ @@ -256,21 +252,10 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle, gtk_box_set_spacing(GTK_BOX(ctk_glx), 10); /* Image banner */ - alignment = gtk_alignment_new(0, 0, 0, 0); - frame = gtk_frame_new(NULL); - img = &glx_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_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(frame), image); - gtk_container_add(GTK_CONTAINER(alignment), frame); - gtk_box_pack_start(GTK_BOX(ctk_glx), alignment, FALSE, FALSE, 0); - + banner = ctk_banner_image_new(&glx_banner_image); + gtk_box_pack_start(GTK_BOX(ctk_glx), banner, FALSE, FALSE, 0); + /* Determine if GLX is supported */ ret = NvCtrlGetStringAttribute(ctk_glx->handle, NV_CTRL_STRING_GLX_SERVER_VENDOR, @@ -296,6 +281,7 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle, event); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); ctk_glx->glxinfo_vpane = vbox; + gtk_widget_set_size_request(scrollWin, -1, 200); /* GLX 1.3 supports frame buffer configurations */ @@ -324,6 +310,7 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(ctk_glx), GTK_WIDGET(vbox), TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), scrollWin, TRUE, TRUE, 0); + gtk_widget_set_size_request(scrollWin, -1, 200); /* * NODE: Because clists have a hard time displaying tooltips in their diff --git a/src/gtk+-2.x/ctkgvo-csc.c b/src/gtk+-2.x/ctkgvo-csc.c new file mode 100644 index 0000000..1a7f06e --- /dev/null +++ b/src/gtk+-2.x/ctkgvo-csc.c @@ -0,0 +1,1047 @@ +/* + * 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 <string.h> + +#include "crt_banner.h" +#include "ctkimage.h" + +#include "ctkgvo-csc.h" + +#include "ctkconfig.h" +#include "ctkhelp.h" + +#include "ctkdropdownmenu.h" + +/* + * The CtkGvoCsc widget is used to provide a way for configuring + * custom Color Space Conversion Matrices, Offsets, and Scale Factors + * on NVIDIA SDI products. At the top, we have a checkbox that + * enables overriding the default CSC matrix. If that checkbox is not + * checked, then everything else on the page is insensitive. + * + * When the "override" checkbox is checked, then the user can modify + * each of the 15 floating point values that comprise the 3x3 matrix, + * 1x3 offset vector, and 1x3 scale vector. + * + * The user can also select from an "Initialization" dropdown menu, to + * initialize the CSC with any of "ITU-601", "ITU-709", "ITU-177", or + * "Identity". + * + * Finally, the user can select how they want changes to be applied: + * by default, they have to click the "Apply" button to flush their + * changes from nvidia-settings out over NV-CONTROL to the NVIDIA + * driver. Alternatively, the user can check the "Apply Changes + * Immediately" checkbox, which will cause changes to be sent to the + * NVIDIA driver whenever the user makes any changes to the CSC. This + * is handy to tweak values in "realtime" while SDI output is enabled. + * + * Note that on older NVIDIA SDI products, changes to CSC require + * stopping and restarting SDI output. Furthermore, on older NVIDIA + * SDI products, CSC only applies to OpenGL SDI output. On newer + * NVIDIA SDI products, the CSC can be applied in real time while CSC + * is enabled, and can apply both to OpenGL and normal X desktop over + * SDI. + */ + +/* + * TODO: ability to save/restore CSC to/from file. + * + * TODO: should use the same banner used on the front SDI page + */ + + +/* local prototypes */ + +static void override_button_toggled (GtkToggleButton *overrideButton, + gpointer user_data); + +static void override_state_toggled (CtkGvoCsc *data, + gboolean enabled); + +static void make_entry (CtkGvoCsc *ctk_gvo_csc, + GtkWidget *table, + GtkWidget **widget, + float value, + int row, + int column); + +static void make_label (CtkGvoCsc *ctk_gvo_csc, + GtkWidget *table, + const char *str, + int row, + int column); + +static void spin_button_value_changed (GtkWidget *button, + gpointer user_data); + +static void apply_immediate_button_toggled (GtkToggleButton + *applyImmediateButton, + gpointer user_data); + +static void apply_button_clicked (GtkButton *button, + gpointer user_data); + +static void initialize_csc_dropdown_changed (CtkDropDownMenu *combo, + gpointer user_data); + +static void set_apply_button_senstive (CtkGvoCsc *ctk_gvo_csc); + +static void apply_csc_values (CtkGvoCsc *ctk_gvo_csc); + +static GtkWidget *build_opengl_only_msg (void); + +/* + * Color Space Conversion Standards + */ + +#define CSC_STANDARD_ITU_601 0 +#define CSC_STANDARD_ITU_709 1 +#define CSC_STANDARD_ITU_177 2 +#define CSC_STANDARD_IDENTITY 3 + +#define CSC_STANDARD_ITU_601_STRING "ITU-601" +#define CSC_STANDARD_ITU_709_STRING "ITU-709" +#define CSC_STANDARD_ITU_177_STRING "ITU-177" +#define CSC_STANDARD_IDENTITY_STRING "Identity" + + + +#define FRAME_BORDER 5 + + + +GType ctk_gvo_csc_get_type(void) +{ + static GType ctk_gvo_csc_type = 0; + + if (!ctk_gvo_csc_type) { + static const GTypeInfo ctk_gvo_csc_info = { + sizeof (CtkGvoCscClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init, */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CtkGvoCsc), + 0, /* n_preallocs */ + NULL, /* instance_init */ + }; + + ctk_gvo_csc_type = + g_type_register_static (GTK_TYPE_VBOX, + "CtkGvoCsc", &ctk_gvo_csc_info, 0); + } + + return ctk_gvo_csc_type; +} + + +/* + * ctk_gvo_csc_new() - create a CtkGvoCsc widget + */ + +GtkWidget* ctk_gvo_csc_new(NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config, + CtkEvent *ctk_event) +{ + GObject *object; + CtkGvoCsc *ctk_gvo_csc; + GtkWidget *banner; + GtkWidget *frame; + GtkWidget *hbox, *hbox2; + GtkWidget *vbox, *vbox2; + GtkWidget *label; + GtkWidget *alignment; + + ReturnStatus ret; + + int row, column, override, caps; + + float initialCSCMatrix[3][3]; + float initialCSCOffset[3]; + float initialCSCScale[3]; + + /* retrieve all the NV-CONTROL attributes that we will need */ + + ret = NvCtrlGetGvoColorConversion(handle, + initialCSCMatrix, + initialCSCOffset, + initialCSCScale); + + if (ret != NvCtrlSuccess) return NULL; + + ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_OVERRIDE_HW_CSC, &override); + + if (ret != NvCtrlSuccess) return NULL; + + ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_CAPABILITIES, &caps); + + if (ret != NvCtrlSuccess) return NULL; + + + /* + * XXX setup to receive events when another NV-CONTROL client + * changes any of the above attributes + */ + + + /* create the object */ + + object = g_object_new(CTK_TYPE_GVO_CSC, NULL); + + ctk_gvo_csc = CTK_GVO_CSC(object); + ctk_gvo_csc->handle = handle; + ctk_gvo_csc->ctk_config = ctk_config; + + 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); + + /* checkbox to enable override of HW CSC */ + + ctk_gvo_csc->overrideButton = gtk_check_button_new_with_label + ("Override default Color Space Conversion"); + + g_signal_connect(GTK_OBJECT(ctk_gvo_csc->overrideButton), "toggled", + G_CALLBACK(override_button_toggled), ctk_gvo_csc); + + frame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); + + gtk_box_pack_start(GTK_BOX(vbox2), + ctk_gvo_csc->overrideButton, + FALSE, // expand + FALSE, // fill + 0); // padding + + gtk_container_add(GTK_CONTAINER(frame), vbox2); + + gtk_box_pack_start(GTK_BOX(ctk_gvo_csc), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + /* create an hbox to store everything else */ + + hbox = gtk_vbox_new(FALSE, 0); + + gtk_box_pack_start(GTK_BOX(ctk_gvo_csc), + hbox, + FALSE, // expand + FALSE, // fill + 0); // padding + + vbox = gtk_vbox_new(FALSE, 0); + + gtk_box_pack_start(GTK_BOX(hbox), + vbox, + FALSE, // expand + FALSE, // fill + 0); // padding + + ctk_gvo_csc->cscOptions = hbox; + + /* create a drop-down menu for the possible initializing values */ + + frame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); + + gtk_container_add(GTK_CONTAINER(frame), vbox2); + + hbox = gtk_hbox_new(FALSE, // homogeneous + 10); // spacing + + gtk_box_pack_start(GTK_BOX(vbox2), + hbox, + FALSE, // expand + FALSE, // fill + 0); // padding + + label = gtk_label_new("Initialize Color Space Conversion with:"); + + gtk_box_pack_start(GTK_BOX(hbox), + label, + FALSE, // expand + FALSE, // fill + 5); // padding + + + ctk_gvo_csc->initializeDropDown = + ctk_drop_down_menu_new(CTK_DROP_DOWN_MENU_FLAG_MONOSPACE); + + ctk_drop_down_menu_append_item + (CTK_DROP_DOWN_MENU(ctk_gvo_csc->initializeDropDown), + CSC_STANDARD_ITU_601_STRING, + CSC_STANDARD_ITU_601); + + ctk_drop_down_menu_append_item + (CTK_DROP_DOWN_MENU(ctk_gvo_csc->initializeDropDown), + CSC_STANDARD_ITU_709_STRING, + CSC_STANDARD_ITU_709); + + ctk_drop_down_menu_append_item + (CTK_DROP_DOWN_MENU(ctk_gvo_csc->initializeDropDown), + CSC_STANDARD_ITU_177_STRING, + CSC_STANDARD_ITU_177); + + ctk_drop_down_menu_append_item + (CTK_DROP_DOWN_MENU(ctk_gvo_csc->initializeDropDown), + CSC_STANDARD_IDENTITY_STRING, + CSC_STANDARD_IDENTITY); + + ctk_drop_down_menu_finalize + (CTK_DROP_DOWN_MENU(ctk_gvo_csc->initializeDropDown)); + + gtk_box_pack_start(GTK_BOX(hbox), + ctk_gvo_csc->initializeDropDown, + FALSE, // expand + FALSE, // fill + 5); // padding + + + g_signal_connect(G_OBJECT(ctk_gvo_csc->initializeDropDown), "changed", + G_CALLBACK(initialize_csc_dropdown_changed), + (gpointer) ctk_gvo_csc); + + + gtk_box_pack_start(GTK_BOX(vbox), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + + /* create an hbox to store the CSC matrix, offset, and scale */ + + hbox = gtk_hbox_new(FALSE, // homogeneous + 10); // spacing + + gtk_box_pack_start(GTK_BOX(vbox), + hbox, + FALSE, // expand + FALSE, // fill + 0); // padding + + + /* create the CSC matrix */ + + frame = gtk_frame_new(NULL); + + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + gtk_box_pack_start(GTK_BOX(hbox), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + ctk_gvo_csc->matrixTable = + gtk_table_new(4, // rows + 4, // columns + FALSE); // homogeneous + + gtk_container_add(GTK_CONTAINER(frame), ctk_gvo_csc->matrixTable); + + /* add labels to the matrix table */ + + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Y" , 1, 0); + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Cr", 2, 0); + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Cb", 3, 0); + + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Red" , 0, 1); + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Green", 0, 2); + make_label(ctk_gvo_csc, ctk_gvo_csc->matrixTable, "Blue" , 0, 3); + + /* create the 3x3 matrix */ + + for (row = 0; row < 3; row++) { + for (column = 0; column < 3; column++) { + + ctk_gvo_csc->matrix[row][column] = initialCSCMatrix[row][column]; + + make_entry(ctk_gvo_csc, + ctk_gvo_csc->matrixTable, + &ctk_gvo_csc->matrixWidget[row][column], + ctk_gvo_csc->matrix[row][column], + row + 1, + column+1); + } + } + + + /* create the CSC offset */ + + frame = gtk_frame_new(NULL); + + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + gtk_box_pack_start(GTK_BOX(hbox), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + ctk_gvo_csc->offsetTable = + gtk_table_new(4, // rows + 1, // columns + FALSE); // homogeneous + + make_label(ctk_gvo_csc, ctk_gvo_csc->offsetTable, "Offset", 0, 0); + + gtk_container_add(GTK_CONTAINER(frame), ctk_gvo_csc->offsetTable); + + for (row = 0; row < 3; row++) { + + ctk_gvo_csc->offset[row] = initialCSCOffset[row]; + + make_entry(ctk_gvo_csc, + ctk_gvo_csc->offsetTable, + &ctk_gvo_csc->offsetWidget[row], + ctk_gvo_csc->offset[row], + row+1, + 0); + } + + + /* create the CSC scale */ + + frame = gtk_frame_new(NULL); + + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + gtk_box_pack_start(GTK_BOX(hbox), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + ctk_gvo_csc->scaleTable = + gtk_table_new(4, // rows + 1, // columns + FALSE); // homogeneous + + make_label(ctk_gvo_csc, ctk_gvo_csc->scaleTable, "Scale" , 0, 0); + + gtk_container_add(GTK_CONTAINER(frame), ctk_gvo_csc->scaleTable); + + for (row = 0; row < 3; row++) { + + ctk_gvo_csc->scale[row] = initialCSCScale[row]; + + make_entry(ctk_gvo_csc, + ctk_gvo_csc->scaleTable, + &ctk_gvo_csc->scaleWidget[row], + ctk_gvo_csc->scale[row], + row+1, + 0); + } + + + /* + * create checkbox for immediate apply; only expose if the X + * server can support apply CSC values immediately + */ + + if (caps & NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_IMMEDIATELY) { + + ctk_gvo_csc->applyImmediateButton = gtk_check_button_new_with_label + ("Apply Changes Immediately"); + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_gvo_csc->applyImmediateButton), FALSE); + + g_signal_connect(GTK_OBJECT(ctk_gvo_csc->applyImmediateButton), + "toggled", + G_CALLBACK(apply_immediate_button_toggled), + ctk_gvo_csc); + } else { + ctk_gvo_csc->applyImmediateButton = NULL; + } + + ctk_gvo_csc->applyImmediately = FALSE; + + + /* + * create an apply button; pack the button in an alignment inside + * an hbox, so that we can properly position the apply button on + * the far right + */ + + ctk_gvo_csc->applyButton = gtk_button_new_from_stock(GTK_STOCK_APPLY); + + g_signal_connect(GTK_OBJECT(ctk_gvo_csc->applyButton), + "clicked", + G_CALLBACK(apply_button_clicked), + ctk_gvo_csc); + + alignment = gtk_alignment_new(1.0, // xalign + 0.5, // yalign + 0.0, // xscale + 0.0); // yscale + + gtk_container_add(GTK_CONTAINER(alignment), ctk_gvo_csc->applyButton); + + hbox2 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox2), + alignment, + TRUE, // expand + TRUE, // fill + 0); // padding + + + /* create a frame to pack the apply stuff in */ + + frame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); + + hbox = gtk_hbox_new(FALSE, 10); + + /* pack applyImmediateButton, but only if we created it */ + + if (ctk_gvo_csc->applyImmediateButton) { + + gtk_box_pack_start(GTK_BOX(hbox), + ctk_gvo_csc->applyImmediateButton, + FALSE, // expand + FALSE, // fill + 0); // padding + } + + /* pack the Apply button */ + + gtk_box_pack_start(GTK_BOX(hbox), + hbox2, + TRUE, // expand + TRUE, // fill + 0); // padding + + /* pack the hbox inside a vbox so that we have proper y padding */ + + gtk_box_pack_start(GTK_BOX(vbox2), + hbox, + FALSE, // expand + FALSE, // fill + 0); // padding + + /* pack the vbox inside the frame */ + + gtk_container_add(GTK_CONTAINER(frame), vbox2); + + gtk_box_pack_start(GTK_BOX(vbox), + frame, + FALSE, // expand + FALSE, // fill + 0); // padding + + /* + * if custom CSC will not be applied to the X screen, make that + * clear to the user + */ + + if ((caps & NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_TO_X_SCREEN) == 0) { + + label = build_opengl_only_msg(); + + gtk_box_pack_start(GTK_BOX(vbox), + label, + FALSE, // expand + FALSE, // fill + 0); // padding + } + + /* + * initialize the override button to what we read in + * NV_CTRL_GVO_OVERRIDE_HW_CSC + */ + + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(ctk_gvo_csc->overrideButton), + override); + + override_state_toggled(ctk_gvo_csc, override); + + /* show the page */ + + gtk_widget_show_all(GTK_WIDGET(object)); + + return GTK_WIDGET(object); + +} /* ctk_gvo_csc_new() */ + + + + +/* + * override_button_toggled() - the override checkbox has been toggled; + * change the sensitivity of the widget; note that we do not send any + * NV-CONTROL protocol here if override has been enabled -- that is + * deferred until the user hits apply. + */ + +static void override_button_toggled(GtkToggleButton *overrideButton, + gpointer user_data) +{ + CtkGvoCsc *ctk_gvo_csc = (CtkGvoCsc *) user_data; + gboolean enabled = gtk_toggle_button_get_active(overrideButton); + override_state_toggled(ctk_gvo_csc, enabled); + + /* + * if override was enabled, don't send NV-CONTROL protocol, yet, + * unless applyImmediately was enabled; otherwise, wait until the + * user applies it. However, if override was disabled, apply that + * immediately. + */ + + if (enabled) { + + if (ctk_gvo_csc->applyImmediately) { + NvCtrlSetAttribute(ctk_gvo_csc->handle, + NV_CTRL_GVO_OVERRIDE_HW_CSC, + NV_CTRL_GVO_OVERRIDE_HW_CSC_TRUE); + } else { + + // make the "Apply" button hot + + gtk_widget_set_sensitive(ctk_gvo_csc->applyButton, TRUE); + } + + } else { + NvCtrlSetAttribute(ctk_gvo_csc->handle, + NV_CTRL_GVO_OVERRIDE_HW_CSC, + NV_CTRL_GVO_OVERRIDE_HW_CSC_FALSE); + } + +} /* override_button_toggled() */ + + + +/* + * override_state_toggled() - change the state of + */ + +static void override_state_toggled(CtkGvoCsc *ctk_gvo_csc, gboolean enabled) +{ + gtk_widget_set_sensitive(ctk_gvo_csc->cscOptions, enabled); + +} /* override_state_toggled() */ + + + +/* + * make_entry() - helper function to create an adjustment, create a + * numeric text entry with spin buttons, and pack the entry into the + * provided table. + */ + +static void make_entry(CtkGvoCsc *ctk_gvo_csc, + GtkWidget *table, + GtkWidget **widget, + float value, + int row, + int column) +{ + GtkAdjustment *adj; + + adj = (GtkAdjustment *) gtk_adjustment_new(value, // value + -1.0, // lower + 1.0, // upper + 0.001, // step incr + 0.1, // page incr + 0.1); // page size + + *widget = gtk_spin_button_new(adj, // adjustment + 0.001, // climb rate + 6); // number of digits + + g_signal_connect(G_OBJECT(*widget), + "value-changed", + G_CALLBACK(spin_button_value_changed), + ctk_gvo_csc); + + gtk_table_attach(GTK_TABLE(table), + *widget, + column, // left attach + column + 1, // right_attach + row, // top_attach + row + 1, // bottom_attach + 0, // xoptions + 0, // yoptions + 10, // xpadding + 10); // ypadding + +} /* make_entry() */ + + + +/* + * make_label() - helper function to create a lable and pack it in the + * given table. + */ + +static void make_label(CtkGvoCsc *ctk_gvo_csc, + GtkWidget *table, + const char *str, + int row, + int column) +{ + GtkWidget *label; + + label = gtk_label_new(str); + + gtk_table_attach(GTK_TABLE(table), + label, + column, + column + 1, // right_attach + row, // top_attach + row + 1, // bottom_attach + 0, // xoptions + 0, // yoptions + 4, // xpadding + 4); // ypadding + +} /* make_label() */ + + + +/* + * spin_button_value_changed() - one of the spin buttons changed; + */ + +static void spin_button_value_changed(GtkWidget *button, + gpointer user_data) +{ + CtkGvoCsc *ctk_gvo_csc = (CtkGvoCsc *) user_data; + gdouble value; + + int row, column; + + value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(button)); + + /* which spinbutton was it? */ + + for (row = 0; row < 3; row++) { + for (column = 0; column < 3; column++) { + + if (ctk_gvo_csc->matrixWidget[row][column] == button) { + ctk_gvo_csc->matrix[row][column] = value; + goto done; + } + } + + if (ctk_gvo_csc->offsetWidget[row] == button) { + ctk_gvo_csc->offset[row] = value; + goto done; + } + + if (ctk_gvo_csc->scaleWidget[row] == button) { + ctk_gvo_csc->scale[row] = value; + goto done; + } + } + + done: + + /* + * the data has changed, make sure the apply button is sensitive + */ + + set_apply_button_senstive(ctk_gvo_csc); + + /* if we are supposed to apply immediately, send the data now */ + + if (ctk_gvo_csc->applyImmediately) { + apply_csc_values(ctk_gvo_csc); + } + +} /* spin_button_value_changed() */ + + + +/* + * apply_immediate_button_toggled() - the "apply immediately" button + * has been toggled; change the sensitivity of the "Apply" button, and + * possibly send the current settings to the X server. + */ + +static +void apply_immediate_button_toggled(GtkToggleButton *applyImmediateButton, + gpointer user_data) +{ + CtkGvoCsc *ctk_gvo_csc = (CtkGvoCsc *) user_data; + gboolean enabled = gtk_toggle_button_get_active(applyImmediateButton); + + /* cache the current state */ + + ctk_gvo_csc->applyImmediately = enabled; + + /* + * the Apply button's sensitivity is the opposite of the Immediate + * apply checkbox -- if changes are applied immediately, then the + * Apply button is not needed + */ + + gtk_widget_set_sensitive(ctk_gvo_csc->applyButton, !enabled); + + /* + * if the apply immediately button is enabled, then flush our + * current values to the X server + */ + + if (enabled) { + apply_csc_values(ctk_gvo_csc); + } + +} /* apply_immediate_button_toggled() */ + + + +/* + * apply_button_clicked() - the apply button has been toggled, send + * the current settings to the X server, and make this button + * insensitive. + */ + +static void apply_button_clicked(GtkButton *button, gpointer user_data) +{ + CtkGvoCsc *ctk_gvo_csc = (CtkGvoCsc *) user_data; + + apply_csc_values(ctk_gvo_csc); + + gtk_widget_set_sensitive(ctk_gvo_csc->applyButton, FALSE); + +} /* apply_button_clicked() */ + + + +/* + * initialize_csc_dropdown_changed() - the "initialize" dropdown menu + * changed; update the values in the matrix, offset, and scale + */ + +static void initialize_csc_dropdown_changed(CtkDropDownMenu *menu, + gpointer user_data) +{ + CtkGvoCsc *ctk_gvo_csc = (CtkGvoCsc *) user_data; + const gfloat (*std)[5]; + gint column, row, value; + + // red green blue offset scale + static const float itu601[3][5] = { + { 0.2991, 0.5870, 0.1150, 0.0625, 0.85547 }, // Y + { 0.5000, -0.4185, -0.0810, 0.5000, 0.87500 }, // Cr + { -0.1685, -0.3310, 0.5000, 0.5000, 0.87500 }, // Cb + }; + + static const float itu709[3][5] = { + { 0.2130, 0.7156, 0.0725, 0.0625, 0.85547 }, // Y + { 0.5000, -0.4542, -0.0455, 0.5000, 0.87500 }, // Cr + { -0.1146, -0.3850, 0.5000, 0.5000, 0.87500 }, // Cb + }; + + static const float itu177[3][5] = { + { 0.412391, 0.357584, 0.180481, 0.0, 0.85547 }, // Y + { 0.019331, 0.119195, 0.950532, 0.0, 0.87500 }, // Cr + { 0.212639, 0.715169, 0.072192, 0.0, 0.87500 }, // Cb + }; + + static const float identity[3][5] = { + { 0.0000, 1.0000, 0.0000, 0.0000, 1.0 }, // Y (Green) + { 1.0000, 0.0000, 0.0000, 0.0000, 1.0 }, // Cr (Red) + { 0.0000, 0.0000, 1.0000, 0.0000, 1.0 }, // Cb (Blue) + }; + + + value = ctk_drop_down_menu_get_current_value(menu); + + switch (value) { + case CSC_STANDARD_ITU_601: std = itu601; break; + case CSC_STANDARD_ITU_709: std = itu709; break; + case CSC_STANDARD_ITU_177: std = itu177; break; + case CSC_STANDARD_IDENTITY: std = identity; break; + default: return; + } + + for (row = 0; row < 3; row++) { + for (column = 0; column < 3; column++) { + ctk_gvo_csc->matrix[row][column] = std[row][column]; + gtk_spin_button_set_value + (GTK_SPIN_BUTTON(ctk_gvo_csc->matrixWidget[row][column]), + ctk_gvo_csc->matrix[row][column]); + } + + ctk_gvo_csc->offset[row] = std[row][3]; + gtk_spin_button_set_value + (GTK_SPIN_BUTTON(ctk_gvo_csc->offsetWidget[row]), + ctk_gvo_csc->offset[row]); + + ctk_gvo_csc->scale[row] = std[row][4]; + gtk_spin_button_set_value + (GTK_SPIN_BUTTON(ctk_gvo_csc->scaleWidget[row]), + ctk_gvo_csc->scale[row]); + } + + /* + * the data has changed, make sure the apply button is sensitive + */ + + set_apply_button_senstive(ctk_gvo_csc); + + /* if we are supposed to apply immediately, send the data now */ + + if (ctk_gvo_csc->applyImmediately) { + apply_csc_values(ctk_gvo_csc); + } + +} /* initialize_csc_dropdown_changed() */ + + + +/* + * set_apply_button_senstive() - make the "Apply" button sensitive + */ + +static void set_apply_button_senstive(CtkGvoCsc *ctk_gvo_csc) +{ + /* if data is applied immediately, then we don't */ + + if (ctk_gvo_csc->applyImmediately) return; + + gtk_widget_set_sensitive(ctk_gvo_csc->applyButton, TRUE); + +} /* set_apply_button_senstive() */ + + + +/* + * apply_csc_values() - apply the current CSC values to the X server + * and make sure CSC override is enabled + */ + +static void apply_csc_values(CtkGvoCsc *ctk_gvo_csc) +{ + NvCtrlSetGvoColorConversion(ctk_gvo_csc->handle, + ctk_gvo_csc->matrix, + ctk_gvo_csc->offset, + ctk_gvo_csc->scale); + + NvCtrlSetAttribute(ctk_gvo_csc->handle, + NV_CTRL_GVO_OVERRIDE_HW_CSC, + NV_CTRL_GVO_OVERRIDE_HW_CSC_TRUE); + +} /* apply_csc_values() */ + + +/* + * build_opengl_only_msg() - build a message to inform the user that + * custom CSC will only be applied to OpenGL GVO output; this returns + * a frame containing the message. + */ + +static GtkWidget *build_opengl_only_msg(void) +{ + GdkPixbuf *pixbuf; + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *frame; + GtkWidget *image = NULL; + + /* create the label */ + + label = gtk_label_new("Note that the overridden Color Space Conversion " + "will only apply to OpenGL applications " + "using the GLX_NV_video_out extension."); + + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + + /* create the information icon */ + + pixbuf = gtk_widget_render_icon(label, + GTK_STOCK_DIALOG_INFO, + GTK_ICON_SIZE_DIALOG, + "CSC information message"); + + /* create a pixmap from the icon */ + + if (pixbuf) { + image = gtk_image_new_from_pixbuf(pixbuf); + } else { + image = NULL; + } + + /* create an hbox and pack the icon and label in it */ + + hbox = gtk_hbox_new(FALSE, 5); + + if (image) { + gtk_box_pack_start(GTK_BOX(hbox), + image, + FALSE, // expand + FALSE, // fill + 5); // padding + } + + gtk_box_pack_start(GTK_BOX(hbox), + label, + FALSE, // expand + FALSE, // fill + 5); // padding + + /* pack the hbox in a vbox to get vertical padding */ + + vbox = gtk_vbox_new(FALSE, 5); + + gtk_box_pack_start(GTK_BOX(vbox), + hbox, + FALSE, // expand + FALSE, // fill + 5); // padding + + /* pack the whole thing in a frame */ + + frame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(frame), FRAME_BORDER); + + gtk_container_add(GTK_CONTAINER(frame), vbox); + + return frame; + +} /* build_opengl_only_msg() */ diff --git a/src/gtk+-2.x/ctkgvo-csc.h b/src/gtk+-2.x/ctkgvo-csc.h new file mode 100644 index 0000000..7561039 --- /dev/null +++ b/src/gtk+-2.x/ctkgvo-csc.h @@ -0,0 +1,100 @@ +/* + * 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_GVO_CSC_H__ +#define __CTK_GVO_CSC_H__ + +#include "ctkevent.h" +#include "ctkconfig.h" + +G_BEGIN_DECLS + +#define CTK_TYPE_GVO_CSC (ctk_gvo_csc_get_type()) + +#define CTK_GVO_CSC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_GVO_CSC, \ + CtkGvoCsc)) + +#define CTK_GVO_CSC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_GVO_CSC, \ + CtkGvoCscClass)) + +#define CTK_IS_GVO_CSC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_GVO_CSC)) + +#define CTK_IS_GVO_CSC_CLASS(class) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_GVO_CSC)) + +#define CTK_GVO_CSC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_GVO_CSC, \ + CtkGvoCscClass)) + + +typedef struct _CtkGvoCsc CtkGvoCsc; +typedef struct _CtkGvoCscClass CtkGvoCscClass; + +struct _CtkGvoCsc +{ + GtkVBox parent; + + NvCtrlAttributeHandle *handle; + CtkConfig *ctk_config; + + float matrix[3][3]; // [row][column] + float offset[3]; + float scale[3]; + + gboolean applyImmediately; + + GtkWidget *matrixWidget[3][3]; + GtkWidget *offsetWidget[3]; + GtkWidget *scaleWidget[3]; + + GtkWidget *matrixTable; + GtkWidget *offsetTable; + GtkWidget *scaleTable; + + GtkWidget *overrideButton; + GtkWidget *initializeDropDown; + GtkWidget *applyImmediateButton; + GtkWidget *applyButton; + + GtkWidget *cscOptions; +}; + +struct _CtkGvoCscClass +{ + GtkVBoxClass parent_class; +}; + +GType ctk_gvo_csc_get_type (void) G_GNUC_CONST; +GtkWidget* ctk_gvo_csc_new (NvCtrlAttributeHandle *, + CtkConfig *, CtkEvent *); + +//GtkTextBuffer *ctk_gvo_csc_create_help(GtkTextTagTable *, +// CtkGvoCsc *); + +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 15f6279..697307e 100644 --- a/src/gtk+-2.x/ctkgvo.c +++ b/src/gtk+-2.x/ctkgvo.c @@ -198,34 +198,44 @@ typedef struct { } FormatDetails; static const FormatName videoFormatNames[] = { - { NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC, "480i 59.94 Hz (SMPTE259) NTSC"}, - { NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL, "576i 50.00 Hz (SMPTE259) PAL"}, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_23_98_SMPTE296, "720p 23.98 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_24_00_SMPTE296, "720p 24.00 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_25_00_SMPTE296, "720p 25.00 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_29_97_SMPTE296, "720p 29.97 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_30_00_SMPTE296, "720p 30.00 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_50_00_SMPTE296, "720p 50.00 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_59_94_SMPTE296, "720p 59.94 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296, "720p 60.00 Hz (SMPTE296)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260, "1035i 59.94 Hz (SMPTE260)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260, "1035i 60.00 Hz (SMPTE260)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295, "1080i 50.00 Hz (SMPTE295)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274, "1080i 50.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274, "1080i 59.94 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_60_00_SMPTE274, "1080i 60.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_976_SMPTE274, "1080p 23.976 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE274, "1080p 24.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274, "1080p 25.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274, "1080p 29.97 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274, "1080p 30.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274, "1080i 47.96 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274, "1080i 48.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274, "1080PsF 25.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274, "1080PsF 29.97 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274, "1080PsF 30.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274, "1080PsF 24.00 Hz (SMPTE274)" }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274, "1080PsF 23.98 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC, "720 x 480i 59.94 Hz (SMPTE259) NTSC"}, + { NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL, "720 x 576i 50.00 Hz (SMPTE259) PAL"}, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_23_98_SMPTE296, "1280 x 720p 23.98 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_24_00_SMPTE296, "1280 x 720p 24.00 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_25_00_SMPTE296, "1280 x 720p 25.00 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_29_97_SMPTE296, "1280 x 720p 29.97 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_30_00_SMPTE296, "1280 x 720p 30.00 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_50_00_SMPTE296, "1280 x 720p 50.00 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_59_94_SMPTE296, "1280 x 720p 59.94 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296, "1280 x 720p 60.00 Hz (SMPTE296)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260, "1920 x 1035i 59.94 Hz (SMPTE260)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260, "1920 x 1035i 60.00 Hz (SMPTE260)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274, "1920 x 1080i 47.96 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274, "1920 x 1080i 48.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295, "1920 x 1080i 50.00 Hz (SMPTE295)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274, "1920 x 1080i 50.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274, "1920 x 1080i 59.94 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_60_00_SMPTE274, "1920 x 1080i 60.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_976_SMPTE274, "1920 x 1080p 23.976 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE274, "1920 x 1080p 24.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274, "1920 x 1080p 25.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274, "1920 x 1080p 29.97 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274, "1920 x 1080p 30.00 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274, "1920 x 1080PsF 23.98 Hz (SMPTE274)" }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274, "1920 x 1080PsF 24.00 Hz (SMPTE274)" }, + { 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)" }, { -1, NULL }, }; @@ -243,6 +253,8 @@ static FormatDetails videoFormatDetails[] = { { NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274, 0, 0, 0 }, @@ -252,13 +264,21 @@ static FormatDetails videoFormatDetails[] = { { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274, 0, 0, 0 }, { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274, 0, 0, 0 }, + { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274, 0, 0, 0 }, { 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_1080PSF_24_00_SMPTE274, 0, 0, 0 }, - { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_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 }, { -1, -1, -1, -1 }, }; @@ -316,7 +336,7 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle, CtkGvo *ctk_gvo; GtkWidget *hbox, *alignment, *button, *label; ReturnStatus ret; - gchar scratch[64], *firmware; + gchar scratch[64], *firmware, *string; gint val, i, width, height, n; GtkWidget *frame, *table, *menu; @@ -378,15 +398,32 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle, gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_container_add(GTK_CONTAINER(frame), table); - /* NV_CTRL_GVO_FIRMWARE_VERSION */ - - ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_FIRMWARE_VERSION, &val); + /* GVO_FIRMWARE_VERSION */ - if (ret == NvCtrlSuccess) { - snprintf(scratch, 64, "1.%02d", val); - firmware = strdup(scratch); + string = NULL; + + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_GVO_FIRMWARE_VERSION, + &string); + + if ((ret == NvCtrlSuccess) && (string)) { + firmware = strdup(string); } else { - firmware = strdup("???"); + + /* + * NV_CTRL_STRING_GVO_FIRMWARE_VERSION was added later, so + * older X servers may not know about it; fallback to + * NV_CTRL_GVO_FIRMWARE_VERSION + */ + + ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_FIRMWARE_VERSION, &val); + + if (ret == NvCtrlSuccess) { + snprintf(scratch, 64, "1.%02d", val); + firmware = strdup(scratch); + } else { + firmware = strdup("???"); + } } add_table_row(table, 0, 0, "Firmware Version:", firmware); @@ -1246,7 +1283,11 @@ static void output_video_format_changed(CtkDropDownMenu *menu, value = ctk_drop_down_menu_get_current_value(menu); - if (!(ctk_gvo->valid_putput_video_format_mask & (1 << value))) { + if (((value < 32) && + !(ctk_gvo->valid_output_video_format_mask[0] & (1 << value))) || + ((value >= 32) && + !(ctk_gvo->valid_output_video_format_mask[1] & (1 << (value - 32))))){ + ctk_config_statusbar_message(ctk_gvo->ctk_config, "Invalid " "Output Video Format: %s; ignoring.", get_video_format_name(value)); @@ -1419,7 +1460,7 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) { ReturnStatus ret; NVCTRLAttributeValidValuesRec valid; - gint bitmask, i, refresh_rate; + gint bitmask, bitmask2, i, refresh_rate; gboolean sensitive, current_not_available = FALSE; /* retrieve the currently available values */ @@ -1436,6 +1477,20 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) bitmask = valid.u.bits.ints; } + /* retrieve additional available values */ + + ret = NvCtrlGetValidAttributeValues(ctk_gvo->handle, + NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2, + &valid); + + /* if we failed to get the available values; assume none are valid */ + + if ((ret != NvCtrlSuccess) || (valid.type != ATTRIBUTE_TYPE_INT_BITS)) { + bitmask2 = 0; + } else { + bitmask2 = valid.u.bits.ints; + } + /* * if the SyncMode is genlock or framelock, trim the bitmask * accordingly: if GENLOCK, then the only bit allowed is the bit @@ -1446,7 +1501,14 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) if ((ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_GENLOCK) && (ctk_gvo->input_video_format != NV_CTRL_GVO_VIDEO_FORMAT_NONE)) { - bitmask &= (1 << ctk_gvo->input_video_format); + + if (ctk_gvo->input_video_format < 32) { + bitmask &= (1 << ctk_gvo->input_video_format); + bitmask2 = 0; + } else { + bitmask = 0; + bitmask2 &= (1 << (ctk_gvo->input_video_format - 32)); + } } if ((ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_FRAMELOCK) && @@ -1463,7 +1525,12 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) for (i = 0; videoFormatDetails[i].format != -1; i++) { if (videoFormatDetails[i].rate != refresh_rate) { - bitmask &= ~(1 << videoFormatDetails[i].format); + + if (videoFormatDetails[i].format < 32) { + bitmask &= ~(1 << videoFormatDetails[i].format); + } else { + bitmask2 &= ~(1 << (videoFormatDetails[i].format - 32)); + } } } } @@ -1474,7 +1541,10 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) */ for (i = 0; videoFormatNames[i].name; i++) { - if ((1 << videoFormatNames[i].format) & bitmask) { + if (((videoFormatNames[i].format < 32) && + ((1 << videoFormatNames[i].format) & bitmask)) || + ((videoFormatNames[i].format >= 32) && + (((1 << (videoFormatNames[i].format - 32)) & bitmask2)))) { sensitive = TRUE; } else { sensitive = FALSE; @@ -1499,7 +1569,10 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) if (current_not_available && bitmask) { for (i = 0; videoFormatNames[i].name; i++) { - if ((1 << videoFormatNames[i].format) & bitmask) { + if (((videoFormatNames[i].format < 32) && + ((1 << videoFormatNames[i].format) & bitmask)) || + ((videoFormatNames[i].format >= 32) && + ((1 << (videoFormatNames[i].format - 32)) & bitmask2))) { NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT, @@ -1520,7 +1593,8 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo) * cache the bitmask */ - ctk_gvo->valid_putput_video_format_mask = bitmask; + ctk_gvo->valid_output_video_format_mask[0] = bitmask; + ctk_gvo->valid_output_video_format_mask[1] = bitmask2; } /* update_output_video_format_menu() */ diff --git a/src/gtk+-2.x/ctkgvo.h b/src/gtk+-2.x/ctkgvo.h index e68fb0b..b495cfd 100644 --- a/src/gtk+-2.x/ctkgvo.h +++ b/src/gtk+-2.x/ctkgvo.h @@ -111,7 +111,7 @@ struct _CtkGvo gint output_video_format; gint output_data_format; - gint valid_putput_video_format_mask; + gint valid_output_video_format_mask[2]; gint input_video_format_detect_timer; GdkCursor *wait_cursor; diff --git a/src/gtk+-2.x/ctkhelp.c b/src/gtk+-2.x/ctkhelp.c index 042f67b..5df77ca 100644 --- a/src/gtk+-2.x/ctkhelp.c +++ b/src/gtk+-2.x/ctkhelp.c @@ -32,7 +32,6 @@ #include <stdlib.h> -static GtkTextTagTable *create_tag_table(void); static GtkTextBuffer *create_default_help(CtkHelp *ctk_help); static void close_button_clicked(GtkButton *button, gpointer user_data); static gboolean window_destroy(GtkWidget *widget, GdkEvent *event, @@ -66,7 +65,7 @@ GType ctk_help_get_type( return ctk_help_type; } -GtkWidget* ctk_help_new(GtkWidget *toggle_button) +GtkWidget* ctk_help_new(GtkWidget *toggle_button, GtkTextTagTable *tag_table) { GObject *object; CtkHelp *ctk_help; @@ -145,9 +144,9 @@ GtkWidget* ctk_help_new(GtkWidget *toggle_button) g_object_set(G_OBJECT(ctk_help->text_viewer), "pixels-inside-wrap", 10, NULL); - /* create the tag table */ + /* save the tag table */ - ctk_help->tag_table = create_tag_table(); + ctk_help->tag_table = tag_table; /* create the default help text */ @@ -247,7 +246,7 @@ static GtkTextBuffer *create_default_help(CtkHelp *ctk_help) } -static GtkTextTagTable *create_tag_table(void) +GtkTextTagTable *ctk_help_create_tag_table(void) { GtkTextTagTable *table; GtkTextTag *tag; diff --git a/src/gtk+-2.x/ctkhelp.h b/src/gtk+-2.x/ctkhelp.h index 53eb719..090adc8 100644 --- a/src/gtk+-2.x/ctkhelp.h +++ b/src/gtk+-2.x/ctkhelp.h @@ -67,9 +67,10 @@ struct _CtkHelpClass GtkWindowClass parent_class; }; -GType ctk_help_get_type (void) G_GNUC_CONST; -GtkWidget *ctk_help_new (GtkWidget *); -void ctk_help_set_page (CtkHelp *, GtkTextBuffer *); +GType ctk_help_get_type (void) G_GNUC_CONST; +GtkWidget *ctk_help_new (GtkWidget *, GtkTextTagTable *); +void ctk_help_set_page (CtkHelp *, GtkTextBuffer *); +GtkTextTagTable *ctk_help_create_tag_table (void); void ctk_help_title (GtkTextBuffer *, GtkTextIter *, const gchar *, ...); void ctk_help_para (GtkTextBuffer *, GtkTextIter *, const gchar *, ...); diff --git a/src/gtk+-2.x/ctkimage.c b/src/gtk+-2.x/ctkimage.c new file mode 100644 index 0000000..319c55f --- /dev/null +++ b/src/gtk+-2.x/ctkimage.c @@ -0,0 +1,124 @@ +/* + * 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 "image.h" +#include "ctkimage.h" + + +/* + * CTK image widget creation + * + */ +GtkWidget* ctk_image_new(const nv_image_t *img) +{ + guint8 *image_buffer = decompress_image_data(img); + gboolean has_alpha = FALSE; + + if (!image_buffer) return NULL; + + if (img->bytes_per_pixel == 4) { /* RGBA */ + has_alpha = TRUE; + } + + return gtk_image_new_from_pixbuf + (gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, + has_alpha, 8, img->width, img->height, + img->width * img->bytes_per_pixel, + free_decompressed_image, NULL)); +} + +GtkWidget* ctk_image_new_from_xpm(const char **img) +{ + if (!img) return NULL; + + return gtk_image_new_from_pixbuf(gdk_pixbuf_new_from_xpm_data(img)); +} + + +/* + * CTK image duplication + * + */ +GtkWidget *ctk_image_dupe(GtkImage *image) +{ + GtkImageType image_type; + GtkWidget *new_image = NULL; + + + if (!image) return NULL; + + image_type = gtk_image_get_storage_type(image); + + switch (image_type) { + + case GTK_IMAGE_PIXBUF: + { + GdkPixbuf *pixbuf = gtk_image_get_pixbuf(image); + new_image = gtk_image_new_from_pixbuf(pixbuf); + } + break; + + default: + /* XXX Support more formats later */ + break; + } + + return new_image; +} + + + +/* + * CTK banner image widget creation + * + */ +GtkWidget* ctk_banner_image_new(const nv_image_t *img) +{ + GtkWidget *image; + GtkWidget *hbox; + GtkWidget *frame; + + + image = ctk_image_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_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(frame), image); + + + return hbox; +} diff --git a/src/gtk+-2.x/ctkimage.h b/src/gtk+-2.x/ctkimage.h new file mode 100644 index 0000000..bbe43f1 --- /dev/null +++ b/src/gtk+-2.x/ctkimage.h @@ -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 + * + */ + +#ifndef __CTK_IMAGE_H__ +#define __CTK_IMAGE_H__ + +#include "image.h" +#include "ctkconfig.h" + +G_BEGIN_DECLS + +GtkWidget* ctk_image_new (const nv_image_t *); +GtkWidget* ctk_image_new_from_xpm (const char **); +GtkWidget* ctk_image_dupe (GtkImage *image); +GtkWidget* ctk_banner_image_new (const nv_image_t *); + +G_END_DECLS + +#endif /* __CTK_IMAGE_H__ */ diff --git a/src/gtk+-2.x/ctkopengl.c b/src/gtk+-2.x/ctkopengl.c index 30c2884..82d867a 100644 --- a/src/gtk+-2.x/ctkopengl.c +++ b/src/gtk+-2.x/ctkopengl.c @@ -26,6 +26,7 @@ #include <NvCtrlAttributes.h> #include "opengl_banner.h" +#include "ctkimage.h" #include "ctkopengl.h" @@ -143,7 +144,7 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, GObject *object; CtkOpenGL *ctk_opengl; GtkWidget *label; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *hseparator; GtkWidget *hbox; @@ -155,9 +156,6 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, NVCTRLAttributeValidValuesRec valid; - guint8 *image_buffer = NULL; - const nv_image_t *img; - object = g_object_new(CTK_TYPE_OPENGL, NULL); ctk_opengl = CTK_OPENGL(object); @@ -167,26 +165,8 @@ GtkWidget* ctk_opengl_new(NvCtrlAttributeHandle *handle, gtk_box_set_spacing(GTK_BOX(object), 10); - - 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); - - img = &opengl_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(&opengl_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); /* diff --git a/src/gtk+-2.x/ctkrandr.c b/src/gtk+-2.x/ctkrandr.c index 9077f0a..3b9c631 100644 --- a/src/gtk+-2.x/ctkrandr.c +++ b/src/gtk+-2.x/ctkrandr.c @@ -28,6 +28,7 @@ #include <X11/Xlib.h> #include <X11/extensions/Xrandr.h> +#include "ctkimage.h" #include "rotation_banner.h" /* Images */ #include "rotation_orientation_horiz.h" #include "rotation_orientation_horiz_flipped.h" @@ -483,26 +484,8 @@ GtkWidget* ctk_randr_new(NvCtrlAttributeHandle *handle, { /* Banner image */ - GtkWidget *hbox = gtk_hbox_new(FALSE, 0); - GtkWidget *frame = gtk_frame_new(NULL); - - const nv_image_t *image_data = &rotation_banner_image; - guint8 *image_buffer = decompress_image_data(image_data); - GdkPixbuf *image_pixbuf = - gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB, - FALSE, 8, image_data->width, - image_data->height, - image_data->width * image_data->bytes_per_pixel, - free_decompressed_image, NULL); - GtkWidget *image = gtk_image_new_from_pixbuf(image_pixbuf); - - - gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0); - - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(frame), image); + GtkWidget *banner = ctk_banner_image_new(&rotation_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); } diff --git a/src/gtk+-2.x/ctkthermal.c b/src/gtk+-2.x/ctkthermal.c index b3b4e4f..6f9b327 100644 --- a/src/gtk+-2.x/ctkthermal.c +++ b/src/gtk+-2.x/ctkthermal.c @@ -29,6 +29,7 @@ #include "ctkthermal.h" #include "ctkgauge.h" #include "thermal_banner.h" +#include "ctkimage.h" #define FRAME_PADDING 10 #define DEFAULT_UPDATE_THERMAL_INFO_TIME_INTERVAL 1000 @@ -126,14 +127,12 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle, CtkThermal *ctk_thermal; GtkWidget *gauge; GtkWidget *hbox, *hbox2, *vbox, *table; - GtkWidget *frame, *image, *label; + GtkWidget *frame, *banner, *label; GtkWidget *eventbox, *entry; ReturnStatus ret; gint trigger, ambient; gint core, upper; - guint8 *image_buffer = NULL; - const nv_image_t *img; gchar *s; @@ -175,25 +174,8 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle, /* banner */ - 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); - - img = &thermal_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(&thermal_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); /* Thermal Information */ diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c index 61efb10..7ce9bfc 100644 --- a/src/gtk+-2.x/ctkwindow.c +++ b/src/gtk+-2.x/ctkwindow.c @@ -37,6 +37,7 @@ #include "ctkframelock.h" #include "ctkgvo.h" +#include "ctkgvo-csc.h" #include "ctkconfig.h" #include "ctkdevice.h" @@ -205,8 +206,17 @@ static void help_button_toggled(GtkToggleButton *button, gpointer user_data) enabled = gtk_toggle_button_get_active(button); - if (enabled) gtk_widget_show_all(ctk_window->ctk_help); - else gtk_widget_hide_all(ctk_window->ctk_help); + if (enabled) { + if (ctk_window->ctk_help == NULL) { + ctk_window->ctk_help = ctk_help_new(GTK_WIDGET(button), + ctk_window->help_tag_table); + ctk_help_set_page(CTK_HELP(ctk_window->ctk_help), + ctk_window->help_text_buffer); + } + gtk_widget_show_all(ctk_window->ctk_help); + } else { + gtk_widget_hide_all(ctk_window->ctk_help); + } } /* help_button_toggled() */ @@ -275,7 +285,9 @@ static void tree_selection_changed(GtkTreeSelection *selection, /* update the help page */ - ctk_help_set_page(CTK_HELP(ctk_window->ctk_help), help); + if (ctk_window->ctk_help != NULL) + ctk_help_set_page(CTK_HELP(ctk_window->ctk_help), help); + ctk_window->help_text_buffer = help; /* Keep track of the selected widget */ @@ -416,9 +428,10 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, g_signal_connect(G_OBJECT(toggle_button), "toggled", G_CALLBACK(help_button_toggled), (gpointer) ctk_window); - - ctk_window->ctk_help = ctk_help_new(toggle_button); - tag_table = CTK_HELP(ctk_window->ctk_help)->tag_table; + + ctk_window->ctk_help = NULL; + tag_table = ctk_help_create_tag_table(); + ctk_window->help_tag_table = tag_table; ctk_config_set_tooltip(ctk_config, toggle_button, "The Help button " "toggles the display of a help window which " @@ -628,10 +641,20 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, child = ctk_gvo_new(handles[i], GTK_WIDGET(ctk_window), ctk_config, ctk_event); if (child) { + GtkTreeIter child_iter; help = ctk_gvo_create_help(tag_table); - add_page(child, help, ctk_window, &iter, NULL, + add_page(child, help, ctk_window, &iter, &child_iter, "Graphics to Video Out", NULL, ctk_gvo_select, ctk_gvo_unselect); + + /* add GVO sub-pages */ + + child = ctk_gvo_csc_new(handles[i], + ctk_config, ctk_event); + if (child) { + add_page(child, NULL, ctk_window, &child_iter, NULL, + "Color Space Conversion", NULL, NULL, NULL); + } } /* clocks (GPU overclocking) */ @@ -655,8 +678,8 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, } /* - * add the framelock page, if any of the X screens support - * framelock + * add the frame lock page, if any of the X screens support + * frame lock */ for (i = 0; i < num_handles; i++) { @@ -667,7 +690,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles, if (!widget) continue; add_page(widget, ctk_framelock_create_help(tag_table), - ctk_window, NULL, NULL, "FrameLock", + ctk_window, NULL, NULL, "Frame Lock", ctk_framelock_config_file_attributes, ctk_framelock_select, ctk_framelock_unselect); diff --git a/src/gtk+-2.x/ctkwindow.h b/src/gtk+-2.x/ctkwindow.h index 3256b8e..c88c23d 100644 --- a/src/gtk+-2.x/ctkwindow.h +++ b/src/gtk+-2.x/ctkwindow.h @@ -78,6 +78,9 @@ struct _CtkWindow GtkTreeIter iter; GtkWidget *widget; + + GtkTextTagTable *help_tag_table; + GtkTextBuffer *help_text_buffer; }; struct _CtkWindowClass diff --git a/src/gtk+-2.x/ctkxvideo.c b/src/gtk+-2.x/ctkxvideo.c index 483b4d3..d423625 100644 --- a/src/gtk+-2.x/ctkxvideo.c +++ b/src/gtk+-2.x/ctkxvideo.c @@ -26,6 +26,7 @@ #include "NvCtrlAttributes.h" #include "xvideo_banner.h" +#include "ctkimage.h" #include "ctkxvideo.h" #include "ctkscale.h" @@ -315,7 +316,7 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, { GObject *object; CtkXVideo *ctk_xvideo; - GtkWidget *image; + GtkWidget *banner; GtkWidget *frame; GtkWidget *alignment; GtkWidget *hbox; @@ -323,8 +324,6 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, GtkWidget *vbox; GtkWidget *button; - guint8 *image_buffer = NULL; - const nv_image_t *img; int xv_overlay_present, xv_texture_present, xv_blitter_present; int sync_mask; @@ -383,26 +382,9 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, /* Video film banner */ - 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); - - img = &xvideo_banner_image; + banner = ctk_banner_image_new(&xvideo_banner_image); + gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); - 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); - /* XVideo Overlay sliders */ diff --git a/src/image_data/Makefile.inc b/src/image_data/Makefile.inc index 48d28df..6606291 100644 --- a/src/image_data/Makefile.inc +++ b/src/image_data/Makefile.inc @@ -79,4 +79,11 @@ EXTRA_DIST += \ rotation_orientation_horiz.h \ rotation_orientation_vert_flipped.h \ rotation_orientation_vert.h \ - clocks_banner.h + clocks_banner.h \ + bnc_cable.h \ + led_green.h \ + led_red.h \ + led_grey.h \ + rj45_input.h \ + rj45_output.h \ + rj45_unused.h diff --git a/src/image_data/bnc_cable.h b/src/image_data/bnc_cable.h new file mode 100644 index 0000000..756946a --- /dev/null +++ b/src/image_data/bnc_cable.h @@ -0,0 +1,480 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (bnc_cable.c) */
+
+#include "image.h"
+
+static const nv_image_t bnc_cable = {
+ 64, 64, 4,
+ "\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"
+ "\0\14\11\11\11\1\\\\\\\0fff\0[[[\0TWT\0WUW\0XXX\0WXW\0UUU\0RRR\0MLM\0FFF"
+ "\0\206\377\377\377\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\215"
+ "\214\215\0\213\0\0\0\0\6\1\1\1\1KKK\14iih\5[\\[\0TTU\0SSS\0\202WWW\0\5US"
+ "U\0RPR\0LMM\0FGF\0???\0\206\377\377\377\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\214\213\214\0\213\0\0\0\0\5=>=!jjj\33\\\\\\\20WUU\10QQS"
+ "\1\202UUU\0\6SSU\0RPR\0MMM\0GIG\0@@@\0""888\0\206\377\377\377\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\10\311\311\311\0\225\224\225\0\256"
+ "\253\256\0\315\311\315\0\303\301\303\0\211\210\211\0\203\204\203\0\1\1\1"
+ "\0\210\0\0\0\0\16&$&/kik7___*WWW\37PQQ\24SSR\14SUS\4RSS\0RPP\0MMM\0GII\0"
+ "AC@\0""888\0""777\0\206\377\377\377\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\7\311\311\311\0\225\224\225\0\256\253\256\0\315\311\315\0\303"
+ "\301\303\0\207\206\207\0\200\202\200\0\210\0\0\0\0\17\23\23\23*a`aX`aaJX"
+ "WW<QRQ0PRP#SSS\31RRS\17PPP\6NMM\0III\0CCC\0:::\0""757\0""899\0\206\377\377"
+ "\377\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\7\311\311\311\0"
+ "\225\224\225\0\256\253\256\0\315\311\315\0\302\300\302\0\207\206\207\0\177"
+ "\201\177\0\207\0\0\0\0\20\16\15\16\40XXX|dddmXYX_RPRPPNPBRPR5RRR)PPP\35L"
+ "MM\23III\12CCC\3===\0""757\0""888\0===\0\206\377\377\377\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\7\311\311\311\0\225\224\225\0\256\253"
+ "\256\0\315\311\315\0\302\300\302\0\207\206\207\0\177\201\177\0\206\0\0\0"
+ "\0\21\1\1\1\21KKK\236fff\221YYY\203PPRtNMNePPPVPPPINPN:LLL.III\"CEC\30<="
+ "=\16""775\6""777\0;;;\0BBB\0\206\377\377\377\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\7\311\311\311\0\225\224\225\0\256\253\256\0\315\311"
+ "\315\0\302\300\302\0\207\206\207\0\177\200\177\0\205\0\0\0\0\22\1\1\1\1>"
+ ">>\265fif\265YYY\247RRR\230MMM\211MMNzNNNkNNN]LLLNIII@CCC3==?'777\34""57"
+ "5\22""999\11@>>\2;<<\0\206\377\377\377\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\7\311\311\311\0\225\224\225\0\256\253\256\0\315\311\315"
+ "\0\302\300\302\0\206\205\206\0~\177~\0\205\0\0\0\0\22""000\261gfg\324ZZZ"
+ "\310RRR\273MMM\254MLL\237MMN\217MMM\201JLLqGIIcEEET???G8789555,899\40>>>"
+ "\26CBB\15\31\31\31\3\206\377\377\377\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\10\311\311\311\0\225\224\225\0\256\253\256\0\315\311\315\0"
+ "\302\300\302\0\206\205\206\0|}|\0ccc\0\203\0\0\0\0\23%%%\244ddf\356\\\\Z"
+ "\344RRR\332LLL\316LJL\301MLM\263LLL\245JJJ\226GGG\207CCCx?=?i888[333L888"
+ "?;;;1CEC&)))\27\0\0\0\0\206\377\377\377\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\10\311\311\311\0\225\224\225\0\256\253\256\0\315\311\315"
+ "\0\302\300\302\0\205\204\205\0{|{\0aaa\0\202\0\0\0\0\24\27\27\27\204aaa\377"
+ "\\\\\\\372RRR\363LJL\351III\337JJL\323JJJ\306JIJ\270GGG\252ECC\235???\215"
+ "888~333p777a;;;RBBBD6667\0\1\1\4\0\0\0\0\206\377\377\377\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\34\311\311\311\0\225\224\225\0\256\253"
+ "\256\0\315\311\315\0\302\300\302\0\205\204\205\0z|z\0```\0\0\0\0\0\17\16"
+ "\17_YYY\377^\\\\\377RRR\377LLL\375GGG\366IJI\355JJJ\343III\327FFF\314CCC"
+ "\276???\260989\242333\223555\205999v@>@g<><X\12\12\12\32\202\0\0\0\0\206"
+ "\377\377\377\0\224\372\372\372\0\6\371\371\371\0\366\366\366\0\265\265\265"
+ "\0\356\356\356\0\274\274\274\0\261\260\261\0\202\332\332\332\0\33\311\311"
+ "\311\0\225\224\225\0\256\252\256\0\315\311\315\0\302\300\302\0\205\204\205"
+ "\0yzy\0^^^\0\1\1\1?QQQ\377^^\\\377PRR\377JII\377FFF\377GGG\377GGI\371GGG"
+ "\361FEF\350CCC\335???\321898\304323\267535\251999\232>==\213BBB|\31\31\31"
+ "G\203\0\0\0\0\206\377\377\377\0\224\372\372\372\0\"\371\371\371\0\366\366"
+ "\366\0\265\265\265\0\357\357\357\0\275\275\275\0\263\261\263\0\334\334\334"
+ "\27\334\334\334\31\312\312\312i\225\223\225\230\255\251\255\302\314\310\314"
+ "\306\300\276\300\310\202\201\202\302uvu\252XWX\243;<;\365EEE\377BBB\377F"
+ "FF\377BBB\377EEE\377FFF\377EFE\377CCC\374@A@\365===\354898\341232\326333"
+ "\312888\275===\257ECE\241%''\177\204\0\0\0\0\206\377\377\377\0\225\372\372"
+ "\372\0!\367\367\367\0\270\270\270\0\362\362\362\22\300\300\300f\266\265\266"
+ "\271\257\257\257\361\237\237\237\377\267\267\267\377\255\255\255\377\325"
+ "\325\325\377\302\302\302\377\317\317\317\377\255\255\255\377\256\257\256"
+ "\377\236\241\236\377\257\264\257\361\241\244\241\354ccc\366444\376666\377"
+ "BDB\377CCA\377AAA\377@??\377===\377989\370222\360232\346888\333;=;\317CC"
+ "C\302002\260\1\1\1\4\204\0\0\0\0\206\377\377\377\0\223\372\372\372\0\203"
+ "\373\373\373\0\37\275\275\275d\215\215\215\366\177\177\177\377\210\210\210"
+ "\377\225\225\225\377\260\260\260\377\253\253\253\377\320\321\320\377\260"
+ "\260\260\377\335\336\335\377\274\273\274\376\327\327\327\374\312\313\312"
+ "\371\263\264\263\365\330\332\330\361\355\356\355\354\376\377\376\360\307"
+ "\310\307\364VWV\374///\377>>>\377===\377;;;\377888\377222\377222\373777\364"
+ ";;;\352AAA\340999\325\5\5\4*\205\0\0\0\0\206\377\377\377\0\222\372\372\372"
+ "\0\31\373\373\373\0\375\375\375\0\377\377\377\0\301\301\301\250rrr\377uu"
+ "u\377\205\205\205\377\223\225\223\377\252\253\252\377\245\245\245\377\312"
+ "\312\312\377\245\246\245\377\327\326\327\377\262\261\262\377\276\275\276"
+ "\376\331\332\331\376\261\261\261\375\333\333\333\373\302\300\302\373\305"
+ "\305\305\373\366\367\366\372\377\377\377\374\352\355\352\375oqo\376323\377"
+ "\202777\377\202222\377\5""555\377999\376>@@\367>@>\357\21\20\22f\206\0\0"
+ "\0\0\206\377\377\377\0\214\372\372\372\0\205\373\373\373\0\"\374\374\374"
+ "\0\375\375\375\0\377\377\377\0\306\306\306\266ttt\377utu\377\201\201\201"
+ "\377\216\214\216\377\245\246\245\377\237\236\237\377\304\304\304\377\237"
+ "\236\237\377\314\314\314\377\273\272\273\377\256\256\256\377\343\344\343"
+ "\377\245\245\245\377\322\322\322\377\317\320\317\376\275\276\275\376\326"
+ "\326\326\376\311\311\311\376\323\324\323\376\326\331\326\376\245\247\245"
+ "\377MNM\376212\377111\377222\377557\377;99\377>>>\377BCB\377\27\30\27\241"
+ "\207\0\0\0\0\206\377\377\377\0\213\363\363\363\0\202\364\364\364\0%\343\341"
+ "\343\0\336\336\336\0\356\356\356\0\343\343\343\0\352\352\352\0\341\341\341"
+ "\0\326\327\326\202\203\203\203\377ono\377}|}\377\211\210\211\377\244\243"
+ "\244\377\234\235\234\377\300\300\300\377\245\243\245\377\300\300\300\377"
+ "\311\310\311\377\243\242\243\377\352\352\352\377\261\261\261\377\314\314"
+ "\314\377\330\330\330\377\275\276\275\377\325\325\325\377\323\322\323\377"
+ "\312\313\312\377\325\326\325\377\317\320\317\377z{z\377CIC\377EIE\377///"
+ "\377333\377999\377=>>\377ECE\377$#$\324\210\0\0\0\0\206\377\377\377\0\214"
+ "\364\364\364\0&\365\365\365\0\344\342\344\0\337\337\337\0\357\357\357\0\345"
+ "\345\345\0\356\356\356\0\347\347\347b\213\213\213\377omo\377~~~\377\214\215"
+ "\214\377\247\245\247\377\243\242\243\377\274\274\274\377\261\261\261\377"
+ "\265\266\265\377\326\325\326\377\233\234\233\377\350\350\350\377\273\272"
+ "\273\377\306\306\306\377\341\341\341\377\306\306\306\377\322\321\322\377"
+ "\326\326\326\377\323\324\323\377\324\325\324\377\332\333\332\377\331\332"
+ "\331\377\245\247\245\377Y_Y\377`b`\377WWW\377222\377===\377EEE\377000\362"
+ "\0\0\0\6\210\0\0\0\0\206\377\377\377\0\214\364\364\364\0%\365\365\365\0\344"
+ "\343\344\0\340\340\340\0\360\360\360\0\350\350\350\0\363\363\363P\223\223"
+ "\223\377rrr\377\201\201\201\377\224\224\224\377\252\252\252\377\256\256\256"
+ "\377\274\274\274\377\300\300\300\377\262\262\262\377\332\332\332\377\231"
+ "\230\231\377\340\340\340\377\304\303\304\377\273\273\273\377\343\343\343"
+ "\377\312\313\312\377\317\316\317\377\330\330\330\377\331\332\331\377\322"
+ "\322\322\377\332\330\332\377\332\333\332\377\317\320\317\377\352\354\352"
+ "\377\300\300\300\377ede\377nmn\377HGH\377===\377111\373\1\1\1\32\211\0\0"
+ "\0\0\206\377\377\377\0\214\364\364\364\0$\365\365\365\0\344\343\344\0\341"
+ "\341\341\0\363\363\363\0\355\355\355<\236\235\236\377{{{\377\214\215\214"
+ "\377\244\243\244\377\256\256\256\377\303\303\303\377\277\277\277\377\334"
+ "\334\334\377\266\266\266\377\345\345\345\377\247\247\247\377\323\323\323"
+ "\377\314\313\314\377\253\252\253\377\340\340\340\377\311\311\311\377\315"
+ "\316\315\377\327\325\327\377\334\334\334\377\320\320\320\377\325\325\325"
+ "\377\337\336\337\377\321\322\321\377\335\335\335\377\325\325\325\377\303"
+ "\303\303\377\306\305\306\377mjm\377NON\377000\376\0\0\0""6\212\0\0\0\0\206"
+ "\377\377\377\0\214\364\364\364\0#\365\365\365\0\345\344\345\0\344\344\344"
+ "\0\371\371\371-\234\234\234\372nmn\377zyz\377~|~\377olo\377\204\202\204\377"
+ "hhh\377\250\246\250\377\220\220\220\377\333\334\333\377\304\304\304\377\326"
+ "\325\326\377\340\340\340\377\256\255\256\377\333\332\333\377\310\310\310"
+ "\377\304\303\304\377\326\326\326\377\331\332\331\377\324\323\324\377\320"
+ "\316\320\377\341\341\341\377\322\322\322\377\325\325\325\377\331\332\331"
+ "\377\306\307\306\377\341\341\341\377\311\311\311\377utu\377B@B\377\200\201"
+ "\200\306\213\0\0\0\0\206\377\377\377\0\214\364\364\364\0$\366\366\366\0\350"
+ "\347\350\0\352\352\3523\216\216\216\361VSV\377TRT\377SQS\377ONO\377dbd\377"
+ "trt\377vuv\377ihi\377SRS\377hgh\377\\]\\\377\265\266\265\377\246\246\246"
+ "\377\335\335\335\377\327\327\327\377\276\276\276\377\327\330\327\377\323"
+ "\324\323\377\324\325\324\377\321\321\321\377\336\340\336\377\326\326\326"
+ "\377\320\317\320\377\333\332\333\377\314\314\314\377\327\326\327\377\312"
+ "\314\312\377\266\266\266\377\337\340\337\377WWW\377z{z\337\377\377\377\1"
+ "\212\0\0\0\0\206\377\377\377\0\213\364\364\364\0%\365\366\365\0\371\372\371"
+ "\0\356\355\356@ywy\377EAE\377OMO\377UWU\377][]\377\203\200\203\377\267\264"
+ "\267\377\325\322\325\377\312\310\312\377\255\253\255\377\222\222\222\377"
+ "\200\202\200\377quq\377]`]\377HKH\377\234\235\234\377\246\247\246\377\337"
+ "\337\337\377\332\331\332\377\320\321\320\377\324\324\324\377\334\335\334"
+ "\377\330\331\330\377\316\315\316\377\333\332\333\377\323\323\323\377\317"
+ "\315\317\377\323\322\323\377\276\277\276\377\332\333\332\377\272\271\272"
+ "\377\210\211\210\377nmn\377\341\340\341O\212\0\0\0\0\206\377\377\377\0\211"
+ "\364\364\364\0\202\365\365\365\0%\370\370\370\0\377\377\377\33\200|\200\366"
+ "858\377VUV\377\211\213\211\377\243\244\243\377\272\271\272\377\320\320\320"
+ "\377\330\327\330\377\327\326\327\377\314\312\314\377\267\266\267\377\242"
+ "\241\242\377\233\234\233\377\250\257\250\377\276\306\276\377\267\271\267"
+ "\377sts\377ILI\377\262\263\262\377\307\307\307\377\333\334\333\377\333\333"
+ "\333\377\332\333\332\377\321\321\321\377\332\333\332\377\325\325\325\377"
+ "\314\314\314\377\323\323\323\377\306\307\306\377\322\322\322\377\274\274"
+ "\274\377\263\263\263\377\333\333\333\377\213\207\213\377\314\310\314\217"
+ "\212\0\0\0\0\206\377\377\377\0\211\353\353\353\0(\354\354\354\0\355\355\355"
+ "\0\345\343\345\0\237\235\237\266<9<\377nmn\377\305\307\305\377\336\337\336"
+ "\377\345\346\345\377\340\342\340\377\325\326\325\377\320\323\320\377\321"
+ "\321\321\377\324\323\324\377\336\335\336\377\335\333\335\377\313\312\313"
+ "\377\277\304\277\377\321\324\321\377\365\363\365\377\377\377\377\377\307"
+ "\310\307\377Z\\Z\377fhf\377\345\344\345\377\341\342\341\377\317\320\317\377"
+ "\334\333\334\377\331\332\331\377\311\313\311\377\323\321\323\377\315\315"
+ "\315\377\312\311\312\377\310\310\310\377\266\264\266\377\323\324\323\377"
+ "\261\261\261\377\266\262\266\377\273\271\273\307\362\362\362\0\211\357\357"
+ "\357\0\206\377\377\377\0\211\354\354\354\0(\355\355\355\0\357\357\357\0\350"
+ "\347\3508YUY\377\177}\177\377\340\340\340\377\345\345\345\377\322\322\322"
+ "\377\265\267\265\377\203\202\203\377}|}\377yzy\377OPO\377QRQ\377\203~\203"
+ "\377\260\257\260\377\317\316\317\377\323\322\323\377\316\315\316\377\334"
+ "\336\334\377\364\365\364\377\377\377\377\377\335\342\335\377z|z\377hgh\377"
+ "\257\260\257\377\350\350\350\377\336\337\336\377\305\306\305\377\326\325"
+ "\326\377\317\320\317\377\305\305\305\377\315\314\315\377\273\273\273\377"
+ "\325\325\325\377\243\243\243\377\302\301\302\377\301\302\301\377\255\253"
+ "\255\332\331\330\331\0\211\327\326\327\0\206\377\377\377\0\211\355\355\355"
+ "\0)\356\356\356\0\361\361\361\0\271\270\271\203srs\377\336\340\336\377\341"
+ "\341\341\377\256\254\256\377\220\222\220\377nnn\377igi\377wxw\377KLK\377"
+ "676\377ROR\377kjk\377\221\225\221\377\303\303\303\377\320\315\320\377\311"
+ "\313\311\377\307\311\307\377\323\323\323\377\341\343\341\377\327\334\327"
+ "\377\254\256\254\377ORO\377non\377\310\310\310\377\276\277\276\377\322\322"
+ "\322\377\326\326\326\377\300\300\300\377\321\320\321\377\300\300\300\377"
+ "\316\316\316\377\266\266\266\377\261\261\261\377\301\301\301\377\270\270"
+ "\270\377\312\312\312\327\332\332\332\0\330\330\330\0\210\327\327\327\0\206"
+ "\377\377\377\0\204\331\330\331\0\3\332\330\332\0\332\331\332\0\332\330\332"
+ "\0\202\331\330\331\0(\332\331\332\0\335\334\335\0\222\221\222\311\302\304"
+ "\302\377\344\344\344\377\246\244\246\377\203\204\203\377www\377nkn\377}~"
+ "}\377WXW\377:<:\377WTW\377trt\377\225\231\225\377\300\301\300\377\320\316"
+ "\320\377\307\311\307\377\334\335\334\377\342\341\342\377\312\313\312\377"
+ "\317\317\317\377\277\303\277\377rtr\377ORO\377DGD\377MNM\377\303\304\303"
+ "\377\350\351\350\377\262\260\262\377\323\321\323\377\300\300\300\377\277"
+ "\276\277\377\306\305\306\377\255\255\255\377\313\313\313\377\244\244\244"
+ "\377\307\311\307\377\321\323\321\275\374\374\374\0\211\372\372\372\0\206"
+ "\377\377\377\0\203\331\331\331\0\1\332\332\332\0\203\333\333\333\0+\332\332"
+ "\332\0\331\331\331\0\332\332\332\0\334\334\334\14\273\274\273\345\336\341"
+ "\336\377\255\255\255\377\202\203\202\377~\177~\377mjm\377\177\200\177\377"
+ "_`_\377;=;\377QQQ\377olo\377\217\221\217\377\272\274\272\377\320\317\320"
+ "\377\311\311\311\377\325\330\325\377\361\357\361\377\316\316\316\377\236"
+ "\237\236\377\301\302\301\377\322\330\322\377\236\242\236\377>D>\377JNJ\377"
+ "YYY\377sts\377\227\227\227\377\311\310\311\377\317\317\317\377\260\260\260"
+ "\377\322\321\322\377\252\252\252\377\321\320\321\377\236\237\236\377\302"
+ "\303\302\377\273\273\273\377\333\333\333\310\365\365\365\0\363\363\363\0"
+ "\210\362\362\362\0\206\377\377\377\0\202\360\360\360\0\6\371\367\371\0\340"
+ "\340\340\0\315\315\315\0\316\316\316\0\325\327\325\0\363\363\363\0\202\362"
+ "\362\362\0(\364\364\364\7\325\331\325\356\265\264\265\377\202\203\202\377"
+ "\202\204\202\377kjk\377\200\177\200\377fgf\377=?=\377POP\377xvx\377\240\243"
+ "\240\377\305\307\305\377\327\325\327\377\315\312\315\377\322\323\322\377"
+ "\357\356\357\377\332\331\332\377\232\231\232\377\240\240\240\377\311\307"
+ "\311\377\316\322\316\377\326\334\326\377\237\244\237\377XYX\377mkm\377PO"
+ "P\377\201\201\201\377\336\336\336\377\251\251\251\377\321\320\321\377\246"
+ "\247\246\377\304\305\304\377\254\255\254\377\265\265\265\377\275\276\275"
+ "\377\301\301\301\377\326\326\326\262\360\360\360\0\356\356\356\0\210\355"
+ "\355\355\0\206\377\377\377\0\202\357\357\357\0""0\370\366\370\0\340\340\340"
+ "\0\315\315\315\0\317\317\317\0\326\330\326\0\273\274\273\0\350\350\350\0"
+ "\377\377\377\0\377\377\377\27\274\275\274\377\203\201\203\377\204\206\204"
+ "\377kik\377~~~\377mnm\377=@=\377MNM\377OLO\377545\377[\\[\377\237\235\237"
+ "\377\314\311\314\377\342\343\342\377\377\377\377\377\356\354\356\377\247"
+ "\247\247\377\244\244\244\377\307\306\307\377\323\324\323\377\276\300\276"
+ "\377\302\306\302\377\327\334\327\377\242\244\242\377fbf\377`]`\377UUU\377"
+ "xxx\377\316\316\316\377\275\275\275\377\254\256\254\377\300\276\300\377\247"
+ "\247\247\377\276\276\276\377\266\266\266\377\271\271\271\377\321\321\321"
+ "\276\363\363\363\0\361\361\361\0\210\360\360\360\0\206\377\377\377\0\202"
+ "\357\357\357\0/\367\366\367\0\340\340\340\0\315\315\315\0\317\317\317\0\327"
+ "\330\327\0\275\276\275\0\354\354\354\0\256\255\256\0\335\335\335M\201\201"
+ "\201\377~\177~\377dbd\377rrr\377jkj\377=@=\377GHG\377SOS\377-,-\377GGG\377"
+ "AEA\377*-*\377/./\377IJI\377\212\210\212\377\241\240\241\377\272\273\272"
+ "\377\327\327\327\377\331\330\331\377\303\303\303\377\266\272\266\377\312"
+ "\311\312\377\324\327\324\377\326\334\326\377\213\214\213\377LJL\377HHH\377"
+ "non\377\306\306\306\377\264\264\264\377\314\313\314\377\236\236\236\377\304"
+ "\303\304\377\262\262\262\377\275\275\275\377\260\260\260\377\320\320\320"
+ "\237\364\364\364\0\211\362\362\362\0\206\377\377\377\0\202\357\357\357\0"
+ "/\367\366\367\0\340\340\340\0\315\315\315\0\320\320\320\0\331\332\331\0\301"
+ "\302\301\0\361\361\361\1\264\263\264U~{~\365\213\214\213\377\236\233\236"
+ "\377\241\236\241\377\226\225\226\377Z\\Z\377ACA\377ZVZ\377jij\377\225\230"
+ "\225\377\250\255\250\377\301\312\301\377\335\340\335\377\340\341\340\377"
+ "\265\265\265\377mnm\377)))\377@@@\377\243\240\243\377\332\333\332\377\310"
+ "\314\310\377\304\310\304\377\337\334\337\377\330\326\330\377\314\322\314"
+ "\377\311\317\311\377WUW\377CCC\377HKH\377\202\203\202\377\337\336\337\377"
+ "\251\250\251\377\277\301\277\377\262\262\262\377\274\274\274\377\256\256"
+ "\256\377\243\243\243\377\342\343\342^\337\337\337\0\211\336\336\336\0\206"
+ "\377\377\377\0\202\357\357\357\0/\367\366\367\0\340\340\340\0\316\316\316"
+ "\0\322\322\322\0\335\336\335\0\306\310\306|\203\205\203\354dad\377}{}\377"
+ "\267\265\267\377\326\321\326\377\314\312\314\377\264\262\264\377\233\233"
+ "\233\377\221\220\221\377\206\206\206\377\236\241\236\377\271\276\271\377"
+ "\254\263\254\377\315\320\315\377\352\353\352\377\375\376\375\377\377\377"
+ "\377\377\375\377\375\377\301\302\301\377ILI\377\10\11\10\377,,,\377\230\232"
+ "\230\377\361\360\361\377\354\351\354\377\264\265\264\377\247\246\247\377"
+ "\331\336\331\377\235\240\235\377FGF\377XXX\377rrr\377\270\270\270\377\306"
+ "\306\306\377\275\276\275\377\273\274\273\377\265\267\265\377\231\230\231"
+ "\377\240\240\240\377\316\314\316#\314\311\314\0\211\313\310\313\0\206\377"
+ "\377\377\0\202\357\357\357\0/\367\366\367\0\340\340\340\0\320\320\320\0\326"
+ "\326\326\15\220\222\220\320`b`\377ZWZ\377\177|\177\377\263\263\263\377\317"
+ "\314\317\377\305\302\305\377\255\254\255\377\230\231\230\377\225\224\225"
+ "\377\233\233\233\377\246\253\246\377\273\303\273\377\323\326\323\377\325"
+ "\327\325\377\344\344\344\377\356\354\356\377\344\342\344\377\327\332\327"
+ "\377\304\305\304\377~\177~\377WZW\377NSN\377:;:\377\15\15\15\377`^`\377\307"
+ "\310\307\377\246\243\246\377\235\234\235\377\307\314\307\377\317\326\317"
+ "\377rrr\377|w|\377SSS\377\253\253\253\377\323\323\323\377\273\273\273\377"
+ "\272\273\272\377\244\244\244\377|||\377\275\275\275\242\315\312\315\0\313"
+ "\311\313\0\211\312\310\312\0\206\377\377\377\0\202\357\357\357\0.\370\367"
+ "\370\0\342\342\342\0\322\322\322\4\215\215\215\320TWT\377^\\^\377zxz\377"
+ "\253\251\253\377\312\307\312\377\304\301\304\377\254\251\254\377\226\225"
+ "\226\377\217\216\217\377\226\226\226\377\237\242\237\377\262\272\262\377"
+ "\315\320\315\377\344\344\344\377\360\361\360\377\362\362\362\377\344\343"
+ "\344\377\260\257\260\377\241\243\241\377\304\302\304\377\217\221\217\377"
+ "FKF\377PQP\377uuu\377kkk\377\24\25\24\377\22\22\22\377\221\220\221\377\310"
+ "\314\310\377\325\325\325\377\321\325\321\377\255\255\255\377\235\224\235"
+ "\377lll\377}~}\377\313\312\313\377\303\303\303\377\253\253\253\377\205\204"
+ "\205\377\210\207\210\364\362\362\362\32\356\356\356\0\212\354\354\354\0\206"
+ "\377\377\377\0\202\357\357\357\0.\371\367\371\0\343\343\343\0\217\220\217"
+ "\267{}{\377\243\242\243\377\262\262\262\377\301\301\301\377\306\306\306\377"
+ "\306\305\306\377\274\274\274\377\253\252\253\377\230\230\230\377\222\222"
+ "\222\377\231\235\231\377\256\264\256\377\307\313\307\377\341\337\341\377"
+ "\355\355\355\377\360\361\360\377\361\363\361\377\341\345\341\377\264\267"
+ "\264\377\305\301\305\377\336\336\336\377\320\321\320\377\256\261\256\377"
+ "\215\220\215\377hfh\377XXX\377[[[\377#$#\377\10\12\10\377\276\275\276\377"
+ "\357\355\357\377\312\316\312\377\310\312\310\377\256\251\256\377vyv\377n"
+ "on\377\324\324\324\377\266\266\266\377\221\220\221\377yxy\377\336\335\336"
+ "S\356\356\356\0\353\353\353\0\212\352\352\352\0\206\377\377\377\0""0\357"
+ "\357\357\0\360\360\360\0\372\370\372\0\274\275\274\243\260\261\260\377\330"
+ "\331\330\377\335\336\335\377\331\333\331\377\326\327\326\377\323\324\323"
+ "\377\321\322\321\377\322\321\322\377\323\322\323\377\317\316\317\377\302"
+ "\302\302\377\267\272\267\377\303\307\303\377\336\336\336\377\356\356\356"
+ "\377\360\361\360\377\360\360\360\377\347\353\347\377\323\331\323\377\252"
+ "\254\252\377\233\232\233\377\317\320\317\377\301\302\301\377\306\313\306"
+ "\377\351\347\351\377\277\277\277\377Y[Y\377BDB\377ghg\377NJN\377,(,\377\305"
+ "\302\305\377\331\333\331\377\314\317\314\377\255\255\255\377~~~\377X[X\377"
+ "\270\272\270\377\254\253\254\377usu\377\314\313\314}\331\330\331\0\352\352"
+ "\352\0\351\351\351\0\212\350\350\350\0\206\377\377\377\0\7\360\360\360\0"
+ "\361\361\361\0\330\331\330\220\311\312\311\377\326\327\326\377\322\323\322"
+ "\377\321\322\321\377\203\320\321\320\377\2\320\320\320\377\323\323\323\377"
+ "\202\324\323\324\377\36\326\325\326\377\323\322\323\377\317\315\317\377\334"
+ "\334\334\377\357\360\357\377\363\364\363\377\352\355\352\377\327\334\327"
+ "\377\266\271\266\377~~~\377KMK\377did\377\300\305\300\377\332\333\332\377"
+ "\345\341\345\377\314\316\314\377\232\231\232\377ddd\377wrw\377\300\270\300"
+ "\377<;<\377FFF\377\346\344\346\377\315\321\315\377\265\265\265\377\212\207"
+ "\212\377]`]\377\274\275\274\377\210\207\210\377\246\246\246\301\224\377\377"
+ "\377\0\17\355\355\355\0\337\340\337]\306\307\306\377\321\323\321\377\320"
+ "\321\320\377\320\320\320\377\320\321\320\377\325\326\325\377\336\337\336"
+ "\377\340\341\340\377\335\335\335\377\300\277\300\377\241\241\241\377\301"
+ "\300\301\377\310\306\310\377\202\317\316\317\377\33\312\312\312\377\320\317"
+ "\320\377\337\343\337\377\333\341\333\377\276\302\276\377\210\211\210\377"
+ "_^_\377EKE\377;?;\377\202\205\202\377\354\350\354\377\317\320\317\377\235"
+ "\234\235\377\237\235\237\377\276\300\276\377\263\254\263\377\261\256\261"
+ "\377Z[Z\377!!!\377\306\306\306\377\321\324\321\377\301\302\301\377\226\227"
+ "\226\377WZW\377\234\235\234\377\220\220\220\371\354\353\354\27\224\377\377"
+ "\377\0\20\357\357\357\0\316\317\316\347\316\317\316\377\320\321\320\377\320"
+ "\320\320\377\322\322\322\377\340\341\340\377\323\324\323\377\244\245\244"
+ "\377xyx\377\225\224\225\377\276\276\276\377\252\252\252\377\246\244\246\377"
+ "\305\303\305\377\323\323\323\377\202\313\314\313\377\32\314\314\314\377\310"
+ "\312\310\377\277\301\277\377\215\217\215\377aba\377KOK\377IMI\377Y\\Y\377"
+ "cac\377\236\235\236\377\262\262\262\377\230\224\230\377\260\262\260\377\335"
+ "\333\335\377\342\335\342\377\267\264\267\377===\377)))\377\245\250\245\377"
+ "\322\325\322\377\317\321\317\377\213\215\213\377Y[Y\377\224\225\224\377\336"
+ "\335\336]\351\350\351\0\224\377\377\377\0\23\340\340\340T\312\313\312\377"
+ "\320\321\320\377\320\320\320\377\323\322\323\377\343\343\343\377\240\240"
+ "\240\377???\377\16\16\16\377\35\35\35\377\246\245\246\377\313\313\313\377"
+ "\253\251\253\377\277\275\277\377\344\343\344\377\335\335\335\377\310\310"
+ "\310\377\311\311\311\377\314\314\314\377\202\316\317\316\377\27\226\230\226"
+ "\377DGD\377@G@\377V[V\377kkk\377pnp\377]]]\377\207\204\207\377\260\262\260"
+ "\377\317\322\317\377\340\335\340\377\343\340\343\377\270\270\270\377\15\16"
+ "\15\377IJI\377\220\224\220\377\330\332\330\377\312\314\312\377chc\377^`^"
+ "\377\302\302\302\255\332\331\332\0\346\345\346\0\224\377\377\377\0-\326\326"
+ "\326\246\315\316\315\377\320\320\320\377\321\321\321\377\341\341\341\377"
+ "\237\237\237\377\37\35\37\377232\377---\377\235\232\235\377\305\305\305\377"
+ "\234\232\234\377\253\247\253\377\332\332\332\377\354\355\354\377\333\335"
+ "\333\377\333\333\333\377\323\323\323\377\312\310\312\377\315\313\315\377"
+ "\321\320\321\377\331\331\331\377\221\223\221\377INI\377ccc\377sos\377lkl"
+ "\377WWW\377UUU\377\302\306\302\377\346\344\346\377\333\325\333\377\340\337"
+ "\340\377\255\255\255\377GHG\377JMJ\377\261\262\261\377\334\334\334\377\230"
+ "\232\230\377ADA\377z{z\377\377\377\377\31\370\370\370\0\365\365\365\0\364"
+ "\364\364\0\215\363\363\363\0\206\377\377\377\0,\322\321\322\302\316\317\316"
+ "\377\320\320\320\377\326\326\326\377\321\321\321\377888\377343\377VUV\377"
+ "\201\200\201\377\234\236\234\377\250\252\250\377\303\301\303\377\277\277"
+ "\277\377\272\273\272\377\270\272\270\377\321\322\321\377\374\374\374\377"
+ "\376\376\376\377\335\336\335\377\313\310\313\377\315\314\315\377\322\321"
+ "\322\377\333\331\333\377\226\227\226\377eae\377ljl\377bbb\377VUV\377===\377"
+ "\223\222\223\377\354\346\354\377\332\330\332\377\315\315\315\377\242\240"
+ "\242\377QTQ\377tvt\377\332\333\332\377\307\310\307\377XZX\377HJH\377\320"
+ "\320\320|\372\372\372\0\366\366\366\0\365\364\365\0\216\364\364\364\0\206"
+ "\377\377\377\0*\323\324\323\300\316\316\316\377\320\320\320\377\335\335\335"
+ "\377\250\250\250\377000\377LLL\377rpr\377\234\234\234\377\264\265\264\377"
+ "\351\346\351\377\364\365\364\377\362\364\362\377\367\367\367\377\347\345"
+ "\347\377\274\274\274\377\321\321\321\377\377\377\377\377\361\363\361\377"
+ "\326\325\326\377\311\310\311\377\310\311\310\377\316\317\316\377\322\324"
+ "\322\377\217\217\217\377YYY\377YWY\377ONO\377GIG\377gfg\377\332\326\332\377"
+ "\331\331\331\377\262\261\262\377aba\377NQN\377\304\305\304\377\334\335\334"
+ "\377\214\217\214\377575\377\234\234\234\304\371\372\371\0\362\363\362\0\220"
+ "\360\361\360\0\206\377\377\377\0*\334\335\334\240\315\315\315\377\320\320"
+ "\320\377\336\335\336\377\232\231\232\377A>A\377ZWZ\377\216\216\216\377\263"
+ "\264\263\377\340\337\340\377\357\357\357\377\350\352\350\377\361\362\361"
+ "\377\374\372\374\377\377\377\377\377\311\307\311\377\227\226\227\377\247"
+ "\250\247\377\343\344\343\377\355\357\355\377\341\340\341\377\304\305\304"
+ "\377\305\312\305\377\315\320\315\377\317\323\317\377ppp\377EDE\377MMM\377"
+ "XYX\377qpq\377\277\272\277\377\306\304\306\377~~~\377<@<\377\253\255\253"
+ "\377\336\337\336\377\255\256\255\377@C@\377\225\226\225\304\366\366\366\12"
+ "\364\365\364\0\361\362\361\0\220\360\361\360\0\206\377\377\377\0)\333\335"
+ "\333e\315\315\315\377\320\320\320\377\334\332\334\377\243\242\243\377HDH"
+ "\377`_`\377\244\245\244\377\334\333\334\377\357\357\357\377\350\351\350\377"
+ "\357\361\357\377\372\367\372\377\373\373\373\377\320\317\320\377\256\254"
+ "\256\377\204\201\204\377\177}\177\377\275\276\275\377\364\364\364\377\377"
+ "\377\377\377\330\331\330\377\301\305\301\377\307\312\307\377\321\330\321"
+ "\377\275\277\275\377NNN\377NQN\377ono\377\227\215\227\377\262\254\262\377"
+ "\231\232\231\377?@?\377\206\210\206\377\326\327\326\377\257\260\257\377n"
+ "pn\377\246\247\246\202\354\354\354\7\361\361\361\0\361\362\361\0\221\360"
+ "\361\360\0\206\377\377\377\0)\356\357\356\32\321\321\321\377\316\316\316"
+ "\377\331\330\331\377\271\270\271\377NLN\377SSS\377\301\301\301\377\366\365"
+ "\366\377\352\353\352\377\355\356\355\377\370\367\370\377\373\372\373\377"
+ "\335\336\335\377\256\254\256\377\220\216\220\377tqt\377\353\350\353\377\315"
+ "\317\315\377\302\303\302\377\377\377\377\377\353\354\353\377\311\313\311"
+ "\377\305\310\305\377\310\314\310\377\326\334\326\377\227\231\227\377YYY\377"
+ "\214\204\214\377\254\245\254\377\246\247\246\377SUS\377Z\\Z\377\315\317\315"
+ "\377\304\305\304\316\254\255\254\232\313\314\313(\242\243\242\0\351\350\351"
+ "\0\357\357\357\0\361\362\361\0\221\360\361\360\0\206\377\377\377\0(\354\355"
+ "\354\0\333\333\333\301\313\313\313\377\323\322\323\377\324\321\324\377[["
+ "[\377<=<\377\272\272\272\377\372\372\372\377\355\356\355\377\366\365\366"
+ "\377\372\367\372\377\346\347\346\377\255\252\255\377\231\227\231\377jgj\377"
+ "\323\321\323\377\354\355\354\377\336\337\336\377\274\277\274\377\327\330"
+ "\327\377\363\364\363\377\336\337\336\377\305\311\305\377\307\313\307\377"
+ "\312\320\312\377\310\312\310\377\211\203\211\377\240\227\240\377\250\251"
+ "\250\377\225\225\225\377SUS\377\316\317\316\216\364\365\364A\332\332\332"
+ "\0\252\253\252\0\311\312\311\0\240\241\240\0\350\347\350\0\356\356\356\0"
+ "\222\360\361\360\0\206\377\377\377\0(\355\353\355\0\357\355\357L\313\312"
+ "\313\377\316\315\316\377\337\336\337\377\211\210\211\377\"#\"\377yzy\377"
+ "\373\375\373\377\372\371\372\377\370\367\370\377\357\357\357\377\315\315"
+ "\315\377\277\274\277\377\204\202\204\377\272\270\272\377\362\362\362\377"
+ "\327\330\327\377\350\352\350\377\320\316\320\377\255\257\255\377\366\366"
+ "\366\377\331\331\331\377\306\314\306\377\310\315\310\377\307\314\307\377"
+ "\314\322\314\377\273\270\273\377\241\237\241\377\232\236\232\377\227\225"
+ "\227\377\312\312\312\232\310\311\310\0\360\361\360\0\330\330\330\0\251\252"
+ "\251\0\310\311\310\0\240\241\240\0\347\347\347\0\356\356\356\0\222\360\361"
+ "\360\0\206\377\377\377\0(\371\370\371\0\373\372\373\0\333\332\333\314\312"
+ "\311\312\377\327\326\327\377\314\313\314\377464\377)+)\377\320\316\320\377"
+ "\377\377\377\377\357\360\357\377\342\343\342\377\342\344\342\377\320\315"
+ "\320\377\315\313\315\377\355\355\355\377\331\332\331\377\343\343\343\377"
+ "\342\340\342\377\270\265\270\377\232\232\232\377\334\333\334\377\264\265"
+ "\264\377\255\257\255\377\315\322\315\377\306\313\306\377\310\316\310\377"
+ "\307\310\307\377\233\235\233\377\227\227\227\377\256\256\256\377\347\350"
+ "\347;\343\344\343\0\355\357\355\0\327\327\327\0\250\251\250\0\310\311\310"
+ "\0\240\241\240\0\347\347\347\0\356\356\356\0\222\360\361\360\0\206\377\377"
+ "\377\0(\370\367\370\0\371\370\371\0\364\363\364<\314\313\314\377\316\315"
+ "\316\377\342\341\342\377\223\223\223\377\24\26\24\377_^_\377\363\362\363"
+ "\377\357\360\357\377\345\345\345\377\367\370\367\377\374\375\374\377\361"
+ "\357\361\377\330\331\330\377\336\337\336\377\347\346\347\377\302\300\302"
+ "\377\253\252\253\377\250\251\250\377\272\273\272\377tst\377\\]\\\377\325"
+ "\327\325\377\311\314\311\377\310\314\310\377\313\314\313\377\237\235\237"
+ "\377\243\241\243\377\275\301\275\377\350\350\350'\346\345\346\0\345\345\345"
+ "\0\325\325\325\0\246\250\246\0\307\310\307\0\237\240\237\0\347\347\347\0"
+ "\356\356\356\0\222\360\361\360\0\206\377\377\377\0\202\370\367\370\0\36\363"
+ "\362\363\0\344\344\344\222\310\310\310\377\321\321\321\377\332\333\332\377"
+ "pqp\377%#%\377xwx\377\351\351\351\377\377\377\377\377\376\376\376\377\363"
+ "\361\363\377\333\333\333\377\331\334\331\377\351\351\351\377\314\313\314"
+ "\377\247\245\247\377\301\302\301\377\261\263\261\377\220\220\220\377\40\37"
+ "\40\377KLK\377\326\331\326\377\312\315\312\377\307\311\307\377\311\312\311"
+ "\377\254\252\254\377\263\262\263\377\301\303\301\342\367\367\367\0\202\364"
+ "\364\364\0\6\365\365\365\0\370\370\370\0\304\306\304\0\236\237\236\0\347"
+ "\347\347\0\356\356\356\0\222\360\361\360\0\206\377\377\377\0\202\373\373"
+ "\373\0\36\374\374\374\0\376\377\376\0\332\330\332\311\305\310\305\377\322"
+ "\324\322\377\326\327\326\377rqr\377111\377rrr\377\354\354\354\377\377\377"
+ "\377\377\345\346\345\377\330\333\330\377\351\352\351\377\327\325\327\377"
+ "\253\251\253\377\270\270\270\377\312\312\312\377\237\236\237\377III\377\22"
+ "\22\22\377^`^\377\327\332\327\377\312\314\312\377\306\307\306\377\305\307"
+ "\305\377\274\276\274\377\247\251\247\377\307\307\307x\366\366\366\0\202\363"
+ "\363\363\0\6\364\364\364\0\366\366\366\0\302\303\302\0\234\235\234\0\346"
+ "\346\346\0\356\356\356\0\222\360\361\360\0\206\377\377\377\0\202\373\373"
+ "\373\0&\373\374\373\0\375\375\375\0\365\365\365\12\322\322\322\342\307\310"
+ "\307\377\322\324\322\377\323\330\323\377|\200|\377...\377HGH\377\243\240"
+ "\243\377\327\327\327\377\363\365\363\377\351\350\351\377\273\271\273\377"
+ "\271\270\271\377\316\317\316\377\251\251\251\377ZYZ\377-,-\377\36\35\36\377"
+ "\210\210\210\377\327\331\327\377\307\310\307\377\305\306\305\377\307\310"
+ "\307\377\262\266\262\377\251\252\251\325\357\357\357\0\354\354\354\0\353"
+ "\353\353\0\352\352\352\0\353\353\353\0\354\354\354\0\355\355\355\0\356\356"
+ "\356\0\344\344\344\0\355\355\355\0\222\360\361\360\0\206\377\377\377\0\203"
+ "\373\373\373\0\26\374\374\374\0\364\364\364\0\366\366\366\34\324\324\324"
+ "\347\304\307\304\377\315\322\315\377\324\333\324\377\227\234\227\377545\377"
+ "!\36!\377YYY\377\217\216\217\377\244\243\244\377\233\231\233\377\243\243"
+ "\243\377\204\205\204\377NMN\377.-.\377\40\37\40\377666\377\304\307\304\377"
+ "\315\316\315\377\202\305\306\305\377\4\303\304\303\377\236\237\236\377\336"
+ "\336\336*\355\355\355\0\206\353\353\353\0\3\354\354\354\0\343\343\343\0\355"
+ "\355\355\0\222\360\361\360\0\206\377\377\377\0\203\373\373\373\0\34\374\374"
+ "\374\0\363\363\363\0\364\364\364\0\362\361\362\25\321\325\321\323\302\307"
+ "\302\377\310\316\310\377\325\334\325\377\302\306\302\377efe\377///\377=<"
+ "=\377<;<\3770/0\377.,.\377'$'\377#\"#\377\36\35\36\377343\377\253\254\253"
+ "\377\324\324\324\377\306\307\306\377\305\306\305\377\307\310\307\377\261"
+ "\263\261\377\310\311\310q\333\333\333\0\354\354\354\0\207\352\352\352\0\3"
+ "\342\342\342\0\354\355\354\0\360\361\360\0\221\357\361\357\0\206\377\377"
+ "\377\0\203\373\373\373\0\6\374\374\374\0\362\362\362\0\363\363\363\0\360"
+ "\360\360\0\364\363\364\1\332\335\332\241\202\305\312\305\377\6\330\335\330"
+ "\377\271\276\271\377<;<\377868\377&$&\377>=>\377\202=;=\377\13MMM\377z|z"
+ "\377\301\305\301\377\326\325\326\377\306\310\306\377\305\306\305\377\304"
+ "\305\304\377\277\301\277\377\313\314\313\277\372\371\372\0\367\366\367\0"
+ "\211\366\365\366\0\1\366\364\366\0\222\365\364\365\0\206\377\377\377\0\203"
+ "\373\373\373\0\33\374\374\374\0\362\362\362\0\363\363\363\0\357\357\357\0"
+ "\363\362\363\0\330\334\330\0\351\352\351Y\316\321\316\354\304\312\304\377"
+ "\321\326\321\377\244\246\244\377DBD\377EDE\377\276\300\276\377\315\321\315"
+ "\377\307\313\307\377\320\322\320\377\326\330\326\377\316\320\316\377\307"
+ "\307\307\377\306\306\306\377\305\305\305\377\277\300\277\377\311\314\311"
+ "\364\370\371\370\22\367\366\367\0\366\365\366\0\234\365\364\365\0\206\377"
+ "\377\377\0\203\373\373\373\0\32\374\374\374\0\362\362\362\0\363\363\363\0"
+ "\357\357\357\0\363\361\363\0\327\333\327\0\347\350\347\0\347\347\347\15\336"
+ "\340\336\213\317\323\317\372\317\323\317\377\306\311\306\377\307\313\307"
+ "\377\321\324\321\377\316\320\316\377\315\316\315\377\311\312\311\377\306"
+ "\307\306\377\306\306\306\377\307\306\307\377\305\304\305\377\300\300\300"
+ "\377\307\307\307\364\355\356\355;\366\367\366\0\366\364\366\0\235\365\364"
+ "\365\0\206\377\377\377\0\203\373\373\373\0\20\374\374\374\0\362\362\362\0"
+ "\363\363\363\0\357\357\357\0\363\361\363\0\327\333\327\0\347\350\347\0\346"
+ "\346\346\0\334\336\334\0\343\344\343\21\337\341\337u\327\331\327\333\314"
+ "\316\314\377\305\307\305\377\302\303\302\377\302\302\302\377\202\303\304"
+ "\303\377\1\304\302\304\377\202\302\302\302\377\4\325\325\325\267\357\357"
+ "\357\36\354\355\354\0\365\366\365\0\236\365\364\365\0\206\377\377\377\0\203"
+ "\373\373\373\0\31\374\374\374\0\362\362\362\0\363\363\363\0\357\357\357\0"
+ "\363\361\363\0\327\333\327\0\347\350\347\0\346\345\346\0\333\335\333\0\342"
+ "\342\342\0\335\337\335\0\360\356\360\0\343\342\343%\343\345\343g\326\325"
+ "\326\231\323\324\323\270\314\315\314\314\316\316\316\304\324\324\324\255"
+ "\337\340\337q\340\340\340+\323\323\323\0\356\356\356\0\353\354\353\0\365"
+ "\366\365\0\236\365\364\365\0\206\377\377\377\0",
+};
+
diff --git a/src/image_data/led_green.h b/src/image_data/led_green.h new file mode 100644 index 0000000..1015f47 --- /dev/null +++ b/src/image_data/led_green.h @@ -0,0 +1,44 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (led_green.c) */
+
+#include "image.h"
+
+static const nv_image_t led_green = {
+ 16, 16, 4,
+ "\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"
+ "\377\0\15\376\377\377\0\375\374\377\27\320\321\314\213\317\324\320\374\337"
+ "\354\332\377\325\356\304\377\312\345\272\377\277\335\253\377\265\322\264"
+ "\377\254\267\263\374\250\243\247\213\377\374\371\27\376\376\377\0\203\377"
+ "\377\377\0\15\377\376\375\0\314\314\314\213\340\347\361\377\331\360\306\377"
+ "\271\341\211\377\225\311[\377z\273-\377}\277A\377|\300m\377\224\274\231\377"
+ "\245\260\252\377\244\237\243\213\377\373\377\0\203\377\377\377\0\15\366\361"
+ "\356R\313\317\316\374\331\364\301\377\256\327y\377\247\324u\377\255\340\203"
+ "\377\233\332g\377~\311.\377]\260*\377d\246\\\377\214\262\231\377\213\225"
+ "\224\374\304\276\310R\203\377\377\377\0\15\314\306\320\234\335\350\344\377"
+ "\270\341\201\377\236\317f\377\305\352\266\377\322\361\317\377\271\337\254"
+ "\377\227\322T\377h\271\26\377<\217'\377b\246s\377\207\250\227\377\222\223"
+ "\230\234\203\377\377\377\0\15\300\275\310\327\332\356\323\377\223\312S\377"
+ "\241\331l\377\307\352\300\377\335\366\326\377\273\335\240\377\232\314[\377"
+ "p\273\30\3777\224\"\3776\217O\377\207\265\231\377quv\327\203\377\377\377"
+ "\0\15\304\276\276\372\323\353\307\377s\266\33\377\212\321E\377\250\330\216"
+ "\377\266\335\214\377\247\326z\377\214\315?\377\\\256\36\377+\220*\377\21"
+ "p.\377\216\275\235\377qsr\372\203\377\377\377\0\15\303\270\310\327\313\340"
+ "\317\377p\262D\377q\300&\377\212\314F\377\224\315H\377\205\3123\377f\270"
+ "\30\377D\236\"\377\21y\40\3774\217T\377\220\271\233\377hfg\327\203\377\377"
+ "\377\0\15\333\312\322\234\274\313\266\377\203\276z\377E\232%\377X\260\34"
+ "\377a\264\36\377Y\247\40\377G\226!\377\25z*\377\3j!\377e\270\204\377r\232"
+ "\202\377\205\207\204\234\203\377\377\377\0\15\372\362\377R\246\260\261\374"
+ "\246\312\260\377]\235`\377*\200%\377%\212\"\377\37\211'\377\12s\36\377\7"
+ "k#\377S\244j\377\212\271\225\377]i]\374\317\304\310R\203\377\377\377\0\15"
+ "\374\377\377\0\322\323\327\213\242\250\250\377\234\271\247\377g\246{\377"
+ "2\214O\377\15q3\3773\226]\377g\265\203\377\211\266\225\377iqd\377\237\225"
+ "\224\213\377\366\374\0\203\377\377\377\0\15\370\377\363\0\377\376\373\27"
+ "\330\313\322\213\234\230\231\374\222\244\230\377\217\265\234\377\220\273"
+ "\237\377\214\264\231\377w\230\203\377`j_\374\250\237\240\213\377\376\377"
+ "\27\373\377\377\0\203\377\377\377\0\15\376\377\377\0\376\374\377\0\377\371"
+ "\377\0\370\356\366R\312\304\310\234\236\232\233\327\210\202\204\372\216\205"
+ "\210\327\252\254\253\234\341\333\335R\377\375\377\0\362\373\372\0\367\377"
+ "\377\0\242\377\377\377\0",
+};
+
diff --git a/src/image_data/led_grey.h b/src/image_data/led_grey.h new file mode 100644 index 0000000..41218ba --- /dev/null +++ b/src/image_data/led_grey.h @@ -0,0 +1,38 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (led_grey.c) */
+
+#include "image.h"
+
+static const nv_image_t led_grey = {
+ 16, 16, 4,
+ "\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"
+ "\270\270\270\213\300\300\300\374\313\313\313\377\241\241\241\377\212\212"
+ "\212\377\177\177\177\377\216\216\216\377\217\217\217\374\226\226\226\213"
+ "\373\373\373\27\376\376\376\0\203\377\377\377\0\14\376\376\376\0\305\305"
+ "\305\213\317\317\317\377\252\252\252\377III\377\37\37\37\377\3\3\3\377\17"
+ "\17\17\377\37\37\37\377===\377www\377\215\215\215\213\204\377\377\377\0\15"
+ "\363\363\363R\270\270\270\374\260\260\260\377555\377FFF\377VVV\377DDD\377"
+ "\37\37\37\377\0\0\0\377\21\21\21\377+++\377eee\374\300\300\300R\203\377\377"
+ "\377\0\15\301\301\301\234\315\315\315\377PPP\377777\377\204\204\204\377\223"
+ "\223\223\377mmm\377333\377\0\0\0\377\3\3\3\377\14\14\14\377DDD\377uuu\234"
+ "\203\377\377\377\0\15\263\263\263\327\266\266\266\377\30\30\30\377JJJ\377"
+ "\202\202\202\377\237\237\237\377sss\377:::\377\5\5\5\377\0\0\0\377\6\6\6"
+ "\377;;;\377NNN\327\203\377\377\377\0\10\254\254\254\372\261\261\261\377\2"
+ "\2\2\377000\377XXX\377fff\377GGG\377!!!\377\202\0\0\0\377\3\3\3\3\377888"
+ "\377EEE\372\203\377\377\377\0\15\251\251\251\327\231\231\231\377\16\16\16"
+ "\377\13\13\13\377'''\377---\377###\377\4\4\4\377\0\0\0\377\2\2\2\377\10\10"
+ "\10\377HHH\377:::\327\203\377\377\377\0\3\300\300\300\234\234\234\234\377"
+ "###\377\202\0\0\0\377\2\5\5\5\377\0\0\0\377\202\1\1\1\377\4\0\0\0\377$$$"
+ "\377>>>\377fff\234\203\377\377\377\0\15\365\365\365R\217\217\217\374[[[\377"
+ "\21\21\21\377\3\3\3\377\0\0\0\377\2\2\2\377\0\0\0\377\1\1\1\377\25\25\25"
+ "\377HHH\377\40\40\40\374\301\301\301R\204\377\377\377\0\13\307\307\307\213"
+ "\202\202\202\377@@@\377\16\16\16\377\4\4\4\377\2\2\2\377\12\12\12\377((("
+ "\377CCC\377\30\30\30\377\201\201\201\213\205\377\377\377\0\14\375\375\375"
+ "\27\312\312\312\213qqq\374YYY\377;;;\377DDD\377@@@\377333\377(((\374\207"
+ "\207\207\213\377\377\377\27\375\375\375\0\205\377\377\377\0\13\372\372\372"
+ "\0\352\352\352R\252\252\252\234\201\201\201\327]]]\372eee\327\222\222\222"
+ "\234\317\317\317R\377\377\377\0\371\371\371\0\376\376\376\0\242\377\377\377"
+ "\0",
+};
+
diff --git a/src/image_data/led_red.h b/src/image_data/led_red.h new file mode 100644 index 0000000..f66a900 --- /dev/null +++ b/src/image_data/led_red.h @@ -0,0 +1,42 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (led_red.c) */
+
+#include "image.h"
+
+static const nv_image_t led_red = {
+ 16, 16, 4,
+ "\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"
+ "\342\325\317\377\333\321\320\377\305\305\303\377\266\300\277\356\326\342"
+ "\342|\377\376\377\6\205\377\377\377\0\13\357\363\364v\301\315\313\377\371"
+ "\354\346\377\361\225\230\377\360I[\377\300\27*\377\306IQ\377\311\202\206"
+ "\377\311\264\261\377\247\262\256\377\311\315\320v\204\377\377\377\0\15\377"
+ "\372\373<\304\312\310\343\373\332\341\377\343n\201\377\3375B\377\353B?\377"
+ "\3374-\377\315\12\20\377\241\4\27\377\240Z\\\377\247\250\240\377\227\235"
+ "\233\343\355\351\352<\203\377\377\377\0\15\336\336\346\206\347\350\332\377"
+ "\363\220\213\377\3416H\377\350\222\221\377\366\237\245\377\362w|\377\343"
+ "3=\377\301\16\22\377\224\21\27\377\220ws\377\247\226\234\377\255\255\255"
+ "\206\203\377\377\377\0\15\274\306\317\303\353\330\321\377\341DU\377\361`"
+ "m\377\355\272\267\377\377\334\332\377\371\231\233\377\340JK\377\323\21\34"
+ "\377\216\25\32\377tFH\377\256\227\235\377\206\204\205\303\203\377\377\377"
+ "\0\15\271\310\313\356\361\320\311\377\314\12\"\377\354OZ\377\351\237\240"
+ "\377\344\261\260\377\356\201\204\377\340=>\377\305\11\27\377\217\30\36\377"
+ "]\40'\377\265\232\241\377vxu\356\203\377\377\377\0\15\267\303\301\356\346"
+ "\312\277\377\3227=\377\340\32'\377\353NU\377\363\\e\377\346AH\377\335\30"
+ "\"\377\264\16\34\377w\35\35\377\200GM\377\273\211\225\377boh\356\203\377"
+ "\377\377\0\15\273\301\301\303\320\303\273\377\277nj\377\300\13\24\377\313"
+ "\14\21\377\341\30\"\377\306\16\30\377\272\10\30\377\215\24\33\377T\"\33\377"
+ "\242nr\377\266s\205\377\\pg\303\203\377\377\377\0\15\336\341\346\206\260"
+ "\256\261\377\273\237\236\377\257ST\377\234\30\26\377\243\23\22\377\236\27"
+ "\36\377{\25\40\377V!\33\377\225]\\\377\300\203\213\377qTY\377\234\250\244"
+ "\206\203\377\377\377\0\15\372\374\373<\265\266\272\343\257\250\257\377\250"
+ "\224\226\377\244qp\377\204CA\377f$&\377zNO\377\234{v\377\302\201\211\377"
+ "\207ce\377Z\\W\343\360\364\365<\204\377\377\377\0\13\362\367\361v\244\237"
+ "\246\377\225\225\235\377\232\213\222\377\261\221\226\377\270\231\227\377"
+ "\263\220\216\377\265oz\377~VW\377JXK\377\336\316\321v\205\377\377\377\0\13"
+ "\377\377\377\6\371\371\371|\270\270\270\356\207\206\204\377ztt\377qgh\377"
+ "j^`\377UUU\377\222\222\222\356\346\346\346|\377\377\377\6\207\377\377\377"
+ "\0\7\377\377\377J\365\365\363\227\336\332\331\324\314\306\306\372\323\312"
+ "\313\324\357\357\357\227\367\367\367J\225\377\377\377\0",
+};
+
diff --git a/src/image_data/rj45_input.h b/src/image_data/rj45_input.h new file mode 100644 index 0000000..75ea529 --- /dev/null +++ b/src/image_data/rj45_input.h @@ -0,0 +1,50 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (rj45_input.c) */
+
+#include "image.h"
+
+static const nv_image_t rj45_input = {
+ 20, 28, 4,
+ "\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"
+ "\0\0\0ddd\377\204\0\377\0\377\1ddd\377\204f\206\236\377\1""666\377\204\236"
+ "\245\212\377\2""666\377\0\0\0\0\202666\377\1\0\0\0\0\206ddd\377\204f\206"
+ "\236\377\206666\377\1\0\0\0\0\202666\377\202\0\0\0\0\1PPP\377\214f\206\236"
+ "\377\1PPP\377\202\0\0\0\0\202666\377\202\0\0\0\0\2PPP\377f\206\236\377\211"
+ "\307\323\334\377\3Jj\204\377f\206\236\377PPP\377\202\0\0\0\0\202666\377\202"
+ "\0\0\0\0\3PPP\377f\206\236\377\307\323\334\377\210\214\244\266\377\3Jj\204"
+ "\377f\206\236\377PPP\377\202\0\0\0\0\202666\377\202\0\0\0\0\16PPP\377f\206"
+ "\236\377\307\323\334\377\214\244\266\377v\220\244\377\245\267\305\377\303"
+ "\317\332\377\245\270\305\377\204\234\260\377e\201\231\377\214\244\266\377"
+ "Jj\204\377f\206\236\377PPP\377\202\0\0\0\0\202666\377\202\0\0\0\0\16PPP\377"
+ "f\206\236\377\307\323\334\377\214\244\266\377v\217\243\377\263\302\316\377"
+ "\317\331\342\377\250\272\307\377\177\230\254\377?^y\377\214\244\266\377J"
+ "j\204\377f\206\236\377PPP\377\202\0\0\0\0\202666\377\202\0\0\0\0\16PPP\377"
+ "f\206\236\377\307\323\334\377\214\244\266\377v\217\243\377\263\302\316\377"
+ "\327\337\347\377\250\272\307\377\177\230\254\377?^y\377\214\244\266\377J"
+ "j\204\377f\206\236\377PPP\377\202\0\0\0\0\202666\377\202\0\0\0\0\1PPP\377"
+ "\203f\206\236\377\6v\217\243\377\263\302\316\377\340\347\354\377\250\272"
+ "\307\377\177\230\254\377?^y\377\203f\206\236\377\1PPP\377\202\0\0\0\0\202"
+ "666\377\202\0\0\0\0\204PPP\377\6v\217\243\377\263\302\316\377\352\356\362"
+ "\377\250\272\307\377\177\230\254\377?^y\377\204PPP\377\202\0\0\0\0\20266"
+ "6\377\206\0\0\0\0\6v\217\243\377\263\302\316\377\365\367\371\377\250\272"
+ "\307\377\177\230\254\377?^y\377\206\0\0\0\0\210666\377\6v\217\243\377\263"
+ "\302\316\377\376\377\377\377\250\272\307\377\177\230\254\377?^y\377\2076"
+ "66\377\207\0\0\0\0\6v\217\243\377\263\302\316\377\377\377\377\377\250\272"
+ "\307\377\177\230\254\377?^y\377\216\0\0\0\0\6v\217\243\377\263\302\316\377"
+ "\377\377\377\377\250\272\307\377\177\230\254\377?^y\377\216\0\0\0\0\6v\217"
+ "\243\377\263\302\316\377\377\377\377\377\250\272\307\377\177\230\254\377"
+ "?^y\377\216\0\0\0\0\6v\217\243\371\263\302\316\371\377\377\377\377\250\272"
+ "\307\371\177\230\254\371?^y\371\216\0\0\0\0\6v\217\243\350\263\302\316\350"
+ "\377\377\377\377\250\272\307\350\177\230\254\350?^y\350\216\0\0\0\0\6v\217"
+ "\243\324\263\302\316\324\377\377\377\377\250\272\307\324\177\230\254\324"
+ "?^y\324\216\0\0\0\0\6v\217\243\275\263\302\316\275\377\377\377\377\250\272"
+ "\307\275\177\230\254\275?^y\275\216\0\0\0\0\6v\217\243\244\263\302\316\244"
+ "\377\377\377\377\250\272\307\244\177\230\254\244?^y\244\216\0\0\0\0\6v\217"
+ "\243\211\263\302\316\211\377\377\377\377\250\272\307\211\177\230\254\211"
+ "?^y\211\216\0\0\0\0\6v\217\243l\263\302\316l\377\377\377\377\250\272\307"
+ "l\177\230\254l?^yl\216\0\0\0\0\6v\217\243M\263\302\316M\377\377\377\377\250"
+ "\272\307M\177\230\254M?^yM\216\0\0\0\0\6v\217\243,\263\302\316,\377\377\377"
+ "\377\250\272\307,\177\230\254,?^y,\207\0\0\0\0",
+};
+
diff --git a/src/image_data/rj45_output.h b/src/image_data/rj45_output.h new file mode 100644 index 0000000..95674d8 --- /dev/null +++ b/src/image_data/rj45_output.h @@ -0,0 +1,53 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (rj45_output.c) */
+
+#include "image.h"
+
+static const nv_image_t rj45_output = {
+ 20, 28, 4,
+ "\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"
+ "\377\2""666\0ddd\377\204y\236y\377\1ddd\377\204f\206\236\377\1""666\377\204"
+ "\377\314\2\377\2""666\377\377\377\377\0\202666\377\1""666\0\206ddd\377\204"
+ "f\206\236\377\206666\377\1\377\377\377\0\202666\377\3""666\0\377\377\377"
+ "\0PPP\377\214f\206\236\377\1PPP\377\202\377\377\377\0\202666\377\4""666\0"
+ "\377\377\377\0PPP\377f\206\236\377\211\307\323\334\377\3Jj\204\377f\206\236"
+ "\377PPP\377\202\377\377\377\0\202666\377\5""666\0\377\377\377\0PPP\377f\206"
+ "\236\377\307\323\334\377\210\214\244\266\377\3Jj\204\377f\206\236\377PPP"
+ "\377\202\377\377\377\0\202666\377\20""666\0\377\377\377\0PPP\377f\206\236"
+ "\377\307\323\334\377\214\244\266\377v\220\244\377\245\267\305\377\303\317"
+ "\332\377\245\270\305\377\204\234\260\377e\201\231\377\214\244\266\377Jj\204"
+ "\377f\206\236\377PPP\377\202\377\377\377\0\202666\377\20""666\0\377\377\377"
+ "\0PPP\377f\206\236\377\307\323\334\377\214\244\266\377v\217\243\377\263\302"
+ "\316\377\317\331\342\377\250\272\307\377\177\230\254\377?^y\377\214\244\266"
+ "\377Jj\204\377f\206\236\377PPP\377\202\377\377\377\0\202666\377\20""666\0"
+ "\377\377\377\0PPP\377f\206\236\377\307\323\334\377\214\244\266\377v\217\243"
+ "\377\263\302\316\377\327\337\347\377\250\272\307\377\177\230\254\377?^y\377"
+ "\214\244\266\377Jj\204\377f\206\236\377PPP\377\202\377\377\377\0\202666\377"
+ "\3""666\0\377\377\377\0PPP\377\203f\206\236\377\6v\217\243\377\263\302\316"
+ "\377\340\347\354\377\250\272\307\377\177\230\254\377?^y\377\203f\206\236"
+ "\377\1PPP\377\202\377\377\377\0\202666\377\2""666\0\377\377\377\0\204PPP"
+ "\377\6v\217\243\377\263\302\316\377\352\356\362\377\250\272\307\377\177\230"
+ "\254\377?^y\377\204PPP\377\202666\0\202666\377\206666\0\6v\217\243\377\263"
+ "\302\316\377\365\367\371\377\250\272\307\377\177\230\254\377?^y\377\2066"
+ "66\0\210666\377\6v\217\243\377\263\302\316\377\376\377\377\377\250\272\307"
+ "\377\177\230\254\377?^y\377\207666\377\207\377\377\377\0\6v\217\243\377\263"
+ "\302\316\377\377\377\377\377\250\272\307\377\177\230\254\377?^y\377\216\377"
+ "\377\377\0\6v\217\243\377\263\302\316\377\377\377\377\377\250\272\307\377"
+ "\177\230\254\377?^y\377\216\377\377\377\0\6v\217\243\377\263\302\316\377"
+ "\377\377\377\377\250\272\307\377\177\230\254\377?^y\377\216\377\377\377\0"
+ "\6v\217\243\371\263\302\316\371\377\377\377\377\250\272\307\371\177\230\254"
+ "\371?^y\371\216\377\377\377\0\6v\217\243\350\263\302\316\350\377\377\377"
+ "\377\250\272\307\350\177\230\254\350?^y\350\216\377\377\377\0\6v\217\243"
+ "\324\263\302\316\324\377\377\377\377\250\272\307\324\177\230\254\324?^y\324"
+ "\216\377\377\377\0\6v\217\243\275\263\302\316\275\377\377\377\377\250\272"
+ "\307\275\177\230\254\275?^y\275\216\377\377\377\0\6v\217\243\244\263\302"
+ "\316\244\377\377\377\377\250\272\307\244\177\230\254\244?^y\244\216\377\377"
+ "\377\0\6v\217\243\211\263\302\316\211\377\377\377\377\250\272\307\211\177"
+ "\230\254\211?^y\211\216\377\377\377\0\6v\217\243l\263\302\316l\377\377\377"
+ "\377\250\272\307l\177\230\254l?^yl\216\377\377\377\0\6v\217\243M\263\302"
+ "\316M\377\377\377\377\250\272\307M\177\230\254M?^yM\216\377\377\377\0\6v"
+ "\217\243,\263\302\316,\377\377\377\377\250\272\307,\177\230\254,?^y,\207"
+ "\377\377\377\0",
+};
+
diff --git a/src/image_data/rj45_unused.h b/src/image_data/rj45_unused.h new file mode 100644 index 0000000..cb08fe6 --- /dev/null +++ b/src/image_data/rj45_unused.h @@ -0,0 +1,21 @@ +/* GIMP RGBA C-Source image dump 1-byte-run-length-encoded (rj45_unused2.c) */ + +#include "image.h" + +static const nv_image_t rj45_unused = { + 20, 28, 4, + "\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" + "66\200\204\0\0\0\0\1""666\200\204\0\0\0\0\2""666\200\0\0\0\0\202666\200\1" + "\0\0\0\0\206666\200\204\0\0\0\0\206666\200\1\0\0\0\0\202666\200\202\0\0\0" + "\0\1""666\200\214\0\0\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1" + """666\200\214\0\0\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1""6" + "66\200\214\0\0\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1""666\200" + "\214\0\0\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1""666\200\214" + "\0\0\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1""666\200\214\0\0" + "\0\0\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\1""666\200\214\0\0\0\0" + "\1""666\200\202\0\0\0\0\202666\200\202\0\0\0\0\216666\200\202\0\0\0\0\202" + "666\200\222\0\0\0\0\225666\200\377\0\0\0\0\347\0\0\0\0\1\250\272\307,\211" + "\0\0\0\0", +}; diff --git a/src/libXNVCtrl/NVCtrl.c b/src/libXNVCtrl/NVCtrl.c index 0eec6bb..38fa737 100644 --- a/src/libXNVCtrl/NVCtrl.c +++ b/src/libXNVCtrl/NVCtrl.c @@ -130,9 +130,41 @@ Bool XNVCTRLIsNvScreen ( } -void XNVCTRLSetAttribute ( +Bool XNVCTRLQueryTargetCount ( Display *dpy, - int screen, + int target_type, + int *value +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryTargetCountReply rep; + xnvCtrlQueryTargetCountReq *req; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlQueryTargetCount, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryTargetCount; + req->target_type = target_type; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + if (value) *value = rep.count; + UnlockDisplay (dpy); + SyncHandle (); + return True; +} + + +void XNVCTRLSetTargetAttribute ( + Display *dpy, + int target_type, + int target_id, unsigned int display_mask, unsigned int attribute, int value @@ -146,7 +178,8 @@ void XNVCTRLSetAttribute ( GetReq (nvCtrlSetAttribute, req); req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlSetAttribute; - req->screen = screen; + req->target_type = target_type; + req->target_id = target_id; req->display_mask = display_mask; req->attribute = attribute; req->value = value; @@ -154,6 +187,18 @@ void XNVCTRLSetAttribute ( SyncHandle (); } +void XNVCTRLSetAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int value +){ + XNVCTRLSetTargetAttribute (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, + display_mask, attribute, value); +} + + Bool XNVCTRLSetAttributeAndGetStatus ( Display *dpy, int screen, @@ -193,9 +238,10 @@ Bool XNVCTRLSetAttributeAndGetStatus ( -Bool XNVCTRLQueryAttribute ( +Bool XNVCTRLQueryTargetAttribute ( Display *dpy, - int screen, + int target_type, + int target_id, unsigned int display_mask, unsigned int attribute, int *value @@ -214,7 +260,8 @@ Bool XNVCTRLQueryAttribute ( GetReq (nvCtrlQueryAttribute, req); req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlQueryAttribute; - req->screen = screen; + req->target_type = target_type; + req->target_id = target_id; req->display_mask = display_mask; req->attribute = attribute; if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { @@ -229,12 +276,24 @@ Bool XNVCTRLQueryAttribute ( return exists; } - -Bool XNVCTRLQueryStringAttribute ( +Bool XNVCTRLQueryAttribute ( Display *dpy, int screen, unsigned int display_mask, unsigned int attribute, + int *value +){ + return XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, attribute, value); +} + + +Bool XNVCTRLQueryTargetStringAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, char **ptr ){ XExtDisplayInfo *info = find_display (dpy); @@ -254,7 +313,8 @@ Bool XNVCTRLQueryStringAttribute ( GetReq (nvCtrlQueryStringAttribute, req); req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlQueryStringAttribute; - req->screen = screen; + req->target_type = target_type; + req->target_id = target_id; req->display_mask = display_mask; req->attribute = attribute; if (!_XReply (dpy, (xReply *) &rep, 0, False)) { @@ -281,6 +341,18 @@ Bool XNVCTRLQueryStringAttribute ( return exists; } +Bool XNVCTRLQueryStringAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + char **ptr +){ + return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, ptr); +} + Bool XNVCTRLSetStringAttribute ( Display *dpy, @@ -326,9 +398,10 @@ Bool XNVCTRLSetStringAttribute ( } -Bool XNVCTRLQueryValidAttributeValues ( +Bool XNVCTRLQueryValidTargetAttributeValues ( Display *dpy, - int screen, + int target_type, + int target_id, unsigned int display_mask, unsigned int attribute, NVCTRLAttributeValidValuesRec *values @@ -349,7 +422,8 @@ Bool XNVCTRLQueryValidAttributeValues ( GetReq (nvCtrlQueryValidAttributeValues, req); req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlQueryValidAttributeValues; - req->screen = screen; + req->target_type = target_type; + req->target_id = target_id; req->display_mask = display_mask; req->attribute = attribute; if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { @@ -372,13 +446,26 @@ Bool XNVCTRLQueryValidAttributeValues ( return exists; } +Bool XNVCTRLQueryValidAttributeValues ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + return XNVCTRLQueryValidTargetAttributeValues(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, values); +} void XNVCTRLSetGvoColorConversion ( Display *dpy, int screen, float colorMatrix[3][3], - float colorOffset[3] + float colorOffset[3], + float colorScale[3] ){ XExtDisplayInfo *info = find_display (dpy); xnvCtrlSetGvoColorConversionReq *req; @@ -390,18 +477,27 @@ void XNVCTRLSetGvoColorConversion ( req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlSetGvoColorConversion; req->screen = screen; - req->row1_col1 = colorMatrix[0][0]; - req->row1_col2 = colorMatrix[0][1]; - req->row1_col3 = colorMatrix[0][2]; - req->row1_col4 = colorOffset[0]; - req->row2_col1 = colorMatrix[1][0]; - req->row2_col2 = colorMatrix[1][1]; - req->row2_col3 = colorMatrix[1][2]; - req->row2_col4 = colorOffset[1]; - req->row3_col1 = colorMatrix[2][0]; - req->row3_col2 = colorMatrix[2][1]; - req->row3_col3 = colorMatrix[2][2]; - req->row3_col4 = colorOffset[2]; + + req->cscMatrix_y_r = colorMatrix[0][0]; + req->cscMatrix_y_g = colorMatrix[0][1]; + req->cscMatrix_y_b = colorMatrix[0][2]; + + req->cscMatrix_cr_r = colorMatrix[1][0]; + req->cscMatrix_cr_g = colorMatrix[1][1]; + req->cscMatrix_cr_b = colorMatrix[1][2]; + + req->cscMatrix_cb_r = colorMatrix[2][0]; + req->cscMatrix_cb_g = colorMatrix[2][1]; + req->cscMatrix_cb_b = colorMatrix[2][2]; + + req->cscOffset_y = colorOffset[0]; + req->cscOffset_cr = colorOffset[1]; + req->cscOffset_cb = colorOffset[2]; + + req->cscScale_y = colorScale[0]; + req->cscScale_cr = colorScale[1]; + req->cscScale_cb = colorScale[2]; + UnlockDisplay (dpy); SyncHandle (); } @@ -411,13 +507,13 @@ Bool XNVCTRLQueryGvoColorConversion ( Display *dpy, int screen, float colorMatrix[3][3], - float colorOffset[3] + float colorOffset[3], + float colorScale[3] ){ XExtDisplayInfo *info = find_display (dpy); xnvCtrlQueryGvoColorConversionReply rep; xnvCtrlQueryGvoColorConversionReq *req; - float buf[3][4]; - + if(!XextHasExtension(info)) return False; @@ -436,21 +532,9 @@ Bool XNVCTRLQueryGvoColorConversion ( return False; } - _XRead(dpy, (char *)(&buf), 48); - - colorMatrix[0][0] = buf[0][0]; - colorMatrix[0][1] = buf[0][1]; - colorMatrix[0][2] = buf[0][2]; - colorMatrix[1][0] = buf[1][0]; - colorMatrix[1][1] = buf[1][1]; - colorMatrix[1][2] = buf[1][2]; - colorMatrix[2][0] = buf[2][0]; - colorMatrix[2][1] = buf[2][1]; - colorMatrix[2][2] = buf[2][2]; - - colorOffset[0] = buf[0][3]; - colorOffset[1] = buf[1][3]; - colorOffset[2] = buf[2][3]; + _XRead(dpy, (char *)(colorMatrix), 36); + _XRead(dpy, (char *)(colorOffset), 12); + _XRead(dpy, (char *)(colorScale), 12); UnlockDisplay (dpy); SyncHandle (); @@ -459,6 +543,36 @@ Bool XNVCTRLQueryGvoColorConversion ( } +Bool XNVCtrlSelectTargetNotify ( + Display *dpy, + int target_type, + int target_id, + int notify_type, + Bool onoff +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSelectTargetNotifyReq *req; + + if(!XextHasExtension (info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlSelectTargetNotify, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSelectTargetNotify; + req->target_type = target_type; + req->target_id = target_id; + req->notifyType = notify_type; + req->onoff = onoff; + UnlockDisplay (dpy); + SyncHandle (); + + return True; +} + + Bool XNVCtrlSelectNotify ( Display *dpy, int screen, @@ -860,7 +974,6 @@ Bool NVCTRLQueryDDCCICapabilities ( int length, numbytes, slop; char *ptr, *p; int len1, len2, len3, len4, len5; - int step; *nvctrl_vcp_supported=*nvctrl_vcp_possible_values=*possible_values_offset=*possible_values_size=*nvctrl_string_vcp_supported=NULL; @@ -974,9 +1087,10 @@ Bool XNVCTRLQueryDDCCITimingReport ( return exists; } -Bool XNVCTRLQueryBinaryData ( +Bool XNVCTRLQueryTargetBinaryData ( Display *dpy, - int screen, + int target_type, + int target_id, unsigned int display_mask, unsigned int attribute, unsigned char **ptr, @@ -999,7 +1113,8 @@ Bool XNVCTRLQueryBinaryData ( GetReq (nvCtrlQueryBinaryData, req); req->reqType = info->codes->major_opcode; req->nvReqType = X_nvCtrlQueryBinaryData; - req->screen = screen; + req->target_type = target_type; + req->target_id = target_id; req->display_mask = display_mask; req->attribute = attribute; if (!_XReply (dpy, (xReply *) &rep, 0, False)) { @@ -1027,16 +1142,34 @@ Bool XNVCTRLQueryBinaryData ( return exists; } +Bool XNVCTRLQueryBinaryData ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len +){ + return XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, ptr, len); +} + + static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire) { XExtDisplayInfo *info = find_display (dpy); - XNVCtrlEvent *re = (XNVCtrlEvent *) host; - xnvctrlEvent *event = (xnvctrlEvent *) wire; + XNVCtrlEvent *re; + xnvctrlEvent *event; + XNVCtrlEventTarget *reTarget; + xnvctrlEventTarget *eventTarget; XNVCTRLCheckExtension (dpy, info, False); - switch ((event->u.u.type & 0x7F) - info->codes->first_event) { + switch ((wire->u.u.type & 0x7F) - info->codes->first_event) { case ATTRIBUTE_CHANGED_EVENT: + re = (XNVCtrlEvent *) host; + event = (xnvctrlEvent *) wire; re->attribute_changed.type = event->u.u.type & 0x7F; re->attribute_changed.serial = _XSetLastRequestRead(dpy, (xGenericReply*) event); @@ -1049,6 +1182,28 @@ static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire) re->attribute_changed.attribute = event->u.attribute_changed.attribute; re->attribute_changed.value = event->u.attribute_changed.value; break; + case TARGET_ATTRIBUTE_CHANGED_EVENT: + reTarget = (XNVCtrlEventTarget *) host; + eventTarget = (xnvctrlEventTarget *) wire; + reTarget->attribute_changed.type = eventTarget->u.u.type & 0x7F; + reTarget->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget); + reTarget->attribute_changed.send_event = + ((eventTarget->u.u.type & 0x80) != 0); + reTarget->attribute_changed.display = dpy; + reTarget->attribute_changed.time = + eventTarget->u.attribute_changed.time; + reTarget->attribute_changed.target_type = + eventTarget->u.attribute_changed.target_type; + reTarget->attribute_changed.target_id = + eventTarget->u.attribute_changed.target_id; + reTarget->attribute_changed.display_mask = + eventTarget->u.attribute_changed.display_mask; + reTarget->attribute_changed.attribute = + eventTarget->u.attribute_changed.attribute; + reTarget->attribute_changed.value = + eventTarget->u.attribute_changed.value; + break; default: return False; } diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h index 1cb1d67..716673b 100644 --- a/src/libXNVCtrl/NVCtrl.h +++ b/src/libXNVCtrl/NVCtrl.h @@ -1,14 +1,36 @@ #ifndef __NVCTRL_H #define __NVCTRL_H + /**************************************************************************/ + /* - * Integer attributes; these are settable/gettable via - * XNVCTRLSetAttribute() and XNVCTRLQueryAttribute, respectively. + * Attribute Targets + * + * Targets define attribute groups. For example, some attributes are only + * valid to set on a GPU, others are only valid when talking about an + * X Screen. Target types are then what is used to identify the target + * group of the attribute you wish to set/query. + * + * Here are the supported target types: + */ + +#define NV_CTRL_TARGET_TYPE_X_SCREEN 0 +#define NV_CTRL_TARGET_TYPE_GPU 1 +#define NV_CTRL_TARGET_TYPE_FRAMELOCK 2 + + +/**************************************************************************/ + +/* + * Attributes + * * Some attributes may only be read; some may require a display_mask - * argument. This information is encoded in the "permission" comment - * after each attribute #define, and can be queried at run time with - * XNVCTRLQueryValidAttributeValues(). + * argument and others may be valid only for specific target types. + * This information is encoded in the "permission" comment after each + * attribute #define, and can be queried at run time with + * XNVCTRLQueryValidAttributeValues() and/or + * XNVCTRLQueryValidTargetAttributeValues() * * Key to Integer Attribute "Permissions": * @@ -27,11 +49,37 @@ * should be used as the display_mask when dealing with attributes * designated with "D" below. For attributes that do not require the * display mask, the argument is ignored. + * + * G: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GPU + * target type via XNVCTRLQueryTargetAttribute(). + * + * F: The attribute may be queried using an NV_CTRL_TARGET_TYPE_FRAMELOCK + * target type via XNVCTRLQueryTargetAttribute(). + * + * NOTE: Unless mentioned otherwise, all attributes may be queried using + * an NV_CTRL_TARGET_TYPE_X_SCREEN target type via + * XNVCTRLQueryTargetAttribute(). */ /**************************************************************************/ +/* + * Integer attributes: + * + * Integer attributes can be queried through the XNVCTRLQueryAttribute() and + * XNVCTRLQueryTargetAttribute() function calls. + * + * Integer attributes can be set through the XNVCTRLSetAttribute() and + * XNVCTRLSetTargetAttribute() function calls. + * + * Unless otherwise noted, all integer attributes can be queried/set + * using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot + * take an NV_CTRL_TARGET_TYPE_X_SCREEN also cannot be queried/set through + * XNVCTRLQueryAttribute()/XNVCTRLSetAttribute() (Since these assume + * an X Screen target). + */ + /* * NV_CTRL_FLATPANEL_SCALING - the current flatpanel scaling state; @@ -233,136 +281,191 @@ /* - * NV_CTRL_CONNECTED_DISPLAYS - returns a display mask indicating what - * display devices are connected to the GPU driving the specified X - * screen. + * NV_CTRL_CONNECTED_DISPLAYS - returns a display mask indicating the last + * cached state of the display devices connected to the GPU or GPU driving + * the specified X screen. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_CONNECTED_DISPLAYS 19 /* R-- */ +#define NV_CTRL_CONNECTED_DISPLAYS 19 /* R--G */ /* * NV_CTRL_ENABLED_DISPLAYS - returns a display mask indicating what - * display devices are enabled for use on the specified X screen. + * display devices are enabled for use on the specified X screen or + * GPU. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_ENABLED_DISPLAYS 20 /* R-- */ +#define NV_CTRL_ENABLED_DISPLAYS 20 /* R--G */ /**************************************************************************/ /* - * Integer attributes specific to configuring FrameLock on boards that + * Integer attributes specific to configuring Frame Lock on boards that * support it. */ /* - * NV_CTRL_FRAMELOCK - returns whether this X screen supports - * FrameLock. All of the other FrameLock attributes are only + * NV_CTRL_FRAMELOCK - returns whether the underlying GPU supports + * Frame Lock. All of the other frame lock attributes are only * applicable if NV_CTRL_FRAMELOCK is _SUPPORTED. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_FRAMELOCK 21 /* R-- */ +#define NV_CTRL_FRAMELOCK 21 /* R--G */ #define NV_CTRL_FRAMELOCK_NOT_SUPPORTED 0 #define NV_CTRL_FRAMELOCK_SUPPORTED 1 /* - * NV_CTRL_FRAMELOCK_MASTER - get/set whether this X screen is the - * FrameLock master for the entire sync group. Note that only one - * node in the sync group should be configured as the master. + * NV_CTRL_FRAMELOCK_MASTER - get/set which display device to use + * as the frame lock master for the entire sync group. Note that only + * one node in the sync group should be configured as the master. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. */ -#define NV_CTRL_FRAMELOCK_MASTER 22 /* RW- */ +#define NV_CTRL_FRAMELOCK_MASTER 22 /* RW-G */ + +/* These are deprecated. NV_CTRL_FRAMELOCK_MASTER now takes and + returns a display mask as value. */ #define NV_CTRL_FRAMELOCK_MASTER_FALSE 0 #define NV_CTRL_FRAMELOCK_MASTER_TRUE 1 /* * NV_CTRL_FRAMELOCK_POLARITY - sync either to the rising edge of the - * framelock pulse, or both the rising and falling edges of the - * framelock pulse. + * frame lock pulse, the falling edge of the frame lock pulse or both. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_POLARITY 23 /* RW- */ +#define NV_CTRL_FRAMELOCK_POLARITY 23 /* RW-F */ #define NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE 0x1 #define NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE 0x2 #define NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES 0x3 /* - * NV_CTRL_FRAMELOCK_SYNC_DELAY - delay between the framelock pulse + * NV_CTRL_FRAMELOCK_SYNC_DELAY - delay between the frame lock pulse * and the GPU sync. This is an 11 bit value which is multipled by * 7.81 to determine the sync delay in microseconds. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_SYNC_DELAY 24 /* RW- */ +#define NV_CTRL_FRAMELOCK_SYNC_DELAY 24 /* RW-F */ #define NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX 2047 #define NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR 7.81 + /* * NV_CTRL_FRAMELOCK_SYNC_INTERVAL - how many house sync pulses - * between the FrameLock sync generation (0 == sync every house sync); + * between the frame lock sync generation (0 == sync every house sync); * this only applies to the master when receiving house sync. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_SYNC_INTERVAL 25 /* RW- */ +#define NV_CTRL_FRAMELOCK_SYNC_INTERVAL 25 /* RW-F */ /* * NV_CTRL_FRAMELOCK_PORT0_STATUS - status of the rj45 port0. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_PORT0_STATUS 26 /* R-- */ +#define NV_CTRL_FRAMELOCK_PORT0_STATUS 26 /* R--F */ #define NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT 0 #define NV_CTRL_FRAMELOCK_PORT0_STATUS_OUTPUT 1 /* * NV_CTRL_FRAMELOCK_PORT1_STATUS - status of the rj45 port1. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_PORT1_STATUS 27 /* R-- */ +#define NV_CTRL_FRAMELOCK_PORT1_STATUS 27 /* R--F */ #define NV_CTRL_FRAMELOCK_PORT1_STATUS_INPUT 0 #define NV_CTRL_FRAMELOCK_PORT1_STATUS_OUTPUT 1 /* - * NV_CTRL_FRAMELOCK_HOUSE_STATUS - status of the house input (the BNC - * connector). + * NV_CTRL_FRAMELOCK_HOUSE_STATUS - returns whether or not the house + * sync signal was detected on the BNC connector of the frame lock + * board. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_HOUSE_STATUS 28 /* R-- */ +#define NV_CTRL_FRAMELOCK_HOUSE_STATUS 28 /* R--F */ #define NV_CTRL_FRAMELOCK_HOUSE_STATUS_NOT_DETECTED 0 #define NV_CTRL_FRAMELOCK_HOUSE_STATUS_DETECTED 1 /* - * NV_CTRL_FRAMELOCK_SYNC - enable/disable the syncing of the - * specified display devices to the FrameLock pulse. + * NV_CTRL_FRAMELOCK_SYNC - enable/disable the syncing of display + * devices to the frame lock pulse as specified by previous calls to + * NV_CTRL_FRAMELOCK_MASTER and NV_CTRL_FRAMELOCK_SLAVES. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. */ -#define NV_CTRL_FRAMELOCK_SYNC 29 /* RWD */ +#define NV_CTRL_FRAMELOCK_SYNC 29 /* RW-G */ #define NV_CTRL_FRAMELOCK_SYNC_DISABLE 0 #define NV_CTRL_FRAMELOCK_SYNC_ENABLE 1 /* - * NV_CTRL_FRAMELOCK_SYNC_READY - reports whether a slave FrameLock + * NV_CTRL_FRAMELOCK_SYNC_READY - reports whether a slave frame lock * board is receiving sync (regardless of whether or not any display * devices are using the sync). + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_SYNC_READY 30 /* R-- */ +#define NV_CTRL_FRAMELOCK_SYNC_READY 30 /* R--F */ #define NV_CTRL_FRAMELOCK_SYNC_READY_FALSE 0 #define NV_CTRL_FRAMELOCK_SYNC_READY_TRUE 1 /* * NV_CTRL_FRAMELOCK_STEREO_SYNC - this indicates that the GPU stereo - * signal is in sync with the framelock stereo signal. + * signal is in sync with the frame lock stereo signal. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_STEREO_SYNC 31 /* R-- */ +#define NV_CTRL_FRAMELOCK_STEREO_SYNC 31 /* R--G */ #define NV_CTRL_FRAMELOCK_STEREO_SYNC_FALSE 0 #define NV_CTRL_FRAMELOCK_STEREO_SYNC_TRUE 1 @@ -378,16 +481,19 @@ * returned by the glXQueryFrameCountNV() function in the * GLX_NV_swap_group extension). Note: for best accuracy of the * Universal Frame Count, it is recommended to toggle the TEST_SIGNAL - * on and off after enabling FrameLock. + * on and off after enabling frame lock. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_FRAMELOCK_TEST_SIGNAL 32 /* RW- */ +#define NV_CTRL_FRAMELOCK_TEST_SIGNAL 32 /* RW-G */ #define NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE 0 #define NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE 1 /* - * NV_CTRL_FRAMELOCK_ETHERNET_DETECTED - The FrameLock boards are + * NV_CTRL_FRAMELOCK_ETHERNET_DETECTED - The frame lock boards are * cabled together using regular cat5 cable, connecting to rj45 ports * on the backplane of the card. There is some concern that users may * think these are ethernet ports and connect them to a @@ -395,22 +501,31 @@ * prevent damage (either to itself or to the router). * NV_CTRL_FRAMELOCK_ETHERNET_DETECTED may be called to find out if * ethernet is connected to one of the rj45 ports. An appropriate - * error message should then be displayed. The _PORT0 and PORT1 + * error message should then be displayed. The _PORT0 and _PORT1 * values may be or'ed together. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED 33 /* R-- */ +#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED 33 /* R--F */ #define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_NONE 0 #define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT0 0x1 #define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT1 0x2 /* - * NV_CTRL_FRAMELOCK_VIDEO_MODE - get/set the video mode of the house - * input. + * NV_CTRL_FRAMELOCK_VIDEO_MODE - get/set what video mode is used + * to interperate the house sync signal. This should only be set + * on the master. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_VIDEO_MODE 34 /* RW- */ +#define NV_CTRL_FRAMELOCK_VIDEO_MODE 34 /* RW-F */ #define NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE 0 #define NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL 1 #define NV_CTRL_FRAMELOCK_VIDEO_MODE_NTSCPALSECAM 2 @@ -429,10 +544,14 @@ /* * NV_CTRL_FRAMELOCK_SYNC_RATE - this is the refresh rate that the - * framelock board is sending to the GPU, in milliHz. + * frame lock board is sending to the GPU, in milliHz. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_FRAMELOCK_SYNC_RATE 35 /* R-- */ +#define NV_CTRL_FRAMELOCK_SYNC_RATE 35 /* R--F */ @@ -467,11 +586,17 @@ /* - * NV_CTRL_FRAMELOCK_TIMING - this is TRUE when the framelock board is - * receiving timing input. + * NV_CTRL_FRAMELOCK_TIMING - this is TRUE when the gpu is both receiving + * and locked to an input timing signal. Timing information may come from + * the following places: Another frame lock device that is set to master, + * the house sync signal, or the GPU's internal timing from a display + * device. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_FRAMELOCK_TIMING 39 /* RW- */ +#define NV_CTRL_FRAMELOCK_TIMING 39 /* R--G */ #define NV_CTRL_FRAMELOCK_TIMING_FALSE 0 #define NV_CTRL_FRAMELOCK_TIMING_TRUE 1 @@ -702,6 +827,9 @@ * * - specify the NV_CTRL_GVO_DATA_FORMAT * + * - specify any custom Color Space Conversion (CSC) matrix, offset, + * and scale with XNVCTRLSetGvoColorConversion(). + * * - if using the GLX_NV_video_out extension to display one or more * pbuffers, call glXGetVideoDeviceNV() to lock the GVO output for use * by the GLX client; then bind the pbuffer(s) to the GVO output with @@ -750,8 +878,8 @@ * genlocking locks at hsync. This requires that the output video * format exactly match the incoming sync video format. * - * FRAMELOCK - the GVO output is framelocked to an incoming sync - * signal; framelocking locks at vsync. This requires that the output + * FRAMELOCK - the GVO output is frame locked to an incoming sync + * signal; frame locking locks at vsync. This requires that the output * video format have the same refresh rate as the incoming sync video * format. */ @@ -780,6 +908,15 @@ * format. Note that the valid video formats will vary depending on * the NV_CTRL_GVO_SYNC_MODE and the incoming sync video format. See * the definition of NV_CTRL_GVO_SYNC_MODE. + * + * Note that when querying the ValidValues for this data type, the + * values are reported as bits within a bitmask + * (ATTRIBUTE_TYPE_INT_BITS); unfortunately, there are more valid + * value bits than will fit in a single 32-bit value. To solve this, + * query the ValidValues for NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT to check + * which of the first 31 VIDEO_FORMATS are valid, then query the + * ValidValues for NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 to check which of + * the VIDEO_FORMATS with value 32 and higher are valid. */ #define NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT 70 /* RW- */ @@ -815,7 +952,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 /* * NV_CTRL_GVO_INPUT_VIDEO_FORMAT - indicates the input video format @@ -850,6 +996,8 @@ #define NV_CTRL_GVO_DATA_FORMAT_DUAL_Y8CR8CB8_TO_DUAL_YCRCB422 14 #define NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB422 15 #define NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB444 16 +#define NV_CTRL_GVO_DATA_FORMAT_Y12CR12CB12_TO_YCRCB444 17 +#define NV_CTRL_GVO_DATA_FORMAT_R12G12B12_TO_YCRCB444 18 /* @@ -916,7 +1064,8 @@ /* * NV_CTRL_GVO_FPGA_VERSION - indicates the version of the Firmware on - * the GVO device. XXX would this be better as a string attribute? + * the GVO device. Deprecated; use + * NV_CTRL_STRING_GVO_FIRMWARE_VERSION instead. */ #define NV_CTRL_GVO_FIRMWARE_VERSION 78 /* R-- */ @@ -944,7 +1093,7 @@ * NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE - must be set for a period * of about 2 seconds for the new InputVideoFormat to be properly * locked to. In nvidia-settings, we do a reacquire whenever genlock - * or framelock mode is entered into, when the user clicks the + * or frame lock mode is entered into, when the user clicks the * "detect" button. This value can be written, but always reads back * _FALSE. */ @@ -979,7 +1128,7 @@ * * XNVCTRLQueryAttribute (dpy, * screen, - * NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC + * NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC, * NV_CTRL_GVO_VIDEO_FORMAT_WIDTH, * &value); * @@ -1005,14 +1154,6 @@ /* - * XXX Still to do: GVO Color Conversion - */ - -/* - * XXX what sync error attributes do we need to expose? - */ - -/* * NV_CTRL_GPU_OVERCLOCKING_STATE - query the current or set a new * overclocking state; the value of this attribute controls the * availability of additional overclocking attributes (see below). @@ -2316,7 +2457,7 @@ * This attribute is only available for flatpanels. */ -#define NV_CTRL_FLATPANEL_CHIP_LOCATION 215/* R-D */ +#define NV_CTRL_FLATPANEL_CHIP_LOCATION 215/* R-DG */ #define NV_CTRL_FLATPANEL_CHIP_LOCATION_INTERNAL 0 #define NV_CTRL_FLATPANEL_CHIP_LOCATION_EXTERNAL 1 @@ -2326,7 +2467,7 @@ * This attribute is only available for flatpanels. */ -#define NV_CTRL_FLATPANEL_LINK 216/* R-D */ +#define NV_CTRL_FLATPANEL_LINK 216/* R-DG */ #define NV_CTRL_FLATPANEL_LINK_SINGLE 0 #define NV_CTRL_FLATPANEL_LINK_DUAL 1 @@ -2336,27 +2477,37 @@ * attribute is only available for flatpanels. */ -#define NV_CTRL_FLATPANEL_SIGNAL 217/* R-D */ +#define NV_CTRL_FLATPANEL_SIGNAL 217/* R-DG */ #define NV_CTRL_FLATPANEL_SIGNAL_LVDS 0 #define NV_CTRL_FLATPANEL_SIGNAL_TMDS 1 /* - * NV_CTRL_USE_HOUSE_SYNC - when TRUE, framelock will sync to the house - * sync + * NV_CTRL_USE_HOUSE_SYNC - when TRUE, the server (master) frame lock + * device will propagate the incoming house sync signal as the outgoing + * frame lock sync signal. If the frame lock device cannot detect a + * frame lock sync signal, it will default to using the internal timings + * from the GPU connected to the primary connector. * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_USE_HOUSE_SYNC 218/* RW- */ +#define NV_CTRL_USE_HOUSE_SYNC 218/* RW-F */ #define NV_CTRL_USE_HOUSE_SYNC_FALSE 0 #define NV_CTRL_USE_HOUSE_SYNC_TRUE 1 /* * NV_CTRL_EDID_AVAILABLE - report if an EDID is available for the * specified display device. + * + * This attribute may also be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. */ -#define NV_CTRL_EDID_AVAILABLE 219 /* R-D */ +#define NV_CTRL_EDID_AVAILABLE 219 /* R-DG */ #define NV_CTRL_EDID_AVAILABLE_FALSE 0 #define NV_CTRL_EDID_AVAILABLE_TRUE 1 @@ -2407,7 +2558,6 @@ #define NV_CTRL_XINERAMA_STEREO_FALSE 0 #define NV_CTRL_XINERAMA_STEREO_TRUE 1 - /* * NV_CTRL_BUS_RATE - if the bus type of the GPU driving the specified * screen is AGP, then NV_CTRL_BUS_RATE returns the configured AGP @@ -2434,24 +2584,150 @@ #define NV_CTRL_XV_SYNC_TO_DISPLAY 226 /* RW- */ +/* + * NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 - this attribute is only intended + * to be used to query the ValidValues for + * NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT above the first 31 VIDEO_FORMATS. + * See NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT for details. + */ -/**************************************************************************/ -#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_XV_SYNC_TO_DISPLAY +#define NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 227 /* --- */ -/**************************************************************************/ +/* + * Override the SDI hardware's Color Space Conversion with the values + * controlled through XNVCTRLSetGvoColorConversion() and + * XNVCTRLGetGvoColorConversion(). If this attribute is FALSE, then + * the values specified through XNVCTRLSetGvoColorConversion() are + * ignored. + */ + +#define NV_CTRL_GVO_OVERRIDE_HW_CSC 228 /* RW- */ +#define NV_CTRL_GVO_OVERRIDE_HW_CSC_FALSE 0 +#define NV_CTRL_GVO_OVERRIDE_HW_CSC_TRUE 1 /* + * NV_CTRL_GVO_CAPABILITIES - this read-only attribute describes GVO + * capabilities that differ between NVIDIA SDI products. This value + * is a bitmask where each bit indicates whether that capability is + * available. + * + * APPLY_CSC_IMMEDIATELY - whether the CSC matrix, offset, and scale + * specified through XNVCTRLSetGvoColorConversion() will take affect + * immediately, or only after SDI output is disabled and enabled + * again. * + * APPLY_CSC_TO_X_SCREEN - whether the CSC matrix, offset, and scale + * specified through XNVCTRLSetGvoColorConversion() will also apply + * to GVO output of an X screen, or only to OpenGL GVO output, as + * enabled through the GLX_NV_video_out extension. + */ + +#define NV_CTRL_GVO_CAPABILITIES 229 /* R-- */ +#define NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_IMMEDIATELY 0x1 +#define NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_TO_X_SCREEN 0x2 + + +/* + * NV_CTRL_GVO_COMPOSITE_TERMINATION - enable or disable 75 ohm + * termination of the SDI composite input signal. + */ + +#define NV_CTRL_GVO_COMPOSITE_TERMINATION 230 /* RW- */ +#define NV_CTRL_GVO_COMPOSITE_TERMINATION_ENABLE 1 +#define NV_CTRL_GVO_COMPOSITE_TERMINATION_DISABLE 0 + + +/* + * NV_CTRL_ASSOCIATED_DISPLAY_DEVICES - display device mask indicating + * which display devices are "associated" with the specified X screen + * (ie: are available to the X screen for displaying the X screen). + */ + +#define NV_CTRL_ASSOCIATED_DISPLAY_DEVICES 231 /* RW- */ + +/* + * NV_CTRL_FRAMELOCK_SLAVES - get/set whether the display device(s) + * given should listen or ignore the master's sync signal. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_SLAVES 232 /* RW-G */ + +/* + * NV_CTRL_FRAMELOCK_MASTERABLE - Can this Display Device be set + * as the master of the frame lock group. Returns MASTERABLE_TRUE if + * the GPU driving the display device is connected to the "primary" + * connector on the frame lock board. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_MASTERABLE 233 /* R-DG */ +#define NV_CTRL_FRAMELOCK_MASTERABLE_FALSE 0 +#define NV_CTRL_FRAMELOCK_MASTERABLE_TRUE 1 + + +/* + * NV_CTRL_PROBE_DISPLAYS - re-probes the hardware to detect what + * display devices are connected to the GPU or GPU driving the + * specified X screen. Returns a display mask. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_PROBE_DISPLAYS 234 /* R--G */ + + +/* + * NV_CTRL_REFRESH_RATE - Returns the refresh rate of the specified + * display device in 100 * Hz (ie. to get the refresh rate in Hz, divide + * the returned value by 100.) + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_REFRESH_RATE 235 /* R-DG */ + +#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_REFRESH_RATE + + +/**************************************************************************/ + +/* * String Attributes: + * + * String attributes can be queryied through the XNVCTRLQueryStringAttribute() + * and XNVCTRLQueryTargetStringAttribute() function calls. + * + * String attributes can be set through the XNVCTRLSetStringAttribute() + * function call. (There are currently no string attributes that can be + * set on non-X Screen targets.) + * + * Unless otherwise noted, all string attributes can be queried/set using an + * NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take an + * NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried/set through + * XNVCTRLQueryStringAttribute()/XNVCTRLSetStringAttribute() (Since + * these assume an X Screen target). */ + /* * NV_CTRL_STRING_PRODUCT_NAME - the GPU product name on which the * specified X screen is running. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_STRING_PRODUCT_NAME 0 /* R-- */ +#define NV_CTRL_STRING_PRODUCT_NAME 0 /* R--G */ /* @@ -2473,9 +2749,12 @@ /* * NV_CTRL_STRING_DISPLAY_DEVICE_NAME - name of the display device * specified in the display_mask argument. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_STRING_DISPLAY_DEVICE_NAME 4 /* R-D */ +#define NV_CTRL_STRING_DISPLAY_DEVICE_NAME 4 /* R-DG */ /* @@ -2494,6 +2773,7 @@ * length, the descriptor shall be truncated with the excess bytes * being discarded. */ + #define NV_CTRL_STRING_DDCCI_MISC_TRANSMIT_DISPLAY_DESCRIPTOR 6 /* RWD */ @@ -2508,22 +2788,184 @@ * moving to right along each line and then starting at left end of the * next line. */ + #define NV_CTRL_STRING_DDCCI_MISC_AUXILIARY_DISPLAY_DATA 7 /* -WD */ -#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_DDCCI_MISC_AUXILIARY_DISPLAY_DATA +#define NV_CTRL_STRING_GVO_FIRMWARE_VERSION 8 /* R-- */ + + +/* + * 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. + */ + +#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. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_ADD_MODELINE 10 /* -WDG */ + + +/* + * NV_CTRL_STRING_DELETE_MODLEINE - 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.) + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_DELETE_MODELINE 11 /* -WDG */ + + +/* + * NV_CTRL_STRING_CURRENT_METAMODE - Returns the metamode currently + * being used by the specified X screen. + */ + +#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) + * + * TwinView must be enabled on the X Screen/GPU to access this attribute. + */ + +#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. + */ + +#define NV_CTRL_STRING_DELETE_METAMODE 14 /* -WD-- */ + +#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_DELETE_METAMODE /**************************************************************************/ /* * Binary Data Attributes: + * + * Binary data attributes can be queryied through the XNVCTRLQueryBinaryData() + * and XNVCTRLQueryTargetBinaryData() function calls. + * + * There are currently no binary data attributes that can be set. + * + * Unless otherwise noted, all Binary data attributes can be queried + * using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take + * an NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried through + * XNVCTRLQueryBinaryData() (Since an X Screen target is assumed). + */ + + +/* + * NV_CTRL_BINARY_DATA_EDID - Returns a display device's EDID information + * data. + * + * This attribute may be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. */ -#define NV_CTRL_BINARY_DATA_EDID 0 /* R-D */ +#define NV_CTRL_BINARY_DATA_EDID 0 /* R-DG */ + + +/* + * 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: + * + * "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. + */ + +#define NV_CTRL_BINARY_DATA_MODELINES 1 /* R-DG */ + + +/* + * 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: + * + * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" + */ + +#define NV_CTRL_BINARY_DATA_METAMODES 2 /* R-D- */ + + +/* + * NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU - Returns the list of X + * screens currently driven by the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of screens + * 4 * n CARD32 screen indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#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. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + */ + +#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. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK 5 /* R-DF */ + +#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE \ + NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK -#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE NV_CTRL_BINARY_DATA_EDID /**************************************************************************/ + /* * CTRLAttributeValidValuesRec - * @@ -2555,12 +2997,15 @@ * The permissions field of NVCTRLAttributeValidValuesRec is a bitmask * that may contain: * - * ATTRIBUTE_TYPE_READ - * ATTRIBUTE_TYPE_WRITE - * ATTRIBUTE_TYPE_DISPLAY + * ATTRIBUTE_TYPE_READ - Attribute may be read (queried.) + * ATTRIBUTE_TYPE_WRITE - Attribute may be written to (set.) + * ATTRIBUTE_TYPE_DISPLAY - Attribute requires a display mask. + * 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. * * See 'Key to Integer Attribute "Permissions"' at the top of this - * file for a description of what these three permission bits mean. + * file for a description of what these permission bits mean. */ #define ATTRIBUTE_TYPE_UNKNOWN 0 @@ -2570,9 +3015,12 @@ #define ATTRIBUTE_TYPE_RANGE 4 #define ATTRIBUTE_TYPE_INT_BITS 5 -#define ATTRIBUTE_TYPE_READ 0x1 -#define ATTRIBUTE_TYPE_WRITE 0x2 -#define ATTRIBUTE_TYPE_DISPLAY 0x4 +#define ATTRIBUTE_TYPE_READ 0x01 +#define ATTRIBUTE_TYPE_WRITE 0x02 +#define ATTRIBUTE_TYPE_DISPLAY 0x04 +#define ATTRIBUTE_TYPE_GPU 0x08 +#define ATTRIBUTE_TYPE_FRAMELOCK 0x10 +#define ATTRIBUTE_TYPE_X_SCREEN 0x20 typedef struct _NVCTRLAttributeValidValues { int type; @@ -2589,8 +3037,19 @@ typedef struct _NVCTRLAttributeValidValues { } NVCTRLAttributeValidValuesRec; +/**************************************************************************/ + +/* + * NV-CONTROL X event notification. + * + * To receive X event notifications dealing with NV-CONTROL, you should + * call XNVCtrlSelectNotify() with one of the following set as the type + * of event to receive (see NVCtrlLib.h for more information): + */ + +#define ATTRIBUTE_CHANGED_EVENT 0 +#define TARGET_ATTRIBUTE_CHANGED_EVENT 1 -#define ATTRIBUTE_CHANGED_EVENT 0 #endif /* __NVCTRL_H */ diff --git a/src/libXNVCtrl/NVCtrlLib.h b/src/libXNVCtrl/NVCtrlLib.h index cc4599f..318e978 100644 --- a/src/libXNVCtrl/NVCtrlLib.h +++ b/src/libXNVCtrl/NVCtrlLib.h @@ -48,6 +48,28 @@ Bool XNVCTRLIsNvScreen ( /* + * XNVCTRLQueryTargetCount - + * + * Returns True if the target type exists. Returns False otherwise. + * If XNVCTRLQueryTargetCount returns True, value will contain the + * count of existing targets on the server of the specified target + * type. + * + * Please see "Attribute Targets" in NVCtrl.h for the list of valid + * target types. + * + * Possible errors: + * BadValue - The target doesn't exist. + */ + +Bool XNVCTRLQueryTargetCount ( + Display *dpy, + int target_type, + int *value +); + + +/* * XNVCTRLSetAttribute - * * Sets the attribute to the given value. The attributes and their @@ -56,6 +78,10 @@ Bool XNVCTRLIsNvScreen ( * Not all attributes require the display_mask parameter; see * NVCtrl.h for details. * + * Calling this function is equivalent to calling XNVCTRLSetTargetAttribute() + * with the target_type set to NV_CTRL_TARGET_TYPE_X_SCREEN and + * target_id set to 'screen'. + * * Possible errors: * BadValue - The screen or attribute doesn't exist. * BadMatch - The NVIDIA driver is not present on that screen. @@ -71,6 +97,30 @@ void XNVCTRLSetAttribute ( /* + * XNVCTRLSetTargetAttribute - + * + * Sets the attribute to the given value. The attributes and their + * possible values are listed in NVCtrl.h. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Possible errors: + * BadValue - The target or attribute doesn't exist. + * BadMatch - The NVIDIA driver is not present on that target. + */ + +void XNVCTRLSetTargetAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int value +); + + +/* * XNVCTRLSetAttributeAndGetStatus - * * Same as XNVCTRLSetAttribute(). @@ -98,6 +148,10 @@ Bool XNVCTRLSetAttributeAndGetStatus ( * Not all attributes require the display_mask parameter; see * NVCtrl.h for details. * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetAttribute() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * * Possible errors: * BadValue - The screen doesn't exist. * BadMatch - The NVIDIA driver is not present on that screen. @@ -113,6 +167,31 @@ Bool XNVCTRLQueryAttribute ( /* + * XNVCTRLQueryTargetAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetAttribute returns True, value will contain the + * value of the specified attribute. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + */ + +Bool XNVCTRLQueryTargetAttribute ( + Display *dpy, + int target_Type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int *value +); + + +/* * XNVCTRLQueryStringAttribute - * * Returns True if the attribute exists. Returns False otherwise. @@ -120,6 +199,10 @@ Bool XNVCTRLQueryAttribute ( * allocated string containing the string attribute requested. It is * the caller's responsibility to free the string when done. * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetStringAttribute() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * * Possible errors: * BadValue - The screen doesn't exist. * BadMatch - The NVIDIA driver is not present on that screen. @@ -134,6 +217,31 @@ Bool XNVCTRLQueryStringAttribute ( char **ptr ); + +/* + * XNVCTRLQueryTargetStringAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetStringAttribute returns True, *ptr will point + * to an allocated string containing the string attribute requested. + * It is the caller's responsibility to free the string when done. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryTargetStringAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char **ptr +); + + /* * XNVCTRLSetStringAttribute - * @@ -153,6 +261,7 @@ Bool XNVCTRLSetStringAttribute ( char *ptr ); + /* * XNVCTRLQueryValidAttributeValues - * @@ -160,6 +269,10 @@ Bool XNVCTRLSetStringAttribute ( * XNVCTRLQueryValidAttributeValues returns True, values will indicate * the valid values for the specified attribute; see the description * of NVCTRLAttributeValidValues in NVCtrl.h. + * + * Calling this function is equivalent to calling + * XNVCTRLQueryValidTargetAttributeValues() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. */ Bool XNVCTRLQueryValidAttributeValues ( @@ -171,11 +284,69 @@ Bool XNVCTRLQueryValidAttributeValues ( ); + +/* + * XNVCTRLQueryValidTargetAttributeValues - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryValidTargetAttributeValues returns True, values will indicate + * the valid values for the specified attribute. + */ + +Bool XNVCTRLQueryValidTargetAttributeValues ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +); + + /* * XNVCTRLSetGvoColorConversion - * - * Sets the color conversion matrix and color offset - * that should be used for GVO (Graphic to Video Out). + * Sets the color conversion matrix, offset, and scale that should be + * used for GVO (Graphic to Video Out). + * + * The Color Space Conversion data is ordered like this: + * + * colorMatrix[0][0] // r.Y + * colorMatrix[0][1] // g.Y + * colorMatrix[0][2] // b.Y + * + * colorMatrix[1][0] // r.Cr + * colorMatrix[1][1] // g.Cr + * colorMatrix[1][2] // b.Cr + * + * colorMatrix[2][0] // r.Cb + * colorMatrix[2][1] // g.Cb + * colorMatrix[2][2] // b.Cb + * + * colorOffset[0] // Y + * colorOffset[1] // Cr + * colorOffset[2] // Cb + * + * colorScale[0] // Y + * colorScale[1] // Cr + * colorScale[2] // Cb + * + * where the data is used according to the following formulae: + * + * Y = colorOffset[0] + colorScale[0] * + * (R * colorMatrix[0][0] + + * G * colorMatrix[0][1] + + * B * colorMatrix[0][2]); + * + * Cr = colorOffset[1] + colorScale[1] * + * (R * colorMatrix[1][0] + + * G * colorMatrix[1][1] + + * B * colorMatrix[1][2]); + * + * Cb = colorOffset[2] + colorScale[2] * + * (R * colorMatrix[2][0] + + * G * colorMatrix[2][1] + + * B * colorMatrix[2][2]); * * Possible errors: * BadMatch - The NVIDIA driver is not present on that screen. @@ -186,16 +357,21 @@ void XNVCTRLSetGvoColorConversion ( Display *dpy, int screen, float colorMatrix[3][3], - float colorOffset[3] + float colorOffset[3], + float colorScale[3] ); + /* * XNVCTRLQueryGvoColorConversion - * * Retrieves the color conversion matrix and color offset * that are currently being used for GVO (Graphic to Video Out). * + * The values are ordered within the arrays according to the comments + * for XNVCTRLSetGvoColorConversion(). + * * Possible errors: * BadMatch - The NVIDIA driver is not present on that screen. * BadImplementation - GVO is not available on that screen. @@ -205,9 +381,11 @@ Bool XNVCTRLQueryGvoColorConversion ( Display *dpy, int screen, float colorMatrix[3][3], - float colorOffset[3] + float colorOffset[3], + float colorScale[3] ); + /* SPECIAL HANDLING OF VCP CODES * * XNVCTRLQueryDDCCILutSize @@ -436,6 +614,10 @@ Bool XNVCTRLQueryDDCCITimingReport ( * requested. It is the caller's responsibility to free the data * when done. len will list the length of the binary data. * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetBinaryData() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * * Possible errors: * BadValue - The screen doesn't exist. * BadMatch - The NVIDIA driver is not present on that screen. @@ -453,11 +635,38 @@ Bool XNVCTRLQueryBinaryData ( /* + * XNVCTRLQueryTargetBinaryData - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetBinaryData returns True, *ptr will point to an + * allocated block of memory containing the binary data attribute + * requested. It is the caller's responsibility to free the data + * when done. len will list the length of the binary data. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryTargetBinaryData ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len +); + + +/* * XNVCtrlSelectNotify - * * This enables/disables receiving of NV-CONTROL events. The type - * specifies the type of event to enable (currently, the only type is - * ATTRIBUTE_CHANGED_EVENT); onoff controls whether receiving this + * specifies the type of event to enable (currently, the only + * type that can be requested per-screen with XNVCtrlSelectNotify() + * is ATTRIBUTE_CHANGED_EVENT); onoff controls whether receiving this * type of event should be enabled (True) or disabled (False). * * Returns True if successful, or False if the screen is not @@ -472,6 +681,28 @@ Bool XNVCtrlSelectNotify ( ); +/* + * XNVCtrlSelectTargetNotify - + * + * This enables/disables receiving of NV-CONTROL events that happen on + * the specified target. The notify_type specifies the type of event to + * enable (currently, the only type that can be requested per-target with + * XNVCtrlSelectTargetNotify() is TARGET_ATTRIBUTE_CHANGED_EVENT); onoff + * controls whether receiving this type of event should be enabled (True) + * or disabled (False). + * + * Returns True if successful, or False if the target is not + * controlled by the NVIDIA driver. + */ + +Bool XNVCtrlSelectTargetNotify ( + Display *dpy, + int target_type, + int target_id, + int notify_type, + Bool onoff +); + /* * XNVCtrlEvent structure @@ -496,4 +727,28 @@ typedef union { } XNVCtrlEvent; +/* + * XNVCtrlEventTarget structure + */ + +typedef struct { + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int target_type; + int target_id; + unsigned int display_mask; + unsigned int attribute; + int value; +} XNVCtrlAttributeChangedEventTarget; + +typedef union { + int type; + XNVCtrlAttributeChangedEventTarget attribute_changed; + long pad[24]; +} XNVCtrlEventTarget; + + #endif /* __NVCTRLLIB_H */ diff --git a/src/libXNVCtrl/libXNVCtrl.a b/src/libXNVCtrl/libXNVCtrl.a Binary files differindex 8cb374b..65f789f 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 c1b7e3f..0ee7ee0 100644 --- a/src/libXNVCtrl/nv_control.h +++ b/src/libXNVCtrl/nv_control.h @@ -2,11 +2,11 @@ #define __NVCONTROL_H #define NV_CONTROL_ERRORS 0 -#define NV_CONTROL_EVENTS 1 +#define NV_CONTROL_EVENTS 2 #define NV_CONTROL_NAME "NV-CONTROL" #define NV_CONTROL_MAJOR 1 -#define NV_CONTROL_MINOR 7 +#define NV_CONTROL_MINOR 9 #define X_nvCtrlQueryExtension 0 #define X_nvCtrlIsNv 1 @@ -15,8 +15,8 @@ #define X_nvCtrlQueryStringAttribute 4 #define X_nvCtrlQueryValidAttributeValues 5 #define X_nvCtrlSelectNotify 6 -#define X_nvCtrlSetGvoColorConversion 7 -#define X_nvCtrlQueryGvoColorConversion 8 +#define X_nvCtrlSetGvoColorConversion_deprecated 7 +#define X_nvCtrlQueryGvoColorConversion_deprecated 8 #define X_nvCtrlSetStringAttribute 9 #define X_nvCtrlQueryDDCCILutSize 10 #define X_nvCtrlQueryDDCCISinglePointLutOperation 11 @@ -29,7 +29,11 @@ #define X_nvCtrlQueryDDCCITimingReport 18 #define X_nvCtrlSetAttributeAndGetStatus 19 #define X_nvCtrlQueryBinaryData 20 -#define X_nvCtrlLastRequest (X_nvCtrlQueryBinaryData + 1) +#define X_nvCtrlSetGvoColorConversion 21 +#define X_nvCtrlQueryGvoColorConversion 22 +#define X_nvCtrlSelectTargetNotify 23 +#define X_nvCtrlQueryTargetCount 24 +#define X_nvCtrlLastRequest (X_nvCtrlQueryTargetCount + 1) /* Define 32 bit floats */ @@ -87,7 +91,30 @@ typedef struct { CARD8 reqType; CARD8 nvReqType; CARD16 length B16; - CARD32 screen B32; + CARD32 target_type B32; +} xnvCtrlQueryTargetCountReq; +#define sz_xnvCtrlQueryTargetCountReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 count B32; + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; + CARD32 padl8 B32; +} xnvCtrlQueryTargetCountReply; +#define sz_xnvCtrlQueryTargetCountReply 32 + +typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_type B16; /* X screen or GPU */ + CARD16 target_id B16; /* X screen number or GPU number */ CARD32 display_mask B32; CARD32 attribute B32; } xnvCtrlQueryAttributeReq; @@ -111,7 +138,8 @@ typedef struct { CARD8 reqType; CARD8 nvReqType; CARD16 length B16; - CARD32 screen B32; + CARD16 target_type B16; + CARD16 target_id B16; CARD32 display_mask B32; CARD32 attribute B32; INT32 value B32; @@ -147,23 +175,20 @@ typedef struct { CARD8 reqType; CARD8 nvReqType; CARD16 length B16; - CARD32 screen B32; + CARD16 target_type B16; /* X screen or GPU */ + CARD16 target_id B16; /* X screen number or GPU number */ CARD32 display_mask B32; CARD32 attribute B32; } xnvCtrlQueryStringAttributeReq; #define sz_xnvCtrlQueryStringAttributeReq 16 -/* - * CtrlQueryStringAttribute reply struct - * n indicates the length of the string. - */ typedef struct { BYTE type; BYTE pad0; CARD16 sequenceNumber B16; CARD32 length B32; CARD32 flags B32; - CARD32 n B32; + CARD32 n B32; /* Length of string */ CARD32 pad4 B32; CARD32 pad5 B32; CARD32 pad6 B32; @@ -201,7 +226,8 @@ typedef struct { CARD8 reqType; CARD8 nvReqType; CARD16 length B16; - CARD32 screen B32; + CARD16 target_type B16; /* X screen or GPU */ + CARD16 target_id B16; /* X screen number or GPU number */ CARD32 display_mask B32; CARD32 attribute B32; } xnvCtrlQueryValidAttributeValuesReq; @@ -221,7 +247,7 @@ typedef struct { } xnvCtrlQueryValidAttributeValuesReply; #define sz_xnvCtrlQueryValidAttributeValuesReply 32 -/* Set GVO Color Conversion request */ +/* Set GVO Color Conversion request (deprecated) */ typedef struct { CARD8 reqType; CARD8 nvReqType; @@ -239,8 +265,63 @@ typedef struct { FLOAT32 row3_col2 F32; FLOAT32 row3_col3 F32; FLOAT32 row3_col4 F32; +} xnvCtrlSetGvoColorConversionDeprecatedReq; +#define sz_xnvCtrlSetGvoColorConversionDeprecatedReq 56 + +/* Query GVO Color Conversion request (deprecated) */ +typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; +} xnvCtrlQueryGvoColorConversionDeprecatedReq; +#define sz_xnvCtrlQueryGvoColorConversionDeprecatedReq 8 + +/* Query GVO Color Conversion reply (deprecated) */ +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xnvCtrlQueryGvoColorConversionDeprecatedReply; +#define sz_xnvCtrlQueryGvoColorConversionDeprecatedReply 32 + + +/* Set GVO Color Conversion request */ +typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; + + FLOAT32 cscMatrix_y_r F32; + FLOAT32 cscMatrix_y_g F32; + FLOAT32 cscMatrix_y_b F32; + + FLOAT32 cscMatrix_cr_r F32; + FLOAT32 cscMatrix_cr_g F32; + FLOAT32 cscMatrix_cr_b F32; + + FLOAT32 cscMatrix_cb_r F32; + FLOAT32 cscMatrix_cb_g F32; + FLOAT32 cscMatrix_cb_b F32; + + FLOAT32 cscOffset_y F32; + FLOAT32 cscOffset_cr F32; + FLOAT32 cscOffset_cb F32; + + FLOAT32 cscScale_y F32; + FLOAT32 cscScale_cr F32; + FLOAT32 cscScale_cb F32; + } xnvCtrlSetGvoColorConversionReq; -#define sz_xnvCtrlSetGvoColorConversionReq 56 +#define sz_xnvCtrlSetGvoColorConversionReq 68 /* Query GVO Color Conversion request */ typedef struct { @@ -267,7 +348,6 @@ typedef struct { #define sz_xnvCtrlQueryGvoColorConversionReply 32 - typedef struct { CARD8 reqType; CARD8 nvReqType; @@ -496,7 +576,8 @@ typedef struct { CARD8 reqType; CARD8 nvReqType; CARD16 length B16; - CARD32 screen B32; + CARD16 target_type B16; /* X screen or GPU */ + CARD16 target_id B16; /* X screen number or GPU number */ CARD32 display_mask B32; CARD32 attribute B32; } xnvCtrlQueryBinaryDataReq; @@ -550,4 +631,39 @@ typedef struct { } xnvctrlEvent; +typedef struct { + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_type B16; + CARD16 target_id B16; + CARD16 notifyType B16; + CARD16 onoff B16; +} xnvCtrlSelectTargetNotifyReq; +#define sz_xnvCtrlSelectTargetNotifyReq 12 + +typedef struct { + union { + struct { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + } u; + struct { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + CARD32 time B32; + CARD16 target_type B16; + CARD16 target_id B16; + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 value B32; + CARD32 pad0 B32; + CARD32 pad1 B32; + } attribute_changed; + } u; +} xnvctrlEventTarget; + + #endif /* __NVCONTROL_H */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.c b/src/libXNVCtrlAttributes/NvCtrlAttributes.c index 6f3ee3b..5cea7c5 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.c @@ -45,7 +45,8 @@ * NvCtrlAttributeInit() - XXX not sure how to handle errors */ -NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int screen, +NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int target_type, + int target_id, unsigned int subsystems) { NvCtrlAttributePrivateHandle *h = NULL; @@ -59,8 +60,9 @@ NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int screen, /* initialize the display and screen to the parameter values */ h->dpy = dpy; - h->screen = screen; - + h->target_type = target_type; + h->target_id = target_id; + /* initialize the NV-CONTROL attributes; give up if this fails */ if (subsystems & NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM) { @@ -69,40 +71,49 @@ NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int screen, } /* - * initialize the XF86VidMode attributes; it is OK if this - * fails - */ - - if (subsystems & NV_CTRL_ATTRIBUTES_XF86VIDMODE_SUBSYSTEM) { - h->vm = NvCtrlInitVidModeAttributes(h); - } - - /* - * initialize the XVideo extension and attributes; it is OK if - * this fails + * initialize X Screen specific attributes for X Screen + * target types. */ - if (subsystems & NV_CTRL_ATTRIBUTES_XVIDEO_SUBSYSTEM) { - h->xv = NvCtrlInitXvAttributes(h); - } - - /* - * initialize the GLX extension and attributes; it is OK if - * this fails - */ - - if (subsystems & NV_CTRL_ATTRIBUTES_GLX_SUBSYSTEM) { - h->glx = NvCtrlInitGlxAttributes(h); - } + if (target_type == NV_CTRL_TARGET_TYPE_X_SCREEN) { - /* - * initialize the XRandR extension and attributes; it is OK if - * this fails - */ + /* + * initialize the XF86VidMode attributes; it is OK if this + * fails + */ + + if (subsystems & NV_CTRL_ATTRIBUTES_XF86VIDMODE_SUBSYSTEM) { + h->vm = NvCtrlInitVidModeAttributes(h); + } + + /* + * initialize the XVideo extension and attributes; it is OK if + * this fails + */ + + if (subsystems & NV_CTRL_ATTRIBUTES_XVIDEO_SUBSYSTEM) { + h->xv = NvCtrlInitXvAttributes(h); + } + + /* + * initialize the GLX extension and attributes; it is OK if + * this fails + */ + + if (subsystems & NV_CTRL_ATTRIBUTES_GLX_SUBSYSTEM) { + h->glx = NvCtrlInitGlxAttributes(h); + } + + /* + * initialize the XRandR extension and attributes; it is OK if + * this fails + */ + + if (subsystems & NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM) { + h->xrandr = NvCtrlInitXrandrAttributes(h); + } - if (subsystems & NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM) { - h->xrandr = NvCtrlInitXrandrAttributes(h); - } + } /* X Screen target type attribute subsystems */ return (NvCtrlAttributeHandle *) h; @@ -135,8 +146,13 @@ char *NvCtrlGetDisplayName(NvCtrlAttributeHandle *handle) h = (NvCtrlAttributePrivateHandle *) handle; display_name = DisplayString(h->dpy); + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) { + /* Return the display name and # without a screen number */ + return nv_standardize_screen_name(display_name, -2); + } - return nv_standardize_screen_name(display_name, h->screen); + return nv_standardize_screen_name(display_name, h->target_id); } /* NvCtrlGetDisplayName() */ @@ -171,13 +187,51 @@ int NvCtrlGetScreen(NvCtrlAttributeHandle *handle) if (!handle) return -1; h = (NvCtrlAttributePrivateHandle *) handle; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; - return h->screen; + return h->target_id; } /* NvCtrlGetScreen() */ /* + * NvCtrlGetTargetType() - returns the target type associated with this + * NvCtrlAttributeHandle. + */ + +int NvCtrlGetTargetType(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + return h->target_type; + +} /* NvCtrlGetTargetType() */ + + +/* + * NvCtrlGetTargetId() - returns the target id number associated with this + * NvCtrlAttributeHandle. + */ + +int NvCtrlGetTargetId(NvCtrlAttributeHandle *handle) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return -1; + + h = (NvCtrlAttributePrivateHandle *) handle; + + return h->target_id; + +} /* NvCtrlGetTargetId() */ + + +/* * NvCtrlGetScreenWidth() - return the width of the screen associated * with this NvCtrlAttributeHandle. */ @@ -190,7 +244,9 @@ int NvCtrlGetScreenWidth(NvCtrlAttributeHandle *handle) h = (NvCtrlAttributePrivateHandle *) handle; - return DisplayWidth(h->dpy, h->screen); + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; + + return DisplayWidth(h->dpy, h->target_id); } /* NvCtrlGetScreenWidth() */ @@ -208,7 +264,9 @@ int NvCtrlGetScreenHeight(NvCtrlAttributeHandle *handle) h = (NvCtrlAttributePrivateHandle *) handle; - return DisplayHeight(h->dpy, h->screen); + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return -1; + + return DisplayHeight(h->dpy, h->target_id); } /* NvCtrlGetScreenHeight() */ @@ -241,6 +299,18 @@ int NvCtrlGetXrandrEventBase(NvCtrlAttributeHandle *handle) } /* NvCtrlGetXrandrEventBase() */ +ReturnStatus NvCtrlQueryTargetCount(NvCtrlAttributeHandle *handle, + int target_type, + int *val) +{ + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + if (!h) return NvCtrlBadArgument; + return NvCtrlNvControlQueryTargetCount(handle, target_type, val); + +} /* NvCtrlQueryTargetCount() */ + ReturnStatus NvCtrlGetAttribute(NvCtrlAttributeHandle *handle, int attr, int *val) { @@ -287,6 +357,15 @@ ReturnStatus NvCtrlGetStringAttribute(NvCtrlAttributeHandle *handle, } /* NvCtrlGetStringAttribute() */ +ReturnStatus NvCtrlSetStringAttribute(NvCtrlAttributeHandle *handle, + int attr, char *ptr, int *ret) +{ + if (!handle) return NvCtrlBadArgument; + return NvCtrlSetStringDisplayAttribute(handle, 0, attr, ptr, ret); + +} /* NvCtrlSetStringAttribute() */ + + ReturnStatus NvCtrlGetDisplayAttribute(NvCtrlAttributeHandle *handle, unsigned int display_mask, int attr, int *val) @@ -438,6 +517,26 @@ NvCtrlGetStringDisplayAttribute(NvCtrlAttributeHandle *handle, ReturnStatus +NvCtrlSetStringDisplayAttribute(NvCtrlAttributeHandle *handle, + unsigned int display_mask, + int attr, char *ptr, int *ret) +{ + NvCtrlAttributePrivateHandle *h; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if ((attr >= 0) && (attr <= NV_CTRL_STRING_LAST_ATTRIBUTE)) { + if (!h->nv) return NvCtrlMissingExtension; + return NvCtrlNvControlSetStringAttribute(h, display_mask, attr, + ptr, ret); + } + + return NvCtrlNoAttribute; + +} /* NvCtrlSetStringDisplayAttribute() */ + + +ReturnStatus NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, unsigned int display_mask, int attr, unsigned char **data, int *len) @@ -502,3 +601,12 @@ void NvCtrlAttributeClose(NvCtrlAttributeHandle *handle) free(h); } /* NvCtrlAttributeClose() */ + + +ReturnStatus +NvCtrlXrandrSetScreenMode (NvCtrlAttributeHandle *handle, + int width, int height, int refresh) +{ + return NvCtrlXrandrSetScreenMagicMode + ((NvCtrlAttributePrivateHandle *)handle, width, height, refresh); +} /* NvCtrlXrandrSetScreenMode() */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.h b/src/libXNVCtrlAttributes/NvCtrlAttributes.h index a2e6beb..08f958d 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributes.h +++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.h @@ -252,12 +252,15 @@ typedef struct GLXFBConfigAttrRec { -NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int screen, +NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int target_type, + int target_id, unsigned int subsystems); char *NvCtrlGetDisplayName(NvCtrlAttributeHandle *handle); Display *NvCtrlGetDisplayPtr(NvCtrlAttributeHandle *handle); int NvCtrlGetScreen(NvCtrlAttributeHandle *handle); +int NvCtrlGetTargetType(NvCtrlAttributeHandle *handle); +int NvCtrlGetTargetId(NvCtrlAttributeHandle *handle); int NvCtrlGetScreenWidth(NvCtrlAttributeHandle *handle); int NvCtrlGetScreenHeight(NvCtrlAttributeHandle *handle); int NvCtrlGetEventBase(NvCtrlAttributeHandle *handle); @@ -286,6 +289,14 @@ ReturnStatus NvCtrlGetColorRamp (NvCtrlAttributeHandle *handle, unsigned short **lut, int *n); +/* + * NvCtrlQueryTargetCount() - query the number of targets available + * on the server of the given target type. This is used, for example + * to return the number of GPUs the server knows about. + */ +ReturnStatus NvCtrlQueryTargetCount(NvCtrlAttributeHandle *handle, + int target_type, + int *val); /* * NvCtrlGetAttribute()/NvCtrlSetAttribute() - these get and set @@ -326,14 +337,23 @@ ReturnStatus NvCtrlGetValidAttributeValues (NvCtrlAttributeHandle *handle, /* * NvCtrlGetStringAttribute() - get the string associated with the * specified attribute, where valid values are the NV_CTRL_STRING_ - * #defines in NVCtrl.h. These strings are read-only (thus there is - * no parallel Set function). + * #defines in NVCtrl.h. */ ReturnStatus NvCtrlGetStringAttribute (NvCtrlAttributeHandle *handle, int attr, char **ptr); /* + * NvCtrlSetStringAttribute() - Set the string associated with the + * specified attribute, where valid values are the NV_CTRL_STRING_ + * #defines in NVCtrl.h that have the 'W' (Write) flag set. If 'ret' + * is specified, (integer) result information is returned. + */ + +ReturnStatus NvCtrlSetStringAttribute (NvCtrlAttributeHandle *handle, + int attr, char *ptr, int *ret); + +/* * The following four functions are identical to the above five, * except that they specify a particular display mask. */ @@ -360,12 +380,40 @@ NvCtrlGetStringDisplayAttribute (NvCtrlAttributeHandle *handle, int attr, char **ptr); ReturnStatus +NvCtrlSetStringDisplayAttribute (NvCtrlAttributeHandle *handle, + unsigned int display_mask, + int attr, char *ptr, int *ret); + +ReturnStatus NvCtrlGetBinaryAttribute(NvCtrlAttributeHandle *handle, unsigned int display_mask, int attr, unsigned char **data, int *len); +/* + * 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 + * attribute is TRUE. + */ + +ReturnStatus +NvCtrlSetGvoColorConversion(NvCtrlAttributeHandle *handle, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]); + +ReturnStatus +NvCtrlGetGvoColorConversion(NvCtrlAttributeHandle *handle, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]); + char *NvCtrlAttributesStrError (ReturnStatus status); void NvCtrlAttributeClose(NvCtrlAttributeHandle *handle); +ReturnStatus +NvCtrlXrandrSetScreenMode (NvCtrlAttributeHandle *handle, + int width, int height, int refresh); + #endif /* __NVCTRL_ATTRIBUTES__ */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c b/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c index b7f3060..08a40b6 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c @@ -36,15 +36,48 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <assert.h> #include <sys/utsname.h> #include <dlfcn.h> /* To dynamically load libGL.so */ #include <GL/glx.h> /* GLX #defines */ -#if defined(NV_BSD) -static void *__libGL_handle = NULL; -#endif + +typedef struct __libGLInfoRec { + + /* libGL.so library handle */ + void *handle; + int ref_count; /* # users of the library */ + + /* OpenGL functions used */ + const GLubyte * (* glGetString) (GLenum); + + /* GLX functions used */ + Bool (* glXQueryExtension) (Display *, int *, int *); + const char * (* glXQueryServerString) (Display *, int, int); + const char * (* glXGetClientString) (Display *, int); + const char * (* glXQueryExtensionsString) (Display *, int); + + Bool (* glXIsDirect) (Display *, GLXContext); + Bool (* glXMakeCurrent) (Display *, GLXDrawable, + GLXContext); + GLXContext (* glXCreateContext) (Display *, XVisualInfo *, + GLXContext, Bool); + void (* glXDestroyContext) (Display *, GLXContext); + XVisualInfo * (* glXChooseVisual) (Display *, int, int *); +#ifdef GLX_VERSION_1_3 + GLXFBConfig * (* glXGetFBConfigs) (Display *, int, int *); + int (* glXGetFBConfigAttrib) (Display *, GLXFBConfig, + int, int *); + XVisualInfo * (* glXGetVisualFromFBConfig) (Display *, GLXFBConfig); +#endif /* GLX_VERSION_1_3 */ + +} __libGLInfo; + +static __libGLInfo *__libGL = NULL; + + /**** * @@ -91,134 +124,180 @@ static void *__libGL_handle = NULL; /****************************************************************************** * - * NvCtrlInitGlxAttributes() - * - * Initializes the NvCtrlGlxAttributes Extension by linking the libGL.so.1 and - * resolving functions used to retrieve GLX information. - * - * NOTE: A private dpy is kept due to a libGL.so.1 bug where closing the library - * before closing the dpy will cause XCloseDisplay to segfault. + * Opens libGL for usage * ****/ -NvCtrlGlxAttributes * -NvCtrlInitGlxAttributes (NvCtrlAttributePrivateHandle *h) +static Bool open_libgl(void) { - NvCtrlGlxAttributes * glx = NULL; - const char * error = NULL; /* libGL error string */ - - /* For querying server about glx extension */ - int errorBase; - int eventBase; - Bool (* glXQueryExtension) (Display *, int *, int *); + const char *error_str = NULL; + /* Initialize bookkeeping structure */ + if ( !__libGL ) { + __libGL = (__libGLInfo *) calloc(1, sizeof(__libGLInfo)); + if ( !__libGL ) { + goto fail; + } + } + - /* Check parameter */ - if ( h == NULL || h->dpy == NULL ) { - goto fail; + /* Library was already opened */ + if ( __libGL->handle ) { + __libGL->ref_count++; + return True; } - /* Allocate for the GlxAttributes struct */ - glx = (NvCtrlGlxAttributes *) - calloc(1, sizeof (NvCtrlGlxAttributes)); - if ( glx == NULL ) { - error = "Out of memory."; + /* We are the first to open the library */ + __libGL->handle = dlopen("libGL.so.1", RTLD_LAZY); + if ( !__libGL->handle ) { goto fail; } -#if defined(NV_BSD) - /* - * XXX In current versions of FreeBSD, static TLS data - * allocated for the initial dlopen() doesn't appear - * to be free()'d on dlclose(); this results in failures - * on subsequent attempts to open libGL.so. - */ - if (__libGL_handle == NULL) { - __libGL_handle = dlopen("libGL.so.1", RTLD_LAZY); - } - glx->libGL = __libGL_handle; -#else - /* Link the libGL lib */ - glx->libGL = dlopen("libGL.so.1", RTLD_LAZY); -#endif - if ( glx->libGL == NULL ) { - /* Silently fail */ - goto fail; - } + /* Resolve GLX functions */ + __libGL->glGetString = + NV_DLSYM(__libGL->handle, "glGetString"); + if ((error_str = dlerror()) != NULL) goto fail; - /* Make sure GLX is supported by the server */ - glXQueryExtension = NV_DLSYM(glx->libGL, "glXQueryExtension"); - glx->dpy = XOpenDisplay( XDisplayString(h->dpy) ); - if ( glx->dpy == NULL ) { - goto fail; - } - if ( !glXQueryExtension(glx->dpy, &errorBase, &eventBase) ) { - goto fail; - } + __libGL->glXQueryExtension = + NV_DLSYM(__libGL->handle, "glXQueryExtension"); + if ((error_str = dlerror()) != NULL) goto fail; + __libGL->glXQueryServerString = + NV_DLSYM(__libGL->handle, "glXQueryServerString"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXGetClientString = + NV_DLSYM(__libGL->handle, "glXGetClientString"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXQueryExtensionsString = + NV_DLSYM(__libGL->handle, "glXQueryExtensionsString"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXIsDirect = + NV_DLSYM(__libGL->handle, "glXIsDirect"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXMakeCurrent = + NV_DLSYM(__libGL->handle, "glXMakeCurrent"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXCreateContext = + NV_DLSYM(__libGL->handle, "glXCreateContext"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXDestroyContext = + NV_DLSYM(__libGL->handle, "glXDestroyContext"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXChooseVisual = + NV_DLSYM(__libGL->handle, "glXChooseVisual"); + if ((error_str = dlerror()) != NULL) goto fail; - /* Resolve GLX functions */ - glx->glGetString = NV_DLSYM(glx->libGL, - "glGetString"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXQueryExtensionsString = NV_DLSYM(glx->libGL, - "glXQueryExtensionsString"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXQueryServerString = NV_DLSYM(glx->libGL, - "glXQueryServerString"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXGetClientString = NV_DLSYM(glx->libGL, - "glXGetClientString"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXIsDirect = NV_DLSYM(glx->libGL, - "glXIsDirect"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXMakeCurrent = NV_DLSYM(glx->libGL, - "glXMakeCurrent"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXCreateContext = NV_DLSYM(glx->libGL, - "glXCreateContext"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXDestroyContext = NV_DLSYM(glx->libGL, - "glXDestroyContext"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXChooseVisual = NV_DLSYM(glx->libGL, - "glXChooseVisual"); - if ((error = dlerror()) != NULL) goto fail; #ifdef GLX_VERSION_1_3 - glx->glXGetFBConfigs = NV_DLSYM(glx->libGL, - "glXGetFBConfigs"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXGetFBConfigAttrib = NV_DLSYM(glx->libGL, - "glXGetFBConfigAttrib"); - if ((error = dlerror()) != NULL) goto fail; - glx->glXGetVisualFromFBConfig = NV_DLSYM(glx->libGL, - "glXGetVisualFromFBConfig"); - if ((error = dlerror()) != NULL) goto fail; + __libGL->glXGetFBConfigs = + NV_DLSYM(__libGL->handle, "glXGetFBConfigs"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXGetFBConfigAttrib = + NV_DLSYM(__libGL->handle, "glXGetFBConfigAttrib"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libGL->glXGetVisualFromFBConfig = + NV_DLSYM(__libGL->handle, "glXGetVisualFromFBConfig"); + if ((error_str = dlerror()) != NULL) goto fail; #endif /* GLX_VERSION_1_3 */ - return glx; - + /* Up the ref count */ + __libGL->ref_count++; + + return True; + /* Handle failures */ fail: - if ( error != NULL ) { - nv_error_msg("libGL setup error : %s\n", error); + if ( error_str ) { + nv_error_msg("libGL setup error : %s\n", error_str); } - if ( glx != NULL ) { - if ( glx->dpy != NULL ) { - XCloseDisplay(glx->dpy); + if ( __libGL ) { + if ( __libGL->handle ) { + dlclose(__libGL->handle); + __libGL->handle = NULL; } - if ( glx->libGL != NULL ) { - dlclose(glx->libGL); + free(__libGL); + __libGL = NULL; + } + return False; + +} /* open_libgL() */ + + + +/****************************************************************************** + * + * Closes libGL - + * + ****/ + +static void close_libgl(void) +{ + if ( __libGL && __libGL->handle && __libGL->ref_count ) { + __libGL->ref_count--; + if ( __libGL->ref_count == 0 ) { + dlclose(__libGL->handle); + __libGL->handle = NULL; + free(__libGL); + __libGL = NULL; } - free(glx); } - return NULL; +} /* close_libgl() */ + + + +/****************************************************************************** + * + * NvCtrlInitGlxAttributes() + * + * Initializes the NvCtrlGlxAttributes Extension by linking the libGL.so.1 and + * resolving functions used to retrieve GLX information. + * + * NOTE: A private dpy is kept due to a libGL.so.1 bug where closing the library + * before closing the dpy will cause XCloseDisplay to segfault. + * + ****/ + +Bool +NvCtrlInitGlxAttributes (NvCtrlAttributePrivateHandle *h) +{ + int event_base; + int error_base; + + + /* Check parameters */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { + return False; + } + + + /* Open libGL.so.1 */ + if ( !open_libgl() ) { + return False; + } + + + /* Verify server support of GLX extension */ + if ( !__libGL->glXQueryExtension(h->dpy, + &(error_base), + &(event_base)) ) { + return False; + } + + return True; + } /* NvCtrlInitGlxAttributes() */ @@ -235,22 +314,13 @@ NvCtrlInitGlxAttributes (NvCtrlAttributePrivateHandle *h) void NvCtrlGlxAttributesClose (NvCtrlAttributePrivateHandle *h) { - if ( h == NULL || h->glx == NULL ) { + if ( !h || !h->glx ) { return; } + + close_libgl(); - if ( h->glx->dpy != NULL ) { - XCloseDisplay( h->glx->dpy ); - } - -#if !defined(NV_BSD) - if ( h->glx->libGL != NULL ) { - dlclose( h->glx->libGL ); - } -#endif - - free(h->glx); - h->glx = NULL; + h->glx = False; } /* NvCtrlGlxAttributesClose() */ @@ -287,20 +357,18 @@ get_fbconfig_attribs(NvCtrlAttributePrivateHandle *h) - /* Some sanity */ - if ( h == NULL || h->dpy == NULL || h->glx == NULL ) { - goto fail; - } + assert(h->target_type == NV_CTRL_TARGET_TYPE_X_SCREEN); + /* Get all fbconfigs for the display/screen */ - fbconfigs = (* (h->glx->glXGetFBConfigs))( h->glx->dpy, h->screen, - &nfbconfigs); + fbconfigs = (* (__libGL->glXGetFBConfigs)) (h->dpy, h->target_id, + &nfbconfigs); if ( fbconfigs == NULL || nfbconfigs == 0 ) { goto fail; } /* Allocate to hold the fbconfig attributes */ - fbcas = calloc(nfbconfigs + 1, sizeof (GLXFBConfigAttr)); + fbcas = calloc(nfbconfigs + 1, sizeof(GLXFBConfigAttr)); if ( fbcas == NULL ) { goto fail; } @@ -309,8 +377,8 @@ get_fbconfig_attribs(NvCtrlAttributePrivateHandle *h) for ( i = 0; i < nfbconfigs; i++ ) { /* Get related visual id if any */ - visinfo = (* (h->glx->glXGetVisualFromFBConfig)) (h->glx->dpy, - fbconfigs[i]); + visinfo = (* (__libGL->glXGetVisualFromFBConfig)) (h->dpy, + fbconfigs[i]); if ( visinfo ) { fbcas[i].visual_id = visinfo->visualid; XFree(visinfo); @@ -318,137 +386,137 @@ get_fbconfig_attribs(NvCtrlAttributePrivateHandle *h) fbcas[i].visual_id = 0; } - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_FBCONFIG_ID, &(fbcas[i].fbconfig_id)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_BUFFER_SIZE, &(fbcas[i].buffer_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_LEVEL, &(fbcas[i].level)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_DOUBLEBUFFER, &(fbcas[i].doublebuffer)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_STEREO, &(fbcas[i].stereo)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_AUX_BUFFERS, &(fbcas[i].aux_buffers)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_RED_SIZE, &(fbcas[i].red_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_GREEN_SIZE, &(fbcas[i].green_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_BLUE_SIZE, &(fbcas[i].blue_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_ALPHA_SIZE, &(fbcas[i].alpha_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_DEPTH_SIZE, &(fbcas[i].depth_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_STENCIL_SIZE, &(fbcas[i].stencil_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_ACCUM_RED_SIZE, &(fbcas[i].accum_red_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_ACCUM_GREEN_SIZE, &(fbcas[i].accum_green_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_ACCUM_BLUE_SIZE, &(fbcas[i].accum_blue_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_ACCUM_ALPHA_SIZE, &(fbcas[i].accum_alpha_size)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_RENDER_TYPE, &(fbcas[i].render_type)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_DRAWABLE_TYPE, &(fbcas[i].drawable_type)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_X_RENDERABLE, &(fbcas[i].x_renderable)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_X_VISUAL_TYPE, &(fbcas[i].x_visual_type)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_CONFIG_CAVEAT, &(fbcas[i].config_caveat)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_TYPE, &(fbcas[i].transparent_type)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_INDEX_VALUE, &(fbcas[i].transparent_index_value)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_RED_VALUE, &(fbcas[i].transparent_red_value)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_GREEN_VALUE, &(fbcas[i].transparent_green_value)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_BLUE_VALUE, &(fbcas[i].transparent_blue_value)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_TRANSPARENT_ALPHA_VALUE, &(fbcas[i].transparent_alpha_value)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_MAX_PBUFFER_WIDTH, &(fbcas[i].pbuffer_width)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_MAX_PBUFFER_HEIGHT, &(fbcas[i].pbuffer_height)); if ( ret != Success ) goto fail; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_MAX_PBUFFER_PIXELS, &(fbcas[i].pbuffer_max)); if ( ret != Success ) goto fail; #if defined(GLX_SAMPLES_ARB) && defined (GLX_SAMPLE_BUFFERS_ARB) fbcas[i].multi_sample_valid = 1; - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, fbconfigs[i], + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_SAMPLES_ARB, &(fbcas[i].multi_samples)); if ( ret != Success ) { fbcas[i].multi_sample_valid = 0; } else { - ret = (* (h->glx->glXGetFBConfigAttrib)) (h->glx->dpy, + ret = (* (__libGL->glXGetFBConfigAttrib))(h->dpy, fbconfigs[i], GLX_SAMPLE_BUFFERS_ARB, &(fbcas[i].multi_sample_buffers)); @@ -470,10 +538,10 @@ get_fbconfig_attribs(NvCtrlAttributePrivateHandle *h) /* Handle failures */ fail: - if ( fbcas != NULL ) { + if ( fbcas ) { free(fbcas); } - if ( fbconfigs != NULL ) { + if ( fbconfigs ) { XFree(fbconfigs); } @@ -500,8 +568,14 @@ NvCtrlGlxGetVoidAttribute (NvCtrlAttributePrivateHandle *h, GLXFBConfigAttr * fbconfig_attribs = NULL; - /* Validate Arguments */ - if (h == NULL || ptr == NULL) { + /* Validate */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { + return NvCtrlBadHandle; + } + if ( !h->glx || !__libGL ) { + return NvCtrlMissingExtension; + } + if ( !ptr ) { return NvCtrlBadArgument; } @@ -555,28 +629,26 @@ NvCtrlGlxGetVoidAttribute (NvCtrlAttributePrivateHandle *h, /* Macros to set up/tear down a rendering context */ #define GET_CONTEXT() \ - \ - root = RootWindow(h->glx->dpy, h->screen); \ - visinfo = h->glx->glXChooseVisual(h->glx->dpy, h->screen, \ + root = RootWindow(h->dpy, h->target_id); \ + visinfo = __libGL->glXChooseVisual(h->dpy, h->target_id, \ &(attribListSgl[0])); \ win_attr.background_pixel = 0; \ win_attr.border_pixel = 0; \ - win_attr.colormap = XCreateColormap(h->glx->dpy, root, \ + win_attr.colormap = XCreateColormap(h->dpy, root, \ visinfo->visual, AllocNone); \ - win_attr.event_mask = StructureNotifyMask | ExposureMask; \ + win_attr.event_mask = 0; \ mask = CWBackPixel | CWBorderPixel | CWColormap | \ CWEventMask; \ - win = XCreateWindow(h->glx->dpy, root, 0, 0, width, height, \ + win = XCreateWindow(h->dpy, root, 0, 0, width, height, \ 0, visinfo->depth, InputOutput, \ visinfo->visual, mask, &win_attr); \ - ctx = h->glx->glXCreateContext(h->glx->dpy, visinfo, NULL, True ); \ - if ( ctx ) { h->glx->glXMakeCurrent(h->glx->dpy, win, ctx); } + ctx = __libGL->glXCreateContext(h->dpy, visinfo, NULL, True ); \ + if ( ctx ) { __libGL->glXMakeCurrent(h->dpy, win, ctx); } #define CLEAN_CONTEXT() \ - \ if ( visinfo ) { XFree(visinfo); } \ - if ( ctx ) { h->glx->glXDestroyContext(h->glx->dpy, ctx); } \ - if ( win ) { XDestroyWindow(h->glx->dpy, win); } + if ( ctx ) { __libGL->glXDestroyContext(h->dpy, ctx); } \ + if ( win ) { XDestroyWindow(h->dpy, win); } ReturnStatus @@ -602,67 +674,68 @@ NvCtrlGlxGetStringAttribute (NvCtrlAttributePrivateHandle *h, GLX_BLUE_SIZE, 1, None }; - - /* Validate Arguments */ - if (h == NULL || ptr == NULL) { + /* Validate */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { + return NvCtrlBadHandle; + } + if ( !h->glx || !__libGL ) { + return NvCtrlMissingExtension; + } + if ( !ptr ) { return NvCtrlBadArgument; } - /* Make sure extension was initialized */ - if ( h->glx == NULL ) { - return NvCtrlError; - } /* Get the right string */ switch (attr) { case NV_CTRL_STRING_GLX_DIRECT_RENDERING: GET_CONTEXT(); - str = ( (* (h->glx->glXIsDirect))(h->glx->dpy, ctx) ) ? "Yes" : "No"; + str = ( (* (__libGL->glXIsDirect))(h->dpy, ctx) ) ? "Yes" : "No"; CLEAN_CONTEXT(); break; case NV_CTRL_STRING_GLX_GLX_EXTENSIONS: - str = (* (h->glx->glXQueryExtensionsString))(h->glx->dpy, h->screen); + str = (* (__libGL->glXQueryExtensionsString))(h->dpy, h->target_id); break; case NV_CTRL_STRING_GLX_SERVER_VENDOR: - str = (* (h->glx->glXQueryServerString))(h->glx->dpy, h->screen, - GLX_VENDOR); + str = (* (__libGL->glXQueryServerString))(h->dpy, h->target_id, + GLX_VENDOR); break; case NV_CTRL_STRING_GLX_SERVER_VERSION: - str = (* (h->glx->glXQueryServerString))(h->glx->dpy, h->screen, - GLX_VERSION); + str = (* (__libGL->glXQueryServerString))(h->dpy, h->target_id, + GLX_VERSION); break; case NV_CTRL_STRING_GLX_SERVER_EXTENSIONS: - str = (* (h->glx->glXQueryServerString))(h->glx->dpy, h->screen, - GLX_EXTENSIONS); + str = (* (__libGL->glXQueryServerString))(h->dpy, h->target_id, + GLX_EXTENSIONS); break; case NV_CTRL_STRING_GLX_CLIENT_VENDOR: - str = (* (h->glx->glXGetClientString))(h->glx->dpy, GLX_VENDOR); + str = (* (__libGL->glXGetClientString))(h->dpy, GLX_VENDOR); break; case NV_CTRL_STRING_GLX_CLIENT_VERSION: - str = (* (h->glx->glXGetClientString))(h->glx->dpy, GLX_VERSION); + str = (* (__libGL->glXGetClientString))(h->dpy, GLX_VERSION); break; case NV_CTRL_STRING_GLX_CLIENT_EXTENSIONS: - str = (* (h->glx->glXGetClientString))(h->glx->dpy, GLX_EXTENSIONS); + str = (* (__libGL->glXGetClientString))(h->dpy, GLX_EXTENSIONS); break; case NV_CTRL_STRING_GLX_OPENGL_VENDOR: GET_CONTEXT(); - str = (const char *) (* (h->glx->glGetString))(GL_VENDOR); + str = (const char *) (* (__libGL->glGetString))(GL_VENDOR); CLEAN_CONTEXT(); break; case NV_CTRL_STRING_GLX_OPENGL_RENDERER: GET_CONTEXT(); - str = (const char *) (* (h->glx->glGetString))(GL_RENDERER); + str = (const char *) (* (__libGL->glGetString))(GL_RENDERER); CLEAN_CONTEXT(); break; case NV_CTRL_STRING_GLX_OPENGL_VERSION: GET_CONTEXT(); - str = (const char *) (* (h->glx->glGetString))(GL_VERSION); + str = (const char *) (* (__libGL->glGetString))(GL_VERSION); CLEAN_CONTEXT(); break; case NV_CTRL_STRING_GLX_OPENGL_EXTENSIONS: GET_CONTEXT(); - str = (const char *) (* (h->glx->glGetString))(GL_EXTENSIONS); + str = (const char *) (* (__libGL->glGetString))(GL_EXTENSIONS); CLEAN_CONTEXT(); break; @@ -673,8 +746,7 @@ NvCtrlGlxGetStringAttribute (NvCtrlAttributePrivateHandle *h, /* Copy the string and return it */ - if ( str == NULL || - (*ptr = strdup(str)) == NULL ) { + if ( !str || (*ptr = strdup(str)) == NULL ) { return NvCtrlError; } diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c index d9b8d25..32177e8 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c @@ -63,18 +63,20 @@ NvCtrlInitNvControlAttributes (NvCtrlAttributePrivateHandle *h) return NULL; } - ret = XNVCTRLIsNvScreen (h->dpy, h->screen); - if (ret != True) { - nv_warning_msg("NV-CONTROL extension not present on screen %d " - "of this Display.", h->screen); - return NULL; + if (h->target_type == NV_CTRL_TARGET_TYPE_X_SCREEN) { + ret = XNVCTRLIsNvScreen (h->dpy, h->target_id); + if (ret != True) { + nv_warning_msg("NV-CONTROL extension not present on screen %d " + "of this Display.", h->target_id); + return NULL; + } } nv = (NvCtrlNvControlAttributes *) calloc(1, sizeof (NvCtrlNvControlAttributes)); - ret = XNVCtrlSelectNotify(h->dpy, h->screen, - ATTRIBUTE_CHANGED_EVENT, True); + ret = XNVCtrlSelectTargetNotify(h->dpy, h->target_type, h->target_id, + TARGET_ATTRIBUTE_CHANGED_EVENT, True); if (ret != True) { nv_warning_msg("Unable to select attribute changed NV-CONTROL " "events."); @@ -90,13 +92,24 @@ NvCtrlInitNvControlAttributes (NvCtrlAttributePrivateHandle *h) } /* NvCtrlInitNvControlAttributes() */ +ReturnStatus NvCtrlNvControlQueryTargetCount(NvCtrlAttributePrivateHandle *h, + int target_type, int *val) +{ + int ret; + + ret = XNVCTRLQueryTargetCount(h->dpy, target_type, val); + return (ret) ? NvCtrlSuccess : NvCtrlError; + +} /* NvCtrlNvControlQueryTargetCount() */ + + ReturnStatus NvCtrlNvControlGetAttribute (NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, int *val) { if (attr <= NV_CTRL_LAST_ATTRIBUTE) { - if (XNVCTRLQueryAttribute (h->dpy, h->screen, display_mask, - attr, val)) { + if (XNVCTRLQueryTargetAttribute (h->dpy, h->target_type, h->target_id, + display_mask, attr, val)) { return NvCtrlSuccess; } else { return NvCtrlAttributeNotAvailable; @@ -105,7 +118,7 @@ ReturnStatus NvCtrlNvControlGetAttribute (NvCtrlAttributePrivateHandle *h, return NvCtrlNoAttribute; -} /* NvCtrlGetAttribute() */ +} /* NvCtrlNvControlGetAttribute() */ ReturnStatus NvCtrlNvControlSetAttribute (NvCtrlAttributePrivateHandle *h, @@ -113,14 +126,15 @@ ReturnStatus NvCtrlNvControlSetAttribute (NvCtrlAttributePrivateHandle *h, int attr, int val) { if (attr <= NV_CTRL_LAST_ATTRIBUTE) { - XNVCTRLSetAttribute (h->dpy, h->screen, display_mask, attr, val); + XNVCTRLSetTargetAttribute (h->dpy, h->target_type, h->target_id, + display_mask, attr, val); XFlush (h->dpy); return NvCtrlSuccess; } return NvCtrlNoAttribute; -} /* NvCtrlGetAttribute() */ +} /* NvCtrlNvControlSetAttribute() */ ReturnStatus NvCtrlNvControlGetValidAttributeValues @@ -129,8 +143,9 @@ ReturnStatus NvCtrlNvControlGetValidAttributeValues int attr, NVCTRLAttributeValidValuesRec *val) { if (attr <= NV_CTRL_LAST_ATTRIBUTE) { - if (XNVCTRLQueryValidAttributeValues (h->dpy, h->screen, - display_mask, attr, val)) { + if (XNVCTRLQueryValidTargetAttributeValues (h->dpy, h->target_type, + h->target_id, display_mask, + attr, val)) { return NvCtrlSuccess; } else { return NvCtrlAttributeNotAvailable; @@ -148,8 +163,9 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *h, int attr, char **ptr) { if (attr <= NV_CTRL_STRING_LAST_ATTRIBUTE) { - if (XNVCTRLQueryStringAttribute (h->dpy, h->screen, - display_mask, attr, ptr)) { + if (XNVCTRLQueryTargetStringAttribute (h->dpy, h->target_type, + h->target_id, display_mask, + attr, ptr)) { return NvCtrlSuccess; } else { return NvCtrlAttributeNotAvailable; @@ -162,6 +178,36 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *h, ReturnStatus +NvCtrlNvControlSetStringAttribute (NvCtrlAttributePrivateHandle *h, + unsigned int display_mask, + int attr, char *ptr, int *ret) +{ + int tmp_int; /* Temp storage if ret is not specified */ + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) { + return NvCtrlBadHandle; + } + + if (attr <= NV_CTRL_LAST_ATTRIBUTE) { + if ( !ret ) { + ret = &tmp_int; + } + *ret = + XNVCTRLSetStringAttribute (h->dpy, h->target_id, display_mask, + attr, ptr); + if ( *ret ) { + return NvCtrlSuccess; + } else { + return NvCtrlAttributeNotAvailable; + } + } + + return NvCtrlNoAttribute; + +} /* NvCtrlNvControlSetStringAttribute() */ + + +ReturnStatus NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, unsigned char **data, int *len) @@ -171,15 +217,14 @@ NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, if (!h->nv) return NvCtrlMissingExtension; /* the X_nvCtrlQueryBinaryData opcode was added in 1.7 */ - + if ((h->nv->major_version < 1) || ((h->nv->major_version == 1) && (h->nv->minor_version < 7))) { return NvCtrlNoAttribute; } - bret = XNVCTRLQueryBinaryData(h->dpy, h->screen, display_mask, - attr, data, len); - + bret = XNVCTRLQueryTargetBinaryData (h->dpy, h->target_type, h->target_id, + display_mask, attr, data, len); if (!bret) { return NvCtrlError; } else { @@ -187,3 +232,61 @@ NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, } } /* NvCtrlNvControlGetBinaryAttribute() */ + + +ReturnStatus +NvCtrlSetGvoColorConversion(NvCtrlAttributeHandle *handle, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]) +{ + NvCtrlAttributePrivateHandle *h; + + if (!handle) return NvCtrlBadHandle; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->nv) return NvCtrlMissingExtension; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return NvCtrlBadHandle; + + XNVCTRLSetGvoColorConversion(h->dpy, + h->target_id, + colorMatrix, + colorOffset, + colorScale); + + return NvCtrlSuccess; + +} /* NvCtrlNvControlSetGvoColorConversion() */ + + +ReturnStatus +NvCtrlGetGvoColorConversion(NvCtrlAttributeHandle *handle, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]) +{ + NvCtrlAttributePrivateHandle *h; + Bool bRet; + + if (!handle) return NvCtrlBadHandle; + + h = (NvCtrlAttributePrivateHandle *) handle; + + if (!h->nv) return NvCtrlMissingExtension; + + if (h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) return NvCtrlBadHandle; + + bRet = XNVCTRLQueryGvoColorConversion(h->dpy, + h->target_id, + colorMatrix, + colorOffset, + colorScale); + if (!bRet) { + return NvCtrlError; + } else { + return NvCtrlSuccess; + } + +} /* NvCtrlNvControlGetGvoColorConversion() */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h index e9f622e..314234d 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 6 +#define NV_MINMINOR 9 /* minimum required version for the XF86VidMode extension */ @@ -85,7 +85,6 @@ typedef struct __NvCtrlXvOverlayAttributes NvCtrlXvOverlayAttributes; typedef struct __NvCtrlXvTextureAttributes NvCtrlXvTextureAttributes; typedef struct __NvCtrlXvBlitterAttributes NvCtrlXvBlitterAttributes; typedef struct __NvCtrlXvAttribute NvCtrlXvAttribute; -typedef struct __NvCtrlGlxAttributes NvCtrlGlxAttributes; typedef struct __NvCtrlXrandrAttributes NvCtrlXrandrAttributes; struct __NvCtrlNvControlAttributes { @@ -131,110 +130,28 @@ struct __NvCtrlXvBlitterAttributes { }; struct __NvCtrlXvAttributes { - - /* libXv.so library handle */ - void *libXv; - - /* Private display connection for the Xv ext. */ - Display *dpy; - - /* libXv functions */ - int (* XvGetPortAttribute) (Display *, XvPortID, Atom, int *); - - int (* XvSetPortAttribute) (Display *, XvPortID, Atom, int); - - XvAttribute* (* XvQueryPortAttributes) (Display *, XvPortID, int *); - - int (* XvQueryExtension) (Display *, unsigned int *, unsigned int *, - unsigned int *, unsigned int *, unsigned int *); - - int (* XvQueryAdaptors) (Display *, Window, unsigned int *, - XvAdaptorInfo **); - - NvCtrlXvOverlayAttributes *overlay; /* XVideo info (overlay) */ NvCtrlXvTextureAttributes *texture; /* XVideo info (texture) */ NvCtrlXvBlitterAttributes *blitter; /* XVideo info (blitter) */ }; -struct __NvCtrlGlxAttributes { - - /* Private display connection for the GLX information ext. */ - Display *dpy; - - /* libGL.so library handle */ - void *libGL; - - /* OpenGL functions used */ - const GLubyte * (* glGetString) (GLenum); - - /* GLX functions used */ - const char * (* glXQueryServerString) (Display *, int, int); - const char * (* glXGetClientString) (Display *, int); - const char * (* glXQueryExtensionsString) (Display *, int); - - Bool (* glXIsDirect) (Display *, GLXContext); - Bool (* glXMakeCurrent) (Display *, GLXDrawable, - GLXContext); - GLXContext (* glXCreateContext) (Display *, XVisualInfo *, - GLXContext, Bool); - void (* glXDestroyContext) (Display *, GLXContext); - XVisualInfo * (* glXChooseVisual) (Display *, int, int *); -#ifdef GLX_VERSION_1_3 - GLXFBConfig * (* glXGetFBConfigs) (Display *, int, int *); - int (* glXGetFBConfigAttrib) (Display *, GLXFBConfig, - int, int *); - XVisualInfo * (* glXGetVisualFromFBConfig) (Display *, GLXFBConfig); -#endif /* GLX_VERSION_1_3 */ -}; - struct __NvCtrlXrandrAttributes { - - /* Private display connection for the XRandR information ext. */ - Display *dpy; - - /* libXrandr.so library handle */ - void *libXrandr; - int event_base; /* XRandR extension event base */ - int error_base; - Rotation rotations; /* Valid rotations */ - int nsizes; /* Valid sizes */ - - /* XRandR functions used */ - Bool (* XRRQueryExtension) (Display *dpy, - int *event_base, - int *error_base); - void (* XRRSelectInput) (Display *dpy, Window window, - int mask); - - SizeID (* XRRConfigCurrentConfiguration) (XRRScreenConfiguration *config, - Rotation *rotation); - - XRRScreenConfiguration * (* XRRGetScreenInfo) (Display *dpy, Drawable draw); - - Rotation (* XRRConfigRotations) (XRRScreenConfiguration *config, - Rotation *rotation); - - void (* XRRFreeScreenConfigInfo) (XRRScreenConfiguration *); - - Rotation (* XRRRotations) (Display *dpy, int screen, Rotation *current_rotation); - XRRScreenSize *(* XRRSizes) (Display *dpy, int screen, int *nsizes); - - Status (* XRRSetScreenConfig) (Display *dpy, - XRRScreenConfiguration *config, - Drawable draw, - int size_index, - Rotation rotation, - Time timestamp); + int event_base; + int error_base; }; struct __NvCtrlAttributePrivateHandle { Display *dpy; /* display connection */ - int screen; /* the screen that this handle controls */ + int target_type; /* Type of target this handle conrols */ + int target_id; /* screen num, gpu num (etc) of target */ + + /* Common attributes */ NvCtrlNvControlAttributes *nv; /* NV-CONTROL extension info */ + + /* Screen-specific attributes */ NvCtrlVidModeAttributes *vm; /* XF86VidMode extension info */ NvCtrlXvAttributes *xv; /* XVideo info */ - NvCtrlGlxAttributes *glx; /* GLX extension info */ + Bool glx; /* GLX extension available */ NvCtrlXrandrAttributes *xrandr; /* XRandR extension info */ }; @@ -256,7 +173,7 @@ NvCtrlXvAttributesClose (NvCtrlAttributePrivateHandle *); /* GLX extension attribute functions */ -NvCtrlGlxAttributes * +Bool NvCtrlInitGlxAttributes (NvCtrlAttributePrivateHandle *); void @@ -285,10 +202,16 @@ NvCtrlXrandrGetAttribute (NvCtrlAttributePrivateHandle *, int, int *); ReturnStatus NvCtrlXrandrSetAttribute (NvCtrlAttributePrivateHandle *, int, int); +ReturnStatus +NvCtrlXrandrSetScreenMagicMode (NvCtrlAttributePrivateHandle *, int, int, int); + /* Generic attribute functions */ ReturnStatus +NvCtrlNvControlQueryTargetCount(NvCtrlAttributePrivateHandle *, int, int *); + +ReturnStatus NvCtrlNvControlGetAttribute (NvCtrlAttributePrivateHandle *, unsigned int, int, int *); @@ -305,6 +228,10 @@ NvCtrlNvControlGetStringAttribute (NvCtrlAttributePrivateHandle *, unsigned int, int, char **); ReturnStatus +NvCtrlNvControlSetStringAttribute (NvCtrlAttributePrivateHandle *, + unsigned int, int, char *, int *); + +ReturnStatus NvCtrlNvControlGetBinaryAttribute(NvCtrlAttributePrivateHandle *h, unsigned int display_mask, int attr, unsigned char **data, int *len); diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c b/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c index 8876e14..4c77d57 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c @@ -82,6 +82,12 @@ NvCtrlInitVidModeAttributes(NvCtrlAttributePrivateHandle *h) NvCtrlVidModeAttributes *vm = NULL; int ret, event, ver, rev, i; + + /* Check parameters */ + if (!h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) { + goto failed; + } + #if defined(X_XF86VidModeGetGammaRampSize) ret = XF86VidModeQueryExtension(h->dpy, &event, &vidModeErrorBase); @@ -110,7 +116,7 @@ NvCtrlInitVidModeAttributes(NvCtrlAttributePrivateHandle *h) prev_error_handler = XSetErrorHandler(vidModeErrorHandler); - ret = XF86VidModeGetGammaRampSize(h->dpy, h->screen, &vm->n); + ret = XF86VidModeGetGammaRampSize(h->dpy, h->target_id, &vm->n); /* check if XF86VidModeGetGammaRampSize was blocked */ @@ -124,7 +130,7 @@ NvCtrlInitVidModeAttributes(NvCtrlAttributePrivateHandle *h) vm->lut[GREEN] = (unsigned short *) malloc(sizeof(unsigned short) * vm->n); vm->lut[BLUE] = (unsigned short *) malloc(sizeof(unsigned short) * vm->n); - ret = XF86VidModeGetGammaRamp(h->dpy, h->screen, vm->n, vm->lut[RED], + ret = XF86VidModeGetGammaRamp(h->dpy, h->target_id, vm->n, vm->lut[RED], vm->lut[GREEN], vm->lut[BLUE]); /* check if XF86VidModeGetGammaRamp was blocked */ @@ -144,7 +150,7 @@ NvCtrlInitVidModeAttributes(NvCtrlAttributePrivateHandle *h) * It's terrible that we have to do this. */ - ret = XF86VidModeSetGammaRamp(h->dpy, h->screen, vm->n, + ret = XF86VidModeSetGammaRamp(h->dpy, h->target_id, vm->n, vm->lut[RED], vm->lut[GREEN], vm->lut[BLUE]); @@ -271,7 +277,10 @@ ReturnStatus NvCtrlSetColorAttributes(NvCtrlAttributeHandle *handle, h = (NvCtrlAttributePrivateHandle *) handle; - if (!h || !h->dpy) return NvCtrlBadHandle; + /* Check parameters */ + if (!h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) { + return NvCtrlBadHandle; + } if (!h->vm) return NvCtrlMissingExtension; /* clamp input, but only the input specified in the bitmask */ @@ -322,7 +331,7 @@ ReturnStatus NvCtrlSetColorAttributes(NvCtrlAttributeHandle *handle, } } - ret = XF86VidModeSetGammaRamp(h->dpy, h->screen, h->vm->n, + ret = XF86VidModeSetGammaRamp(h->dpy, h->target_id, h->vm->n, h->vm->lut[RED], h->vm->lut[GREEN], h->vm->lut[BLUE]); @@ -349,7 +358,10 @@ ReturnStatus NvCtrlGetColorRamp(NvCtrlAttributeHandle *handle, h = (NvCtrlAttributePrivateHandle *) handle; - if (!h || !h->dpy) return NvCtrlBadHandle; + /* Check parameters */ + if (!h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN) { + return NvCtrlBadHandle; + } if (!h->vm) return NvCtrlMissingExtension; *n = h->vm->n; diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c b/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c index 1aaba8a..29b0412 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c @@ -24,14 +24,12 @@ /* * XRandR backend - * - * Currently only rotation is supported. - * */ #include <sys/utsname.h> #include <stdlib.h> /* 64 bit malloc */ +#include <assert.h> #include <dlfcn.h> /* To dynamically load libXrandr.so.2 */ #include <X11/Xlib.h> @@ -45,57 +43,197 @@ #include "parse.h" +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); + + void (* XRRSelectInput) + (Display *dpy, Window window, int mask); + + XRRScreenConfiguration * (* XRRGetScreenInfo) + (Display *dpy, Drawable draw); + + SizeID (* XRRConfigCurrentConfiguration) + (XRRScreenConfiguration *config, Rotation *rotation); + + Rotation (* XRRConfigRotations) + (XRRScreenConfiguration *config, Rotation *rotation); + + XRRScreenSize * (* XRRConfigSizes) + (XRRScreenConfiguration *config, int *nsizes); + + short * (* XRRConfigRates) + (XRRScreenConfiguration *config, int size_index, int *nrates); + + Status (* XRRSetScreenConfig) + (Display *dpy, XRRScreenConfiguration *config, Drawable draw, + int size_index, Rotation rotation, Time timestamp); + + Status (* XRRSetScreenConfigAndRate) + (Display *dpy, XRRScreenConfiguration *config, Drawable draw, + int size_index, Rotation rotation, short rate, Time timestamp); + + void (* XRRFreeScreenConfigInfo) + (XRRScreenConfiguration *); + +} __libXrandrInfo; + +static __libXrandrInfo *__libXrandr = NULL; + + /****************************************************************************** * - * Sets the requested rotation orientation. + * Opens libXrandr for usage * ****/ -static ReturnStatus -set_rotation(NvCtrlAttributePrivateHandle *h, Rotation rotation) +static Bool open_libxrandr(void) { - XRRScreenConfiguration *sc; - Rotation cur_rotation; - SizeID cur_size; - Status status; + const char *error_str = NULL; - /* Check orientation is supported */ - if ( !( h->xrandr->rotations & rotation ) ) { - return NvCtrlBadArgument; + /* Initialize bookkeeping structure */ + if ( !__libXrandr ) { + __libXrandr = (__libXrandrInfo *) calloc(1, sizeof(__libXrandrInfo)); + if ( !__libXrandr ) { + goto fail; + } + } + + /* Library was already opened */ + if ( __libXrandr->handle ) { + __libXrandr->ref_count++; + return True; } - /* Get current size & orientation */ - sc = h->xrandr->XRRGetScreenInfo(h->xrandr->dpy, - RootWindow(h->xrandr->dpy, h->screen)); - if ( !sc ) { - return NvCtrlError; + + /* We are the first to open the library */ + __libXrandr->handle = dlopen("libXrandr.so.2", RTLD_LAZY); + if ( !__libXrandr->handle ) { + goto fail; } - cur_size = h->xrandr->XRRConfigCurrentConfiguration(sc, &cur_rotation); - status = h->xrandr->XRRSetScreenConfig (h->xrandr->dpy, sc, - RootWindow(h->xrandr->dpy, - h->screen), - cur_size, rotation, CurrentTime); - h->xrandr->XRRFreeScreenConfigInfo(sc); - if ( status != Success ) { - return NvCtrlError; + /* Resolve XRandR functions */ + __libXrandr->XRRQueryExtension = + NV_DLSYM(__libXrandr->handle, "XRRQueryExtension"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRSelectInput = + NV_DLSYM(__libXrandr->handle, "XRRSelectInput"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRGetScreenInfo = + NV_DLSYM(__libXrandr->handle, "XRRGetScreenInfo"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRConfigCurrentConfiguration = + NV_DLSYM(__libXrandr->handle, "XRRConfigCurrentConfiguration"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRConfigRotations = + NV_DLSYM(__libXrandr->handle, "XRRConfigRotations"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRConfigSizes = + NV_DLSYM(__libXrandr->handle, "XRRConfigSizes"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRConfigRates = + NV_DLSYM(__libXrandr->handle, "XRRConfigRates"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRSetScreenConfig = + NV_DLSYM(__libXrandr->handle, "XRRSetScreenConfig"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRSetScreenConfigAndRate = + NV_DLSYM(__libXrandr->handle, "XRRSetScreenConfigAndRate"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXrandr->XRRFreeScreenConfigInfo = + NV_DLSYM(__libXrandr->handle, "XRRFreeScreenConfigInfo"); + if ((error_str = dlerror()) != NULL) goto fail; + + + /* Up the ref count */ + __libXrandr->ref_count++; + + return True; + + + /* Handle failures */ + fail: + if ( error_str ) { + nv_error_msg("libXrandr setup error : %s\n", error_str); + } + if ( __libXrandr ) { + if ( __libXrandr->handle ) { + dlclose(__libXrandr->handle); + __libXrandr->handle = NULL; + } + free(__libXrandr); + __libXrandr = NULL; } + return False; + +} /* open_libxrandr() */ - return NvCtrlSuccess; -} /* set_rotation() */ +/****************************************************************************** + * + * Closes libXrandr when it is no longer being used. + * + ****/ + +static void close_libxrandr(void) +{ + if ( __libXrandr && __libXrandr->handle && __libXrandr->ref_count ) { + __libXrandr->ref_count--; + +#if !defined(NV_BSD) /* WAR for FreeBSD static TLS data bug */ + if ( __libXrandr->ref_count == 0 ) { + dlclose(__libXrandr->handle); + __libXrandr->handle = NULL; + free(__libXrandr); + __libXrandr = NULL; + } +#endif + } + +} /* close_libxrandr() */ + + + +/****************************************************************************** + * + * Some XR&R functions fails on XFree86 4.3.0 with BadImplementation if the + * screen resolution is not the one the server started with. We work around + * that by temporarily installing an error handler, trying the call, and then + * disabling the rotation page if it fails. + * + ****/ static int errors = 0; +static int (*old_error_handler)(Display *, XErrorEvent *); + static int error_handler (Display *dpy, XErrorEvent *err) { errors++; return 0; -} + +} /* error_handler() */ + /****************************************************************************** @@ -108,133 +246,72 @@ error_handler (Display *dpy, XErrorEvent *err) NvCtrlXrandrAttributes * NvCtrlInitXrandrAttributes (NvCtrlAttributePrivateHandle *h) { - NvCtrlXrandrAttributes *xrandr = NULL; - const char *error = NULL; /* libXrandr error string */ - Bool ret; - Rotation rotation; - XRRScreenSize *sizes; - int (*oldErrorHandler)(Display *, XErrorEvent *); - - - /* Check parameter */ - if ( h == NULL || h->dpy == NULL ) { - goto fail; - } + NvCtrlXrandrAttributes * xrandr = NULL; + XRRScreenConfiguration *sc; + Rotation rotation, rotations; - /* Allocate attributes structure */ - xrandr = (NvCtrlXrandrAttributes *) - calloc(1, sizeof (NvCtrlXrandrAttributes)); - if ( xrandr == NULL ) { - error = "Out of memory."; + /* Check parameters */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { goto fail; } - /* Link the libXrandr lib */ - xrandr->libXrandr = dlopen("libXrandr.so.2", RTLD_LAZY); - if ( xrandr->libXrandr == NULL ) { + /* Open libXrandr.so.2 */ + if ( !open_libxrandr() ) { /* Silently fail */ goto fail; } - /* Resolve XRandR functions */ - xrandr->XRRQueryExtension = NV_DLSYM(xrandr->libXrandr, - "XRRQueryExtension"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRSelectInput = NV_DLSYM(xrandr->libXrandr, "XRRSelectInput"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRConfigCurrentConfiguration = NV_DLSYM(xrandr->libXrandr, - "XRRConfigCurrentConfiguration"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRGetScreenInfo = NV_DLSYM(xrandr->libXrandr, - "XRRGetScreenInfo"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRConfigRotations = NV_DLSYM(xrandr->libXrandr, "XRRConfigRotations"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRFreeScreenConfigInfo = NV_DLSYM(xrandr->libXrandr, - "XRRFreeScreenConfigInfo"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRSetScreenConfig = NV_DLSYM(xrandr->libXrandr, - "XRRSetScreenConfig"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRRotations = NV_DLSYM(xrandr->libXrandr, "XRRRotations"); - if ((error = dlerror()) != NULL) goto fail; - - xrandr->XRRSizes = NV_DLSYM(xrandr->libXrandr, "XRRSizes"); - if ((error = dlerror()) != NULL) goto fail; - - - /* Duplicate the display connection */ - - xrandr->dpy = XOpenDisplay(XDisplayString(h->dpy)); - if ( xrandr->dpy == NULL ) + /* Create storage for XRandR attributes */ + xrandr = + (NvCtrlXrandrAttributes *) calloc(1, sizeof(NvCtrlXrandrAttributes)); + if ( !xrandr ) { goto fail; + } + - /* Verify rotation is supported */ - ret = xrandr->XRRQueryExtension(xrandr->dpy, &xrandr->event_base, - &xrandr->error_base); - if ( !ret ) goto fail; - - /* - * XRRRotations fails on XFree86 4.3.0 with BadImplementation if the screen - * resolution is not the one the server started with. We work around that - * by temporarily installing an error handler, trying the call, and then - * disabling the rotation page if it fails. - */ - XSync(xrandr->dpy, False); + XSync(h->dpy, False); errors = 0; - oldErrorHandler = XSetErrorHandler(error_handler); + old_error_handler = XSetErrorHandler(error_handler); + + /* Verify server support of XRandR extension */ + if ( !__libXrandr->XRRQueryExtension(h->dpy, + &(xrandr->event_base), + &(xrandr->error_base)) ) { + XSync(h->dpy, False); + XSetErrorHandler(old_error_handler); + goto fail; + } - xrandr->rotations = xrandr->XRRRotations(xrandr->dpy, h->screen, - &rotation); - sizes = xrandr->XRRSizes(xrandr->dpy, h->screen, - &(xrandr->nsizes)); + + /* Register to receive XRandR events */ + __libXrandr->XRRSelectInput(h->dpy, RootWindow(h->dpy, h->target_id), + RRScreenChangeNotifyMask); - XSync(xrandr->dpy, False); - XSetErrorHandler(oldErrorHandler); - if ( errors > 0 ) goto fail; + /* Try calling a couple functions that are known to fail */ + sc = __libXrandr->XRRGetScreenInfo(h->dpy, RootWindow(h->dpy, h->target_id)); + if ( sc ) { + rotations = __libXrandr->XRRConfigRotations(sc, &rotation); + __libXrandr->XRRFreeScreenConfigInfo(sc); + } else { + errors++; + } - /* Must support more than one rotation orientation */ - if ( (xrandr->rotations == 1) || (xrandr->rotations == 2) || - (xrandr->rotations == 4) || (xrandr->rotations == 8) ) { + XSync(h->dpy, False); + XSetErrorHandler(old_error_handler); + if ( errors > 0 ) { goto fail; } - - /* Register to recieve XRandR events */ - xrandr->XRRSelectInput(xrandr->dpy, RootWindow(xrandr->dpy, h->screen), - RRScreenChangeNotifyMask); - - // xrandr->rotations = 1; - return xrandr; - - /* Handle failures */ fail: - if ( error != NULL ) { - nv_error_msg("libXrandr setup error : %s\n", error); - } - if ( xrandr != NULL ) { - if ( xrandr->dpy != NULL ) { - XCloseDisplay(xrandr->dpy); - } - if ( xrandr->libXrandr != NULL ) { - dlclose(xrandr->libXrandr); - } + if ( xrandr ) { free(xrandr); } - return NULL; } /* NvCtrlInitXrandrAttributes() */ @@ -251,16 +328,12 @@ NvCtrlInitXrandrAttributes (NvCtrlAttributePrivateHandle *h) void NvCtrlXrandrAttributesClose (NvCtrlAttributePrivateHandle *h) { - if ( h == NULL || h->xrandr == NULL ) { + /* Check parameters */ + if ( !h || !h->xrandr || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { return; } - if ( h->xrandr->dpy ) { - XCloseDisplay(h->xrandr->dpy); - } - if ( h->xrandr->libXrandr != NULL ) { - dlclose( h->xrandr->libXrandr ); - } + close_libxrandr(); free(h->xrandr); h->xrandr = NULL; @@ -280,39 +353,49 @@ NvCtrlXrandrGetAttribute (NvCtrlAttributePrivateHandle *h, int attr, int *val) { XRRScreenConfiguration *sc; - Rotation rotation; + Rotation rotation, rotations; - /* Validate Arguments */ - if ( h == NULL ) { + /* Validate */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { return NvCtrlBadHandle; } - if ( h->xrandr == NULL ) { + if ( !h->xrandr || !__libXrandr ) { return NvCtrlMissingExtension; } - if ( val == NULL ) { + if ( !val ) { return NvCtrlBadArgument; } + /* Get current screen configuration information */ + sc = __libXrandr->XRRGetScreenInfo(h->dpy, RootWindow(h->dpy, + h->target_id)); + if ( !sc ) { + return NvCtrlError; + } + rotations = __libXrandr->XRRConfigRotations(sc, &rotation); + __libXrandr->XRRFreeScreenConfigInfo(sc); + + /* Fetch right attribute */ switch ( attr ) { case NV_CTRL_ATTR_XRANDR_ROTATION_SUPPORTED: - *val = ( (h->xrandr!=NULL)?1:0 ); + /* For rotation to be supported, there must + * be at least 2 orientations + */ + *val = ( rotations != 1 && rotations != 2 && + rotations != 4 && rotations != 8 ) ? 1 : 0; break; case NV_CTRL_ATTR_XRANDR_ROTATIONS: - *val = h->xrandr->rotations; + /* Return the available rotations */ + *val = rotations; break; case NV_CTRL_ATTR_XRANDR_ROTATION: - sc = h->xrandr->XRRGetScreenInfo(h->xrandr->dpy, - RootWindow(h->xrandr->dpy, - h->screen)); - h->xrandr->XRRConfigRotations(sc, &rotation); - h->xrandr->XRRFreeScreenConfigInfo(sc); - + /* Return the current rotation */ *val = (int)rotation; break; @@ -321,6 +404,7 @@ NvCtrlXrandrGetAttribute (NvCtrlAttributePrivateHandle *h, break; } /* Done fetching attribute */ + return NvCtrlSuccess; } /* NvCtrlXrandrGetAttribute */ @@ -333,15 +417,54 @@ NvCtrlXrandrGetAttribute (NvCtrlAttributePrivateHandle *h, * ****/ +static ReturnStatus +set_rotation(NvCtrlAttributePrivateHandle *h, Rotation rotation) +{ + XRRScreenConfiguration *sc; + Rotation cur_rotation, rotations; + SizeID cur_size; + Status ret; + + + assert(h->target_type == NV_CTRL_TARGET_TYPE_X_SCREEN); + + /* 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); + rotations = __libXrandr->XRRConfigRotations(sc, &cur_rotation); + + + /* Check orientation we want is supported */ + if ( !(rotations & rotation) ) { + __libXrandr->XRRFreeScreenConfigInfo(sc); + return NvCtrlBadArgument; + } + + + /* Set the orientation */ + ret = __libXrandr->XRRSetScreenConfig(h->dpy, sc, + RootWindow(h->dpy, h->target_id), + cur_size, rotation, CurrentTime); + __libXrandr->XRRFreeScreenConfigInfo(sc); + + return ( ret == Success )?NvCtrlSuccess:NvCtrlError; + +} /* set_rotation() */ + + ReturnStatus NvCtrlXrandrSetAttribute (NvCtrlAttributePrivateHandle *h, int attr, int val) { - /* Validate Arguments */ - if ( h == NULL ) { + /* Validate */ + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { return NvCtrlBadHandle; } - if ( h->xrandr == NULL ) { + if ( !h->xrandr || !__libXrandr ) { return NvCtrlMissingExtension; } @@ -358,14 +481,86 @@ NvCtrlXrandrSetAttribute (NvCtrlAttributePrivateHandle *h, break; case NV_CTRL_ATTR_XRANDR_ROTATION: - return set_rotation(h, (Rotation) val); + return set_rotation(h, (Rotation)val); break; default: return NvCtrlNoAttribute; break; - } /* Done setting attribute */ + } return NvCtrlSuccess; } /* NvCtrlXrandrSetAttribute */ + + + +/****************************************************************************** + * + * Sets XRandR size and refresh rate. + * + ****/ + +ReturnStatus +NvCtrlXrandrSetScreenMagicMode (NvCtrlAttributePrivateHandle *h, + int width, int height, int magic_ref_rate) +{ + XRRScreenConfiguration *sc; + Rotation cur_rotation; + int nsizes; + XRRScreenSize *sizes; + int nrates; + short *rates; + Status ret; + + + /* 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; + } + __libXrandr->XRRConfigRotations(sc, &cur_rotation); + + + /* Look for size that has matching refresh rate */ + sizes = __libXrandr->XRRConfigSizes(sc, &nsizes); + while ( --nsizes >= 0 ) { + + /* Must match in size */ + if ( sizes[nsizes].width != width || + sizes[nsizes].height != height ) { + continue; + } + + rates = __libXrandr->XRRConfigRates(sc, nsizes, &nrates); + while ( --nrates >= 0 ) { + + /* Set the mode if we found the rate */ + if ( *rates == magic_ref_rate ) { + ret = __libXrandr->XRRSetScreenConfigAndRate + (h->dpy, sc, RootWindow(h->dpy, h->target_id), nsizes, + cur_rotation, magic_ref_rate, CurrentTime); + + __libXrandr->XRRFreeScreenConfigInfo(sc); + return (ret == Success)?NvCtrlSuccess:NvCtrlError; + } + rates++; + } + } + + /* If we are here, then we could not find the correct mode to set */ + __libXrandr->XRRFreeScreenConfigInfo(sc); + return NvCtrlError; + +} /* NvCtrlXrandrSetScreenMagicMode */ diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c b/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c index c105be4..5d061d6 100644 --- a/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c +++ b/src/libXNVCtrlAttributes/NvCtrlAttributesXv.c @@ -33,7 +33,7 @@ #include "msg.h" -static NvCtrlXvAttribute *getXvAttribute (NvCtrlXvAttributes *, +static NvCtrlXvAttribute *getXvAttribute (NvCtrlAttributePrivateHandle *, XvPortID, const char *); static Bool checkAdaptor(NvCtrlAttributePrivateHandle *h, @@ -45,6 +45,123 @@ static unsigned int getXvPort(NvCtrlAttributePrivateHandle *h, static NvCtrlXvAttribute *getXvAttributePtr(NvCtrlAttributePrivateHandle *h, unsigned int attribute); +typedef struct __libXvInfoRec { + + /* libXv.so library handle */ + void *handle; + int ref_count; /* # users of the library */ + + /* libXv functions used */ + int (* XvGetPortAttribute) (Display *, XvPortID, Atom, int *); + int (* XvSetPortAttribute) (Display *, XvPortID, Atom, int); + XvAttribute * (* XvQueryPortAttributes) (Display *, XvPortID, int *); + int (* XvQueryExtension) (Display *, unsigned int *, + unsigned int *, unsigned int *, + unsigned int *, unsigned int *); + int (* XvQueryAdaptors) (Display *, Window, unsigned int *, + XvAdaptorInfo **); +} __libXvInfo; + +static __libXvInfo *__libXv = NULL; + + + +/* + * Opens libXv for usage + */ + +static Bool open_libxv(void) +{ + const char *error_str = NULL; + + + /* Initialize bookkeeping structure */ + if ( !__libXv ) { + __libXv = (__libXvInfo *) calloc(1, sizeof(__libXvInfo)); + if ( !__libXv ) { + goto fail; + } + } + + + /* Library was already opened */ + if ( __libXv->handle ) { + __libXv->ref_count++; + return True; + } + + + /* We are the first to open the library */ + __libXv->handle = dlopen("libXv.so.1", RTLD_LAZY); + if ( __libXv->handle == NULL ) { + goto fail; + } + + + /* Resolve Xv functions */ + __libXv->XvQueryExtension = + NV_DLSYM(__libXv->handle, "XvQueryExtension"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXv->XvQueryAdaptors = + NV_DLSYM(__libXv->handle, "XvQueryAdaptors"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXv->XvGetPortAttribute = + NV_DLSYM(__libXv->handle, "XvGetPortAttribute"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXv->XvSetPortAttribute = + NV_DLSYM(__libXv->handle, "XvSetPortAttribute"); + if ((error_str = dlerror()) != NULL) goto fail; + + __libXv->XvQueryPortAttributes = + NV_DLSYM(__libXv->handle, "XvQueryPortAttributes"); + if ((error_str = dlerror()) != NULL) goto fail; + + + /* Up the ref count */ + __libXv->ref_count++; + + return True; + + + fail: + if ( error_str ) { + nv_error_msg("libXv setup error : %s\n", error_str); + } + if ( __libXv ) { + if ( __libXv->handle ) { + dlclose(__libXv->handle); + __libXv->handle = NULL; + } + free(__libXv); + __libXv = NULL; + } + return False; + +} /* open_libxv() */ + + + +/* + * Closes libXv when it is no longer used. + */ + +static void close_libxv(void) +{ + if ( __libXv && __libXv->handle && __libXv->ref_count ) { + __libXv->ref_count--; + if ( __libXv->ref_count == 0 ) { + dlclose(__libXv->handle); + __libXv->handle = NULL; + free(__libXv); + __libXv = NULL; + } + } +} /* close_libxv() */ + + /* * NvCtrlInitXvAttributes() - scan through the list of Xv adaptors on @@ -60,33 +177,20 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) { NvCtrlXvAttributes *xv = NULL; XvAdaptorInfo *ainfo; - unsigned int ver, rev, req, event, error, nadaptors; + unsigned int ver, rev, req, event_base, error_base, nadaptors; int ret, i; - Display *dpy; const char *error_str = NULL; const char *warn_str = NULL; /* Check parameters */ - if (h == NULL || h->dpy == NULL) { + if ( !h || !h->dpy || h->target_type != NV_CTRL_TARGET_TYPE_X_SCREEN ) { goto fail; } - dpy = h->dpy; - /* Allocate the attributes structure */ - xv = (NvCtrlXvAttributes *) - calloc(1, sizeof (NvCtrlXvAttributes)); - if ( xv == NULL ) { - error_str = "Out of memory."; - goto fail; - } - - - /* Link the libXv lib */ - xv->libXv = dlopen("libXv.so.1", RTLD_LAZY); - - if (xv->libXv == NULL) { + /* Open libXv.so.1 */ + if ( !open_libxv() ) { warn_str = "Failed to open libXv.so.1: this library " "is not present in your system or is not in your " "LD_LIBRARY_PATH."; @@ -94,37 +198,26 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) } - /* Resolve Xv functions needed */ - xv->XvQueryExtension = NV_DLSYM(xv->libXv, "XvQueryExtension"); - if ((error_str = dlerror()) != NULL) goto fail; - - xv->XvQueryAdaptors = NV_DLSYM(xv->libXv, "XvQueryAdaptors"); - if ((error_str = dlerror()) != NULL) goto fail; - - xv->XvGetPortAttribute = NV_DLSYM(xv->libXv, "XvGetPortAttribute"); - if ((error_str = dlerror()) != NULL) goto fail; - - xv->XvSetPortAttribute = NV_DLSYM(xv->libXv, "XvSetPortAttribute"); - if ((error_str = dlerror()) != NULL) goto fail; - - xv->XvQueryPortAttributes = NV_DLSYM(xv->libXv, "XvQueryPortAttributes"); - if ((error_str = dlerror()) != NULL) goto fail; - - - /* Duplicate the display connection and verify Xv extension exists */ - xv->dpy = XOpenDisplay( XDisplayString(h->dpy) ); - if ( xv->dpy == NULL ) { + /* Allocate the attributes structure */ + xv = (NvCtrlXvAttributes *) + calloc(1, sizeof (NvCtrlXvAttributes)); + if ( xv == NULL ) { + error_str = "Out of memory."; goto fail; } - ret = xv->XvQueryExtension(xv->dpy, &ver, &rev, &req, &event, &error); + + + /* Verify server support of Xv extension */ + ret = __libXv->XvQueryExtension(h->dpy, &ver, &rev, &req, + &event_base, &error_base); if (ret != Success) goto fail; /* XXX do we have a minimum Xv version? */ /* Get the list of adaptors */ - ret = xv->XvQueryAdaptors(xv->dpy, RootWindow(dpy, h->screen), - &nadaptors, &ainfo); + ret = __libXv->XvQueryAdaptors(h->dpy, RootWindow(h->dpy, h->target_id), + &nadaptors, &ainfo); if (ret != Success || !nadaptors || !ainfo) goto fail; @@ -143,15 +236,15 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) } attrs->port = ainfo[i].base_id; - attrs->saturation = getXvAttribute(xv, attrs->port, + attrs->saturation = getXvAttribute(h, attrs->port, "XV_SATURATION"); - attrs->contrast = getXvAttribute(xv, attrs->port, + attrs->contrast = getXvAttribute(h, attrs->port, "XV_CONTRAST"); - attrs->brightness = getXvAttribute(xv, attrs->port, + attrs->brightness = getXvAttribute(h, attrs->port, "XV_BRIGHTNESS"); - attrs->hue = getXvAttribute(xv, attrs->port, + attrs->hue = getXvAttribute(h, attrs->port, "XV_HUE"); - attrs->defaults = getXvAttribute(xv, attrs->port, + attrs->defaults = getXvAttribute(h, attrs->port, "XV_SET_DEFAULTS"); if (!attrs->saturation || @@ -186,9 +279,9 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) } attrs->port = ainfo[i].base_id; - attrs->sync_to_vblank = getXvAttribute(xv, attrs->port, + attrs->sync_to_vblank = getXvAttribute(h, attrs->port, "XV_SYNC_TO_VBLANK"); - attrs->defaults = getXvAttribute(xv, attrs->port, + attrs->defaults = getXvAttribute(h, attrs->port, "XV_SET_DEFAULTS"); if (!attrs->sync_to_vblank || !attrs->defaults) { @@ -216,9 +309,9 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) } attrs->port = ainfo[i].base_id; - attrs->sync_to_vblank = getXvAttribute(xv, attrs->port, + attrs->sync_to_vblank = getXvAttribute(h, attrs->port, "XV_SYNC_TO_VBLANK"); - attrs->defaults = getXvAttribute(xv, attrs->port, + attrs->defaults = getXvAttribute(h, attrs->port, "XV_SET_DEFAULTS"); if (!attrs->sync_to_vblank || !attrs->defaults) { @@ -247,13 +340,16 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) nv_warning_msg("libXv setup warning: %s\n", warn_str); } if (xv != NULL) { - if ( xv->dpy != NULL ) { - XCloseDisplay(xv->dpy); + if (xv->overlay) { + free(xv->overlay); } - if (xv->libXv) { - dlclose(xv->libXv); + if (xv->texture) { + free(xv->texture); } - free (xv); + if (xv->blitter) { + free(xv->blitter); + } + free(xv); } return NULL; @@ -262,7 +358,6 @@ NvCtrlXvAttributes * NvCtrlInitXvAttributes(NvCtrlAttributePrivateHandle *h) - ReturnStatus NvCtrlXvGetAttribute(NvCtrlAttributePrivateHandle *h, int attr, int *val) { @@ -288,7 +383,7 @@ ReturnStatus NvCtrlXvGetAttribute(NvCtrlAttributePrivateHandle *h, /* finally, query the value */ - if (h->xv->XvGetPortAttribute(h->xv->dpy, port, a->atom, val) != Success) { + if (__libXv->XvGetPortAttribute(h->dpy, port, a->atom, val) != Success) { return NvCtrlError; } @@ -320,11 +415,11 @@ ReturnStatus NvCtrlXvSetAttribute(NvCtrlAttributePrivateHandle *h, /* finally, set the value */ - if (h->xv->XvSetPortAttribute(h->xv->dpy, port, a->atom, val) != Success) { + if (__libXv->XvSetPortAttribute(h->dpy, port, a->atom, val) != Success) { return NvCtrlError; } - XFlush(h->xv->dpy); + XFlush(h->dpy); return NvCtrlSuccess; @@ -367,7 +462,7 @@ NvCtrlXvGetValidAttributeValues(NvCtrlAttributePrivateHandle *h, int attr, * NvCtrlXvAttribute struct if successful, otherwise return NULL. */ -static NvCtrlXvAttribute *getXvAttribute(NvCtrlXvAttributes *xv, +static NvCtrlXvAttribute *getXvAttribute(NvCtrlAttributePrivateHandle *h, XvPortID port, const char *name) { @@ -375,7 +470,7 @@ static NvCtrlXvAttribute *getXvAttribute(NvCtrlXvAttributes *xv, XvAttribute *attributes = NULL; int i, n; - attributes = xv->XvQueryPortAttributes(xv->dpy, port, &n); + attributes = __libXv->XvQueryPortAttributes(h->dpy, port, &n); if (!attributes || !n) goto failed; @@ -386,7 +481,7 @@ static NvCtrlXvAttribute *getXvAttribute(NvCtrlXvAttributes *xv, attr->range.type = ATTRIBUTE_TYPE_RANGE; attr->range.u.range.min = attributes[i].min_value; attr->range.u.range.max = attributes[i].max_value; - attr->atom = XInternAtom(xv->dpy, name, True); + attr->atom = XInternAtom(h->dpy, name, True); if (attr->atom == None) goto failed; if (! (attributes[i].flags & XvSettable)) goto failed; @@ -397,6 +492,10 @@ static NvCtrlXvAttribute *getXvAttribute(NvCtrlXvAttributes *xv, attr->range.permissions |= ATTRIBUTE_TYPE_READ; } + /* All Xv attributes are controlled with X screen target type */ + + attr->range.permissions |= ATTRIBUTE_TYPE_X_SCREEN; + break; } @@ -530,23 +629,16 @@ static NvCtrlXvAttribute *getXvAttributePtr(NvCtrlAttributePrivateHandle *h, /* * Frees and relinquishes any resource used by the Xv Attributes - * */ void NvCtrlXvAttributesClose (NvCtrlAttributePrivateHandle *h) { - if (h == NULL || h->xv == NULL) { + if (!h || !h->xv) { return; } - if (h->xv->dpy) { - XCloseDisplay(h->xv->dpy); - } - - if (h->xv->libXv) { - dlclose(h->xv->libXv); - } + close_libxv(); if (h->xv->overlay) { free(h->xv->overlay); diff --git a/src/nvidia-settings.c b/src/nvidia-settings.c index f0f9dd3..79e6f75 100644 --- a/src/nvidia-settings.c +++ b/src/nvidia-settings.c @@ -39,8 +39,9 @@ int main(int argc, char **argv) ConfigProperties conf; ParsedAttribute *p; CtrlHandles *h; + NvCtrlAttributeHandle **handles; Options *op; - int ret; + int ret, i, num_handles; /* * initialize the ui @@ -89,16 +90,34 @@ int main(int argc, char **argv) return 1; } + /* + * pull the screens' 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; + } + } else { + handles = NULL; + } + /* pass control to the gui */ - ctk_main(h->h, h->num_screens, p, &conf); - + ctk_main(handles, num_handles, p, &conf); + /* write the configuration file */ nv_write_config_file(op->config, h, p, &conf); /* cleanup */ + if (handles) free(handles); nv_free_ctrl_handles(h); nv_parsed_attribute_free(p); diff --git a/src/parse.c b/src/parse.c index d892898..d681736 100644 --- a/src/parse.c +++ b/src/parse.c @@ -35,6 +35,8 @@ /* local helper functions */ +static int nv_parse_display_and_target(char *start, char *end, + ParsedAttribute *a); static char **nv_strtok(char *s, char c, int *n); static void nv_free_strtoks(char **s, int n); static int ctoi(const char c); @@ -48,12 +50,16 @@ static char *nv_strndup(char *s, int n); * attribute. */ -#define F NV_PARSER_TYPE_FRAMELOCK +#define F NV_PARSER_TYPE_FRAMELOCK #define C NV_PARSER_TYPE_COLOR_ATTRIBUTE #define N NV_PARSER_TYPE_NO_CONFIG_WRITE #define G NV_PARSER_TYPE_GUI_ATTRIUBUTE #define V NV_PARSER_TYPE_XVIDEO_ATTRIBUTE #define P NV_PARSER_TYPE_PACKED_ATTRIBUTE +#define D NV_PARSER_TYPE_VALUE_IS_DISPLAY +#define A NV_PARSER_TYPE_NO_QUERY_ALL +#define Z NV_PARSER_TYPE_NO_ZERO_VALUE + AttributeTableEntry attributeTable[] = { @@ -81,6 +87,7 @@ AttributeTableEntry attributeTable[] = { { "TwinView", NV_CTRL_TWINVIEW, 0 }, { "ConnectedDisplays", NV_CTRL_CONNECTED_DISPLAYS, 0 }, { "EnabledDisplays", NV_CTRL_ENABLED_DISPLAYS, 0 }, + { "ProbeDisplays", NV_CTRL_PROBE_DISPLAYS, A }, { "ForceGenericCpu", NV_CTRL_FORCE_GENERIC_CPU, 0 }, { "GammaCorrectedAALines", NV_CTRL_OPENGL_AA_LINE_GAMMA, 0 }, { "ShowSLIHUD", NV_CTRL_SHOW_SLI_HUD, 0 }, @@ -93,12 +100,28 @@ AttributeTableEntry attributeTable[] = { { "CursorShadowBlue", NV_CTRL_CURSOR_SHADOW_BLUE, 0 }, { "FSAAAppControlled", NV_CTRL_FSAA_APPLICATION_CONTROLLED, 0 }, { "LogAnisoAppControlled", NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED,0 }, - { "FrameLockMaster", NV_CTRL_FRAMELOCK_MASTER, N|F|G }, - { "FrameLockPolarity", NV_CTRL_FRAMELOCK_POLARITY, N|F|G }, + { "RefreshRate", NV_CTRL_REFRESH_RATE, 0 }, + + { "FrameLockMaster", NV_CTRL_FRAMELOCK_MASTER, N|F|G|D }, + { "FrameLockSlaves", NV_CTRL_FRAMELOCK_SLAVES, N|F|G|D }, + { "FramelockUseHouseSync", NV_CTRL_USE_HOUSE_SYNC, N|F|G }, + { "FrameLockSyncInterval", NV_CTRL_FRAMELOCK_SYNC_INTERVAL, N|F|G }, + { "FrameLockPolarity", NV_CTRL_FRAMELOCK_POLARITY, N|F|G }, + { "FrameLockVideoMode", NV_CTRL_FRAMELOCK_VIDEO_MODE, N|F|G }, { "FrameLockSyncDelay", NV_CTRL_FRAMELOCK_SYNC_DELAY, N|F|G }, { "FrameLockEnable", NV_CTRL_FRAMELOCK_SYNC, N|F|G }, - { "FrameLockSyncInterval", NV_CTRL_FRAMELOCK_SYNC_INTERVAL, N|F|G }, - { "FrameLockHouseFormat", NV_CTRL_FRAMELOCK_VIDEO_MODE, N|F|G }, + { "FrameLockAvailable", NV_CTRL_FRAMELOCK, N|F|G }, + { "FrameLockPort0Status", NV_CTRL_FRAMELOCK_PORT0_STATUS, N|F|G }, + { "FrameLockPort1Status", NV_CTRL_FRAMELOCK_PORT1_STATUS, N|F|G }, + { "FrameLockHouseStatus", NV_CTRL_FRAMELOCK_HOUSE_STATUS, N|F|G }, + { "FrameLockSyncReady", NV_CTRL_FRAMELOCK_SYNC_READY, N|F|G }, + { "FrameLockStereoSync", NV_CTRL_FRAMELOCK_STEREO_SYNC, N|F|G }, + { "FrameLockTestSignal", NV_CTRL_FRAMELOCK_TEST_SIGNAL, N|F|G }, + { "FrameLockEthDetected", NV_CTRL_FRAMELOCK_ETHERNET_DETECTED, N|F|G }, + { "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 }, + { "Brightness", BRIGHTNESS_VALUE|ALL_CHANNELS, N|C|G }, { "RedBrightness", BRIGHTNESS_VALUE|RED_CHANNEL, C|G }, { "GreenBrightness", BRIGHTNESS_VALUE|GREEN_CHANNEL, C|G }, @@ -119,7 +142,6 @@ AttributeTableEntry attributeTable[] = { { "TVSaturation", NV_CTRL_TV_SATURATION, 0 }, { "GPUCoreTemp", NV_CTRL_GPU_CORE_TEMPERATURE, N }, { "GPUAmbientTemp", NV_CTRL_AMBIENT_TEMPERATURE, N }, - { "FramelockUseHouseSync", NV_CTRL_USE_HOUSE_SYNC, 0 }, { "OpenGLImageSettings", NV_CTRL_IMAGE_SETTINGS, 0 }, { "XVideoOverlaySaturation", NV_CTRL_ATTR_XV_OVERLAY_SATURATION, V }, @@ -128,7 +150,7 @@ AttributeTableEntry attributeTable[] = { { "XVideoOverlayHue", NV_CTRL_ATTR_XV_OVERLAY_HUE, V }, { "XVideoTextureSyncToVBlank", NV_CTRL_ATTR_XV_TEXTURE_SYNC_TO_VBLANK, V }, { "XVideoBlitterSyncToVBlank", NV_CTRL_ATTR_XV_BLITTER_SYNC_TO_VBLANK, V }, - { "XVideoSyncToDisplay", NV_CTRL_XV_SYNC_TO_DISPLAY, 0 }, + { "XVideoSyncToDisplay", NV_CTRL_XV_SYNC_TO_DISPLAY, D|Z }, { "GPUOverclockingState", NV_CTRL_GPU_OVERCLOCKING_STATE, N }, { "GPUDefault2DClockFreqs", NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS, N|P }, @@ -146,6 +168,9 @@ AttributeTableEntry attributeTable[] = { #undef G #undef V #undef P +#undef D +#undef A + /* * When new integer attributes are added to NVCtrl.h, an entry should @@ -154,11 +179,45 @@ AttributeTableEntry attributeTable[] = { * about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_XV_SYNC_TO_DISPLAY +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_REFRESH_RATE #warning "Have you forgotten to add a new integer attribute to attributeTable?" #endif + +/* + * targetTypeTable[] - this table stores an association of the values + * for each attribute target type. + */ + +TargetTypeEntry targetTypeTable[] = { + + { "X Screen", /* name */ + "screen", /* parsed_name */ + X_SCREEN_TARGET, /* target_index */ + NV_CTRL_TARGET_TYPE_X_SCREEN, /* nvctrl */ + ATTRIBUTE_TYPE_X_SCREEN, /* permission_bit */ + NV_TRUE }, /* uses_display_devices */ + + { "GPU", /* name */ + "gpu", /* parsed_name */ + GPU_TARGET, /* target_index */ + NV_CTRL_TARGET_TYPE_GPU, /* nvctrl */ + ATTRIBUTE_TYPE_GPU, /* permission_bit */ + NV_TRUE }, /* uses_display_devices */ + + { "Frame Lock Device", /* name */ + "framelock", /* parsed_name */ + FRAMELOCK_TARGET, /* target_index */ + NV_CTRL_TARGET_TYPE_FRAMELOCK, /* nvctrl */ + ATTRIBUTE_TYPE_FRAMELOCK, /* permission_bit */ + NV_FALSE }, /* uses_display_devices */ + + { NULL, NULL, 0, 0, 0 }, +}; + + + /* * nv_parse_attribute_string() - see comments in parse.h */ @@ -168,7 +227,7 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a) char *s, *tmp, *name, *start, *display_device_name, *no_spaces = NULL; char tmpname[NV_PARSER_MAX_NAME_LEN]; AttributeTableEntry *t; - int len, digits_only; + int len, ret; #define stop(x) { if (no_spaces) free(no_spaces); return (x); } @@ -192,38 +251,16 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a) /* * If we found a DISPLAY_NAME_SEPARATOR, and there is some text - * before it, it is either a screen number (if all characters - * between no_spaces and s are digits), or a display name. + * before it, parse that text as an X Display name, X screen, + * and/or a target specification. */ if ((s) && (s != no_spaces)) { - /* are all characters numeric? */ + ret = nv_parse_display_and_target(no_spaces, s, a); - digits_only = NV_TRUE; - a->screen = 0; - for (tmp = no_spaces; tmp != s; tmp++) { - if (!isdigit(*tmp)) { - digits_only = NV_FALSE; - a->screen = 0; - } - a->screen *= 10; - a->screen += ctoi(*tmp); - } - - if (digits_only) { - a->display = NULL; - a->flags |= NV_PARSER_HAS_X_SCREEN; - } else { - a->display = nv_strndup(no_spaces, s - no_spaces); - a->flags |= NV_PARSER_HAS_X_DISPLAY; - - /* - * this will attempt to parse out any screen number from the - * display name - */ - - nv_assign_default_display(a, NULL); + if (ret != NV_PARSER_STATUS_SUCCESS) { + stop(ret); } } @@ -313,6 +350,188 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a) /* + * nv_parse_display_and_target() - helper function for + * nv_parse_attribute_string() to parse all the text before the + * DISPLAY_NAME_SEPARATOR. This text is expected to be an X Display + * name, just an X screen, and/or a target specification. + */ + +static int nv_parse_display_and_target(char *start, + char *end, /* exclusive */ + ParsedAttribute *a) +{ + int digits_only, i, target_type, target_id, len; + char *tmp, *s, *pOpen, *pClose, *colon; + + /* + * are all characters numeric? compute the target_id integer as we + * scan the string to check + */ + + digits_only = NV_TRUE; + target_id = 0; + + for (s = start; s < end; s++) { + if (!isdigit(*s)) { + digits_only = NV_FALSE; + break; + } + target_id = (target_id * 10) + ctoi(*s); + } + + /* + * if all characters are numeric, assume the target type is + * X_SCREEN, and build the target_id; we have no X Display name in + * this case. + */ + + if (digits_only) { + a->display = NULL; + a->flags &= ~NV_PARSER_HAS_X_DISPLAY; + a->flags |= NV_PARSER_HAS_TARGET; + a->target_id = target_id; + a->target_type = NV_CTRL_TARGET_TYPE_X_SCREEN; + + /* we are done */ + + return NV_PARSER_STATUS_SUCCESS; + } + + /* + * if we get here, then there are non-digit characters; look for a + * pair of brackets, and treat the contents as a target + * specification. + */ + + pOpen = pClose = NULL; + + for (s = start; s < end; s++) { + if (*s == '[') pOpen = s; + if (*s == ']') pClose = s; + } + + if (pOpen && pClose && (pClose > pOpen) && ((pClose - pOpen) > 1)) { + + /* + * we have a pair of brackets and something inside the + * brackets, pull that into a temporary string. + */ + + len = pClose - pOpen - 1; + + tmp = nv_strndup(pOpen + 1, len); + + /* find the colon within the temp string */ + + colon = strchr(tmp, ':'); + + /* no colon? give up */ + + if (!colon) { + free(tmp); + return NV_PARSER_STATUS_TARGET_SPEC_NO_COLON; + } + + /* + * check that what is between the opening bracket and the + * colon is a target type name + */ + + *colon = '\0'; + target_type = -1; + + for (i = 0; targetTypeTable[i].name; i++) { + if (nv_strcasecmp(tmp, targetTypeTable[i].parsed_name)) { + target_type = targetTypeTable[i].nvctrl; + break; + } + } + + *colon = ':'; + + /* if we did not find a matching target name, give up */ + + if (target_type == -1) { + free(tmp); + return NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET; + } + + /* + * check that we have something between the colon and the end + * of the temp string + */ + + if ((colon + 1 - tmp) >= len) { + free(tmp); + return NV_PARSER_STATUS_TARGET_SPEC_NO_TARGET_ID; + } + + /* + * everything after the colon should be numeric; assign it to + * the target_id + */ + + target_id = 0; + + for (s = colon + 1; *s; s++) { + if (!isdigit(*s)) { + free(tmp); + return NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET_ID; + } + target_id = (target_id * 10) + ctoi(*s); + } + + a->target_type = target_type; + a->target_id = target_id; + + a->flags |= NV_PARSER_HAS_TARGET; + + /* we're finally done with the temp string */ + + free(tmp); + + /* + * check that there is no stray text between the closing + * bracket and the end of our parsable string + */ + + if ((end - pClose) > 1) { + return NV_PARSER_STATUS_TARGET_SPEC_TRAILING_GARBAGE; + } + + /* + * make end now point at the start of the bracketed target + * info for the X Display name processing below + */ + + end = pOpen; + } + + + /* treat everything between start and end as an X Display name */ + + if (start < end) { + + a->display = nv_strndup(start, end - start); + a->flags |= NV_PARSER_HAS_X_DISPLAY; + + /* + * this will attempt to parse out any screen number from the + * display name + */ + + nv_assign_default_display(a, NULL); + } + + /* done */ + + return NV_PARSER_STATUS_SUCCESS; + +} /* nv_parse_display_and_target() */ + + + +/* * nv_parse_strerror() - given the error status returned by * nv_parse_attribute_string(), return a string describing the * error. @@ -343,6 +562,17 @@ char *nv_parse_strerror(int status) return "Unrecognized attribute name"; break; case NV_PARSER_STATUS_MISSING_COMMA: return "Missing comma in packed integer value"; break; + case NV_PARSER_STATUS_TARGET_SPEC_NO_COLON: + return "No colon in target specification"; break; + case NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET: + return "Bad target in target specification"; break; + case NV_PARSER_STATUS_TARGET_SPEC_NO_TARGET_ID: + return "No target ID in target specification"; break; + case NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET_ID: + return "Bad target ID in target specification"; break; + case NV_PARSER_STATUS_TARGET_SPEC_TRAILING_GARBAGE: + return "Trailing garbage after target specification"; break; + default: return "Unknown error"; break; } @@ -477,9 +707,8 @@ uint32 display_device_name_to_display_device_mask(const char *str) /* * display_device_mask_to_display_name() - construct a string * describing the given display device mask. The returned pointer - * points to a global character buffer, so subsequent calls to - * display_device_mask_to_display_device_name() will clobber the - * contents. + * points to a newly allocated string, so callers to this function + * are responsible for freeing the memory. */ #define DISPLAY_DEVICE_STRING_LEN 256 @@ -587,6 +816,7 @@ uint32 expand_display_device_mask_wildcards(const uint32 d, const uint32 e) void nv_assign_default_display(ParsedAttribute *a, const char *display) { char *colon, *dot, *s; + int digits_only; if (!(a->flags & NV_PARSER_HAS_X_DISPLAY)) { if (display) a->display = strdup(display); @@ -594,18 +824,33 @@ void nv_assign_default_display(ParsedAttribute *a, const char *display) a->flags |= NV_PARSER_HAS_X_DISPLAY; } - if (!(a->flags & NV_PARSER_HAS_X_SCREEN) && a->display) { + if (!(a->flags & NV_PARSER_HAS_TARGET) && a->display) { colon = strchr(a->display, ':'); if (colon) { dot = strchr(colon, '.'); if (dot) { - a->screen = 0; - s = dot + 1; - while (*s && isdigit(*s)) { - a->screen *= 10; - a->screen += ctoi(*s); - a->flags |= NV_PARSER_HAS_X_SCREEN; - s++; + + /* + * if all characters afer the '.' are digits, + * interpret it as a screen number. + */ + + digits_only = NV_FALSE; + a->target_id = 0; + + for (s = dot + 1; *s; s++) { + if (isdigit(*s)) { + digits_only = NV_TRUE; + a->target_id = (a->target_id * 10) + ctoi(*s); + } else { + digits_only = NV_FALSE; + break; + } + } + + if (digits_only) { + a->target_type = NV_CTRL_TARGET_TYPE_X_SCREEN; + a->flags |= NV_PARSER_HAS_TARGET; } } } @@ -651,7 +896,8 @@ void nv_parsed_attribute_add(ParsedAttribute *head, ParsedAttribute *a) if (a->display) t->display = strdup(a->display); else t->display = NULL; - t->screen = a->screen; + t->target_type = a->target_type; + t->target_id = a->target_id; t->attr = a->attr; t->val = a->val; t->fval = a->fval; @@ -717,6 +963,15 @@ char *nv_get_attribute_name(const int attr) } /* nv_get_attribute_name() */ + +/* + * nv_standardize_screen_name() - standardize the X Display name, by + * inserting the hostname (if necessary), and using the specified + * screen number. If 'screen' is -1, use the screen number already in + * the string. If 'screen' is -2, do not put a screen number in the + * Display name. + */ + char *nv_standardize_screen_name(const char *orig, int screen) { char *display_name, *screen_name, *colon, *dot, *tmp; @@ -775,15 +1030,24 @@ char *nv_standardize_screen_name(const char *orig, int screen) dot = strchr(colon, '.'); if (dot) *dot = '\0'; + + /* + * if the screen parameter is -2, then do not write out a screen + * number. + */ - len = strlen(display_name) + 8; - screen_name = malloc(len); - snprintf(screen_name, len, "%s.%d", display_name, screen); - - free(display_name); + if (screen == -2) { + screen_name = display_name; + } else { + len = strlen(display_name) + 8; + screen_name = malloc(len); + snprintf(screen_name, len, "%s.%d", display_name, screen); + free(display_name); + } return (screen_name); -} + +} /* nv_standardize_screen_name() */ diff --git a/src/parse.h b/src/parse.h index ccff17f..d12c7b6 100644 --- a/src/parse.h +++ b/src/parse.h @@ -35,7 +35,7 @@ */ #define NV_PARSER_HAS_X_DISPLAY (1<<0) -#define NV_PARSER_HAS_X_SCREEN (1<<2) +#define NV_PARSER_HAS_TARGET (1<<2) #define NV_PARSER_HAS_DISPLAY_DEVICE (1<<3) #define NV_PARSER_HAS_VAL (1<<4) @@ -49,6 +49,9 @@ #define NV_PARSER_TYPE_GUI_ATTRIUBUTE (1<<19) #define NV_PARSER_TYPE_XVIDEO_ATTRIBUTE (1<<20) #define NV_PARSER_TYPE_PACKED_ATTRIBUTE (1<<21) +#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_ASSIGNMENT 0 #define NV_PARSER_QUERY 1 @@ -62,17 +65,23 @@ * error codes returned by nv_parse_attribute_string(). */ -#define NV_PARSER_STATUS_SUCCESS 0 -#define NV_PARSER_STATUS_BAD_ARGUMENT 1 -#define NV_PARSER_STATUS_EMPTY_STRING 2 -#define NV_PARSER_STATUS_ATTR_NAME_TOO_LONG 3 -#define NV_PARSER_STATUS_ATTR_NAME_MISSING 4 -#define NV_PARSER_STATUS_BAD_DISPLAY_DEVICE 5 -#define NV_PARSER_STATUS_MISSING_EQUAL_SIGN 6 -#define NV_PARSER_STATUS_NO_VALUE 7 -#define NV_PARSER_STATUS_TRAILING_GARBAGE 8 -#define NV_PARSER_STATUS_UNKNOWN_ATTR_NAME 9 -#define NV_PARSER_STATUS_MISSING_COMMA 10 +#define NV_PARSER_STATUS_SUCCESS 0 +#define NV_PARSER_STATUS_BAD_ARGUMENT 1 +#define NV_PARSER_STATUS_EMPTY_STRING 2 +#define NV_PARSER_STATUS_ATTR_NAME_TOO_LONG 3 +#define NV_PARSER_STATUS_ATTR_NAME_MISSING 4 +#define NV_PARSER_STATUS_BAD_DISPLAY_DEVICE 5 +#define NV_PARSER_STATUS_MISSING_EQUAL_SIGN 6 +#define NV_PARSER_STATUS_NO_VALUE 7 +#define NV_PARSER_STATUS_TRAILING_GARBAGE 8 +#define NV_PARSER_STATUS_UNKNOWN_ATTR_NAME 9 +#define NV_PARSER_STATUS_MISSING_COMMA 10 +#define NV_PARSER_STATUS_TARGET_SPEC_NO_COLON 11 +#define NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET 12 +#define NV_PARSER_STATUS_TARGET_SPEC_NO_TARGET_ID 13 +#define NV_PARSER_STATUS_TARGET_SPEC_BAD_TARGET_ID 14 +#define NV_PARSER_STATUS_TARGET_SPEC_TRAILING_GARBAGE 15 + /* * define useful types @@ -96,13 +105,14 @@ typedef struct _AttributeTableEntry { /* * ParsedAttribute - struct filled out by - * nv_ParseAttributeString(). + * nv_parse_attribute_string(). */ typedef struct _ParsedAttribute { char *display; char *name; - int screen; + int target_type; + int target_id; int attr; int val; float fval; /* XXX put in a union with val? */ @@ -119,6 +129,45 @@ typedef struct _ParsedAttribute { extern AttributeTableEntry attributeTable[]; + +/* + * Indices into CtrlHandles->targets[] array; stored in + * TargetTypeEntry.target_index. + */ + +#define X_SCREEN_TARGET 0 +#define GPU_TARGET 1 +#define FRAMELOCK_TARGET 2 +#define MAX_TARGET_TYPES 3 + + + +/* + * TargetTypeEntry - an array of these structures defines the values + * associated with each target type. + */ + +typedef struct { + char *name; /* string describing the TargetType */ + char *parsed_name; /* name used by parser */ + int target_index; /* index into the CtrlHandles->targets[] array */ + int nvctrl; /* NV-CONTROL target type value (NV_CTRL_TARGET_TYPE) */ + + /* flag set in NVCTRLAttributeValidValuesRec.permissions */ + unsigned int permission_bit; + + /* whether this target type is aware of display devices */ + int uses_display_devices; + +} TargetTypeEntry; + + +/* + * TargetType table; defined in parse.c + */ + +extern TargetTypeEntry targetTypeTable[]; + /* * nv_parse_attribute_string() - this function parses an attribute * string, the syntax for which is: @@ -133,6 +182,17 @@ extern AttributeTableEntry attributeTable[]; * {screen}/ may be specified by itself (ie: without the * "{host}:{display}." part). * + * Additionally, instead of specifying a screen, a target + * specification (target type and id) may be given in brackets: + * + * [{target-type}:{target-id}]/{attribute name}... + * + * This can be used in place of "{screen}" when it is used by itself + * on the left of the "/"; or, it can take the place of ".{screen}" + * when used along with an X Display name: + * + * {host}:{display}[{target-type}:{target-id}]/{attribute name}... + * * {attribute name} should be a string without any whitespace (a case * insensitive compare will be done to find a match in the * attributeTable in parse.c). {value} should be an integer. diff --git a/src/query-assign.c b/src/query-assign.c index ed89298..2ff1de4 100644 --- a/src/query-assign.c +++ b/src/query-assign.c @@ -44,11 +44,12 @@ static int process_attribute_queries(int, char**, const char *); static int process_attribute_assignments(int, char**, const char *); static int query_all(const char *); +static int query_all_targets(const char *display_name, const int target_index); static void print_valid_values(char *, uint32, NVCTRLAttributeValidValuesRec); -static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d, - int screen, char *whence); +static int validate_value(CtrlHandleTarget *t, ParsedAttribute *a, uint32 d, + int target_type, char *whence); /* * nv_process_assignments_and_queries() - process any assignments or @@ -80,92 +81,174 @@ int nv_process_assignments_and_queries(Options *op) /* - * nv_get_enabled_display_devices() - allocate an array of unsigned - * ints of length n, and query the X server for each screen's enabled - * display device mask, saving each X screen's display mask into the - * appropriate index in the array. - * - * This is just an optimization to avoid redundant round trips to the - * X server later in NvCtrlProcessParsedAttribute(). - * - * On success a freshly malloc'ed array of length n is returned (it is - * the caller's responsibility to free this memory). On error an - * error message is printed and NULL is returned. - */ - -uint32 *nv_get_enabled_display_devices(int n, NvCtrlAttributeHandle **h) -{ - ReturnStatus status; - int *d, screen; - - d = malloc(sizeof(int) * n); - - for (screen = 0; screen < n; screen++) { - if (!h[screen]) { - d[screen] = 0x0; - continue; - } - - status = NvCtrlGetAttribute(h[screen], NV_CTRL_ENABLED_DISPLAYS, - &d[screen]); - if (status != NvCtrlSuccess) { - nv_error_msg("Error querying enabled displays on " - "screen %d (%s).", screen, - NvCtrlAttributesStrError(status)); - free(d); - return NULL; - } - } - - return (uint32 *)d; - -} /* nv_get_enabled_display_devices() */ - - - -/* * nv_alloc_ctrl_handles() - allocate a new CtrlHandles structure, * connect to the X server identified by display, and initialize an - * NvCtrlAttributeHandle for each X screen. + * NvCtrlAttributeHandle for each possible target (X screens, gpus, + * FrameLock devices). */ CtrlHandles *nv_alloc_ctrl_handles(const char *display) { - CtrlHandles *h; - int i; + ReturnStatus status; + CtrlHandles *h, *pQueryHandle = NULL; + NvCtrlAttributeHandle *handle; + int target, i, j, val, d, len; + char *tmp; - h = malloc(sizeof(CtrlHandles)); + /* allocate the CtrlHandles struct */ + + h = calloc(1, sizeof(CtrlHandles)); + + /* store any given X display name */ if (display) h->display = strdup(display); else h->display = NULL; + /* open the X display connection */ + h->dpy = XOpenDisplay(h->display); - if (h->dpy) { - - h->num_screens = ScreenCount(h->dpy); + if (!h->dpy) { + nv_error_msg("Cannot open display '%s'.", XDisplayName(h->display)); + return h; + } + + /* + * loop over each target type and setup the appropriate + * information + */ + + for (j = 0; targetTypeTable[j].name; j++) { - h->h = malloc(h->num_screens * sizeof(NvCtrlAttributeHandle *)); - h->screen_names = malloc(h->num_screens * sizeof(char *)); + /* extract the target index from the table */ - for (i = 0; i < h->num_screens; i++) { - h->h[i] = NvCtrlAttributeInit - (h->dpy, i, NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS); - h->screen_names[i] = NvCtrlGetDisplayName(h->h[i]); - } + target = targetTypeTable[j].target_index; + + /* + * get the number of targets of this type; if this is an X + * screen target, just use Xlib's ScreenCount() (note: to + * support Xinerama: we'll want to use + * NvCtrlQueryTargetCount() rather than ScreenCount()); for + * other target types, use NvCtrlQueryTargetCount(). + */ + + if (target == X_SCREEN_TARGET) { + + h->targets[target].n = ScreenCount(h->dpy); + + } else { + + /* + * note: pQueryHandle should be assigned below by a + * previous iteration of this loop; depends on X screen + * targets getting handled first + */ + + if (pQueryHandle) { + status = NvCtrlQueryTargetCount + (pQueryHandle, targetTypeTable[j].nvctrl, &val); + } else { + status = NvCtrlMissingExtension; + } - h->d = nv_get_enabled_display_devices(h->num_screens, h->h); + if (status != NvCtrlSuccess) { + nv_error_msg("Unable to determine number of NVIDIA " + "%ss on '%s'.", + targetTypeTable[j].name, + XDisplayName(h->display)); + val = 0; + } + + h->targets[target].n = val; + } + + /* if there are no targets of this type, skip */ + + if (h->targets[target].n == 0) continue; - } else { + /* allocate an array of CtrlHandleTarget's */ - nv_error_msg("Cannot open display '%s'.", XDisplayName(h->display)); + h->targets[target].t = + calloc(h->targets[target].n, sizeof(CtrlHandleTarget)); - h->num_screens = 0; - h->h = NULL; - h->d = NULL; - h->screen_names = NULL; - } + /* + * loop over all the targets of this type and setup the + * CtrlHandleTarget's + */ + + for (i = 0; i < h->targets[target].n; i++) { + + /* allocate the handle */ + + handle = NvCtrlAttributeInit(h->dpy, + targetTypeTable[j].nvctrl, i, + NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS); + + h->targets[target].t[i].h = handle; + + /* + * silently fail: this might happen if not all X screens + * are NVIDIA X screens + */ + + if (!handle) continue; + + /* + * get a name for this target; in the case of + * X_SCREEN_TARGET targets, just use the string returned + * from NvCtrlGetDisplayName(); for other target types, + * append a target specification. + */ + + tmp = NvCtrlGetDisplayName(handle); + + if (target == X_SCREEN_TARGET) { + h->targets[target].t[i].name = tmp; + } else { + len = strlen(tmp) + strlen(targetTypeTable[j].parsed_name) +16; + h->targets[target].t[i].name = malloc(len); + if (h->targets[target].t[i].name) { + snprintf(h->targets[target].t[i].name, len, "%s[%s:%d]", + tmp, targetTypeTable[j].parsed_name, i); + free(tmp); + } else { + h->targets[target].t[i].name = tmp; + } + } + + /* + * get the enabled display device mask; for X screens and + * GPUs we query NV-CONTROL; for anything else + * (framelock), we just assign this to 0. + */ + + if (targetTypeTable[j].uses_display_devices) { + + status = NvCtrlGetAttribute(handle, + NV_CTRL_ENABLED_DISPLAYS, &d); + + if (status != NvCtrlSuccess) { + nv_error_msg("Error querying enabled displays on " + "%s %d (%s).", targetTypeTable[j].name, i, + NvCtrlAttributesStrError(status)); + d = 0; + } + } else { + d = 0; + } + + h->targets[target].t[i].d = d; + + /* + * store this handle so that we can use it to query other + * target counts later + */ + + if (!pQueryHandle) pQueryHandle = handle; + } + } + return h; } /* nv_alloc_ctrl_handles() */ @@ -178,7 +261,7 @@ CtrlHandles *nv_alloc_ctrl_handles(const char *display) void nv_free_ctrl_handles(CtrlHandles *h) { - int i; + int i, j, target; if (!h) return; @@ -197,14 +280,21 @@ void nv_free_ctrl_handles(CtrlHandles *h) XCloseDisplay(h->dpy); h->dpy = NULL; - for (i = 0; i < h->num_screens; i++) { - NvCtrlAttributeClose(h->h[i]); - if (h->screen_names[i]) free(h->screen_names[i]); + for (j = 0; targetTypeTable[j].name; j++) { + + target = targetTypeTable[j].target_index; + + for (i = 0; i < h->targets[target].n; i++) { + + NvCtrlAttributeClose(h->targets[target].t[i].h); + + if (h->targets[target].t[i].name) { + free(h->targets[target].t[i].name); + } + } + + if (h->targets[target].t) free(h->targets[target].t); } - - if (h->d) free(h->d); - if (h->h) free(h->h); - if (h->screen_names) free(h->screen_names); } free(h); @@ -214,8 +304,8 @@ void nv_free_ctrl_handles(CtrlHandles *h) /* - * process_attribute_queries() - parse the list of queries, and - * call NvCtrlProcessParsedAttribute() to process each query. + * process_attribute_queries() - parse the list of queries, and call + * nv_ctrl_process_parsed_attribute() to process each query. * * If any errors are encountered, an error message is printed and * NV_FALSE is returned. Otherwise, NV_TRUE is returned. @@ -234,6 +324,10 @@ static int process_attribute_queries(int num, char **queries, val = NV_FALSE; + /* print a newline before we begin */ + + nv_msg(NULL, ""); + /* loop over each requested query */ for (query = 0; query < num; query++) { @@ -244,6 +338,24 @@ static int process_attribute_queries(int num, char **queries, query_all(display_name); continue; } + + /* special case the target type queries */ + + if (nv_strcasecmp(queries[query], "screens")) { + query_all_targets(display_name, X_SCREEN_TARGET); + continue; + } + + if (nv_strcasecmp(queries[query], "gpus")) { + query_all_targets(display_name, GPU_TARGET); + continue; + } + + if (nv_strcasecmp(queries[query], "framelocks")) { + query_all_targets(display_name, FRAMELOCK_TARGET); + continue; + } + /* call the parser to parse queries[query] */ @@ -272,6 +384,10 @@ static int process_attribute_queries(int num, char **queries, if (ret == NV_FALSE) goto done; + /* print a newline at the end */ + + nv_msg(NULL, ""); + } /* query */ val = NV_TRUE; @@ -306,6 +422,10 @@ static int process_attribute_assignments(int num, char **assignments, val = NV_FALSE; + /* print a newline before we begin */ + + nv_msg(NULL, ""); + /* loop over each requested assignment */ for (assignment = 0; assignment < num; assignment++) { @@ -340,6 +460,10 @@ static int process_attribute_assignments(int num, char **assignments, if (ret == NV_FALSE) goto done; + /* print a newline at the end */ + + nv_msg(NULL, ""); + } /* assignment */ val = NV_TRUE; @@ -357,17 +481,16 @@ static int process_attribute_assignments(int num, char **assignments, * attribute, and check that the value to be assigned is valid. */ -static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d, - int screen, char *whence) +static int validate_value(CtrlHandleTarget *t, ParsedAttribute *a, uint32 d, + int target_type, char *whence) { - int bad_val = NV_FALSE; + int i, bad_val = NV_FALSE; NVCTRLAttributeValidValuesRec valid; ReturnStatus status; char d_str[256]; char *tmp_d_str; - status = NvCtrlGetValidDisplayAttributeValues(h->h[screen], d, - a->attr, &valid); + status = NvCtrlGetValidDisplayAttributeValues(t->h, d, a->attr, &valid); if (status != NvCtrlSuccess) { nv_error_msg("Unable to query valid values for attribute %s (%s).", @@ -416,17 +539,29 @@ static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d, break; } + /* is this value available for this target type? */ + + for (i = 0; targetTypeTable[i].name; i++) { + if ((targetTypeTable[i].target_index == target_type) && + !(targetTypeTable[i].permission_bit & valid.permissions)) { + bad_val = NV_TRUE; + break; + } + } + + /* if the value is bad, print why */ + if (bad_val) { if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { nv_warning_msg("The value pair %d,%d for attribute '%s' (%s%s) " "specified %s is invalid.", a->val >> 16, a->val & 0xffff, - a->name, h->screen_names[screen], + a->name, t->name, d_str, whence); } else { nv_warning_msg("The value %d for attribute '%s' (%s%s) " "specified %s is invalid.", - a->val, a->name, h->screen_names[screen], + a->val, a->name, t->name, d_str, whence); } print_valid_values(a->name, a->flags, valid); @@ -446,7 +581,7 @@ static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d, static void print_valid_values(char *name, uint32 flags, NVCTRLAttributeValidValuesRec valid) { - int bit, first, last; + int bit, first, last, i, n; char str[256]; char *c; @@ -522,6 +657,24 @@ static void print_valid_values(char *name, uint32 flags, if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) { nv_msg(INDENT, "'%s' is display device specific.", name); } + + /* print the valid target types */ + + c = str; + n = 0; + + for (i = 0; targetTypeTable[i].name; i++) { + if (valid.permissions & targetTypeTable[i].permission_bit) { + if (n > 0) c += sprintf(c, ", "); + c += sprintf(c, targetTypeTable[i].name); + n++; + } + } + + if (n == 0) sprintf(c, "None"); + + nv_msg(INDENT, "'%s' can use the following target types: %s", + name, str); #undef INDENT @@ -549,6 +702,7 @@ static int query_all(const char *display_name) const char *fmt, *fmt_display; NVCTRLAttributeValidValuesRec valid; CtrlHandles *h; + CtrlHandleTarget *t; static const char *__fmt_str_int = "Attribute '%s' (screen: %s): %d."; @@ -567,11 +721,20 @@ static int query_all(const char *display_name) #define INDENT " " - for (screen = 0; screen < h->num_screens; screen++) { + /* + * For now, we only loop over X screen targets; we could loop over + * other target types, too, but that would likely be redundant + * with X screens. + */ + + for (screen = 0; screen < h->targets[X_SCREEN_TARGET].n; screen++) { + + t = &h->targets[X_SCREEN_TARGET].t[screen]; - if (!h->h[screen]) continue; + if (!t->h) continue; - nv_msg(NULL, "Attributes for %s:", h->screen_names[screen]); + nv_msg(NULL, "Attributes for %s:", t->name); + nv_msg(NULL, ""); for (entry = 0; attributeTable[entry].name; entry++) { @@ -581,34 +744,36 @@ static int query_all(const char *display_name) if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) continue; + /* skip attributes that shouldn't be queried here */ + + if (a->flags & NV_PARSER_TYPE_NO_QUERY_ALL) continue; + for (bit = 0; bit < 24; bit++) { mask = 1 << bit; - if ((h->d[screen] & mask) == 0x0) continue; + if ((t->d & mask) == 0x0) continue; - status = - NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask, - a->attr, &valid); + status = NvCtrlGetValidDisplayAttributeValues + (t->h, mask, a->attr, &valid); if (status == NvCtrlAttributeNotAvailable) goto exit_bit_loop; if (status != NvCtrlSuccess) { nv_error_msg("Error while querying valid values for " "attribute '%s' on %s (%s).", - a->name, h->screen_names[screen], + a->name, t->name, NvCtrlAttributesStrError(status)); goto exit_bit_loop; } - status = NvCtrlGetDisplayAttribute(h->h[screen], mask, - a->attr, &val); + status = NvCtrlGetDisplayAttribute(t->h, mask, a->attr, &val); if (status == NvCtrlAttributeNotAvailable) goto exit_bit_loop; if (status != NvCtrlSuccess) { nv_error_msg("Error while querying attribute '%s' " "on %s (%s).", - a->name, h->screen_names[screen], + a->name, t->name, NvCtrlAttributesStrError(status)); goto exit_bit_loop; } @@ -631,29 +796,33 @@ static int query_all(const char *display_name) if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { nv_msg(INDENT, fmt_display, a->name, - h->screen_names[screen], tmp_d_str, + t->name, tmp_d_str, val >> 16, val & 0xffff); } else { nv_msg(INDENT, fmt_display, a->name, - h->screen_names[screen], tmp_d_str, val); + 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, h->screen_names[screen], + nv_msg(INDENT, fmt, a->name, t->name, val >> 16, val & 0xffff); } else { - nv_msg(INDENT, fmt, a->name, h->screen_names[screen],val); + 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 */ } @@ -678,16 +847,125 @@ static int query_all(const char *display_name) /* - * process_parsed_attribute_internal() - this function does the - * actually attribute processing for NvCtrlProcessParsedAttribute(). + * query_all_targets() - print a list of all the targets (of the + * specified type) accessible via the Display connection. + */ + +static int query_all_targets(const char *display_name, const int target_index) +{ + CtrlHandles *h; + CtrlHandleTarget *t; + ReturnStatus status; + int i, table_index; + char *str, *name, *product_name; + + /* find the index into targetTypeTable[] for target_index */ + + table_index = -1; + + for (i = 0; targetTypeTable[i].name; i++) { + if (targetTypeTable[i].target_index == target_index) { + table_index = i; + break; + } + } + + if (table_index == -1) return NV_FALSE; + + /* create handles */ + + h = nv_alloc_ctrl_handles(display_name); + + /* build the standard X server name */ + + str = nv_standardize_screen_name(XDisplayName(h->display), -2); + + /* warn if we don't have any of the target type */ + + if (h->targets[target_index].n <= 0) { + + nv_warning_msg("No %ss on %s", + targetTypeTable[table_index].name, str); + + free(str); + nv_free_ctrl_handles(h); + return NV_FALSE; + } + + /* print how many of the target type we have */ + + nv_msg(NULL, "%d %s%s on %s", + h->targets[target_index].n, + targetTypeTable[table_index].name, + (h->targets[target_index].n > 1) ? "s" : "", + str); + nv_msg(NULL, ""); + + free(str); + + /* print information per target */ + + for (i = 0; i < h->targets[target_index].n; i++) { + + t = &h->targets[target_index].t[i]; + + str = NULL; + + if (target_index == FRAMELOCK_TARGET) { + + /* for framelock, create the product name */ + + product_name = malloc(32); + snprintf(product_name, 32, "G-Sync %d", i); + + } else { + + /* for X_SCREEN_TARGET or GPU_TARGET, query the product name */ + + status = NvCtrlGetStringAttribute + (t->h, NV_CTRL_STRING_PRODUCT_NAME, &product_name); + + if (status != NvCtrlSuccess) product_name = strdup("Unknown"); + + } + + /* + * use the name for the target handle, or "Unknown" if we + * don't have a target handle name (this can happen for a + * non-NVIDIA X screen) + */ + + if (t->name) { + name = t->name; + } else { + name = "Not NVIDIA"; + } + + nv_msg(" ", "[%d] %s (%s)", i, name, product_name); + nv_msg(NULL, ""); + + free(product_name); + } + + nv_free_ctrl_handles(h); + + return NV_TRUE; + +} /* query_all_targets() */ + + + +/* + * process_parsed_attribute_internal() - this function does the actual + * attribute processing for nv_process_parsed_attribute(). * * If an error occurs, an error message is printed and NV_FALSE is * returned; if successful, NV_TRUE is returned. */ -static int process_parsed_attribute_internal(CtrlHandles *h, +static int process_parsed_attribute_internal(CtrlHandleTarget *t, ParsedAttribute *a, uint32 d, - int screen, int assign, + int target_type, int assign, int verbose, char *whence, NVCTRLAttributeValidValuesRec valid) @@ -705,14 +983,15 @@ static int process_parsed_attribute_internal(CtrlHandles *h, } if (assign) { - ret = validate_value(h, a, d, screen, whence); + ret = validate_value(t, a, d, target_type, whence); if (!ret) return NV_FALSE; - status = NvCtrlSetDisplayAttribute(h->h[screen], d, a->attr, a->val); + status = NvCtrlSetDisplayAttribute(t->h, d, a->attr, a->val); + if (status != NvCtrlSuccess) { nv_error_msg("Error assigning value %d to attribute '%s' " "(%s%s) as specified %s (%s).", - a->val, a->name, h->screen_names[screen], str, whence, + a->val, a->name, t->name, str, whence, NvCtrlAttributesStrError(status)); return NV_FALSE; } @@ -720,37 +999,37 @@ static int process_parsed_attribute_internal(CtrlHandles *h, if (verbose) { if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d,%d.", - a->name, h->screen_names[screen], str, + a->name, t->name, str, a->val >> 16, a->val & 0xffff); } else { nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d.", - a->name, h->screen_names[screen], str, a->val); + a->name, t->name, str, a->val); } } } else { /* query */ - status = NvCtrlGetDisplayAttribute(h->h[screen], d, a->attr, &a->val); + status = NvCtrlGetDisplayAttribute(t->h, d, a->attr, &a->val); if (status == NvCtrlAttributeNotAvailable) { nv_warning_msg("Error querying attribute '%s' specified %s; " "'%s' is not available on %s%s.", a->name, whence, a->name, - h->screen_names[screen], str); + t->name, str); } else if (status != NvCtrlSuccess) { nv_error_msg("Error while querying attribute '%s' " "(%s%s) specified %s (%s).", - a->name, h->screen_names[screen], str, whence, + a->name, t->name, str, whence, NvCtrlAttributesStrError(status)); return NV_FALSE; } else { if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { nv_msg(" ", "Attribute '%s' (%s%s): %d,%d.", - a->name, h->screen_names[screen], str, + a->name, t->name, str, a->val >> 16, a->val & 0xffff); } else { nv_msg(" ", "Attribute '%s' (%s%s): %d.", - a->name, h->screen_names[screen], str, a->val); + a->name, t->name, str, a->val); } print_valid_values(a->name, a->flags, valid); } @@ -766,25 +1045,26 @@ static int process_parsed_attribute_internal(CtrlHandles *h, * nv_process_parsed_attribute() - this is the processing engine for * all parsed attributes. * - * A parsed attribute may or may not specify an X screen; if an X - * screen was specified, we validate that screen and process the - * attribute just for that screen. If a screen was not specified, we - * process the attribute for all valid screens. + * A parsed attribute may or may not specify a target (X screen, GPU, + * framelock device); if a target was specified, we validate that + * target and process the attribute just for that target. If a target + * was not specified, we process the attribute for all valid X + * screens. * * A parsed attribute may or may not specify one or more display * devices. For attributes that require that a display device be * specified: if a display device mask is specified, we validate it * and process the attribute just for the display devices in the mask. * If a display device mask was not specified, then we process the - * attribute for all enabled display devices on each of the screens + * attribute for all enabled display devices on each of the targets * that have been requested. * * "Processing" a parsed attribute means either querying for the - * current value of the attribute on all requested screens and display + * current value of the attribute on all requested targets and display * devices (see above), or assigning the attribute on all requested - * screens and display devices (see above). + * targets and display devices (see above). * - * The majority of the work (determining which screens, which display + * The majority of the work (determining which targets, which display * devices) is the same, regardless of what sort of processing we * actually need to do (thus this shared function). * @@ -796,14 +1076,14 @@ static int process_parsed_attribute_internal(CtrlHandles *h, * query). * * The CtrlHandles argument contains an array of - * NvCtrlAttributeHandle's (one per X screen on this X server), as - * well as the number of X screens, an array of enabled display - * devices for each screen, and a string description of each screen. + * NvCtrlAttributeHandle's (one for each target on this X server), as + * well as the number of targets, an array of enabled display devices + * for each target, and a string description of each target. * * The whence_fmt and following varargs are used by the callee to * describe where the attribute came from. A whence string should be * something like "on line 12 of config file ~/.nvidia-settings-rc" or - * "in query ':0.0/fsaa'". Whence is used in the case of error to + * "in query ':0.0/fsaa'". Whence is used in the case of an error to * indicate where the error came from. * * If successful, the processing determined by 'assign' and 'verbose' @@ -815,15 +1095,16 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, int assign, int verbose, char *whence_fmt, ...) { - int screen, start_screen, end_screen, bit, ret, val; - char *whence, *tmp_d_str0, *tmp_d_str1; + int i, target, start, end, bit, ret, val, target_type_index; + char *whence, *tmp_d_str0, *tmp_d_str1, *target_type_name; uint32 display_devices, mask; ReturnStatus status; NVCTRLAttributeValidValuesRec valid; - + CtrlHandleTarget *t; + val = NV_FALSE; - /* build the description */ + /* build the whence string */ NV_VSNPRINTF(whence, whence_fmt); @@ -838,61 +1119,118 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, goto done; } - /* if a screen was specified, make sure it is valid */ - - if (a->flags & NV_PARSER_HAS_X_SCREEN) { + /* + * if a target was specified, make sure it is valid, and setup + * the variables 'start', 'end', and 'target'. + */ + + if (a->flags & NV_PARSER_HAS_TARGET) { + + /* + * look up the target index for the target type specified in + * the ParsedAttribute + */ + + target = -1; + target_type_name = "?"; - if (a->screen >= h->num_screens) { - if (h->num_screens == 1) { - nv_error_msg("Invalid X screen %d specified %s " - "(there is only 1 screen on this Display).", - a->screen, whence); + for (i = 0; targetTypeTable[i].name; i++) { + if (targetTypeTable[i].nvctrl == a->target_type) { + target = targetTypeTable[i].target_index; + target_type_name = targetTypeTable[i].name; + break; + } + } + + if (target == -1) { + nv_error_msg("Invalid target specified %s.", whence); + goto done; + } + + /* make sure the target_id is in range */ + + if (a->target_id >= h->targets[target].n) { + + if (h->targets[target].n == 1) { + nv_error_msg("Invalid %s %d specified %s (there is only " + "1 %s on this Display).", + target_type_name, + a->target_id, whence, target_type_name); } else { - nv_error_msg("Invalid X screen %d specified %s " - "(there are only %d screens on this Display).", - a->screen, whence, h->num_screens); + nv_error_msg("Invalid %s %d specified %s " + "(there are only %d %ss on this Display).", + target_type_name, + a->target_id, whence, + h->targets[target].n, + target_type_name); } goto done; } + + /* + * make sure we have a handle for this target; missing a + * handle should only happen for X screens because not all X + * screens will be controlled by NVIDIA + */ - if (!h->h[a->screen]) { - nv_error_msg("Invalid screen %d specified %s " - "(NV-CONTROL extension not supported on " - "screen %d).", a->screen, whence, a->screen); + if (!h->targets[target].t[a->target_id].h) { + nv_error_msg("Invalid %s %d specified %s (NV-CONTROL extension " + "not supported on %s %d).", + target_type_name, + a->target_id, whence, + target_type_name, a->target_id); } /* - * assign start_screen and end_screen such that the screen - * loop only uses this screen. + * assign 'start' and 'end' such that the below loop only uses + * this target. */ - start_screen = a->screen; - end_screen = a->screen + 1; + start = a->target_id; + end = a->target_id + 1; + } else { /* - * no screen was specified; assign start_screen and end_screen - * such that we loop over all the screens + * no target was specified; assume a target type of + * X_SCREEN_TARGET, and assign 'start' and 'end' such that we + * loop over all the screens; we could potentially store the + * correct default target type for each attribute and default + * to that rather than assume X_SCREEN_TARGET. */ - start_screen = 0; - end_screen = h->num_screens; + target = X_SCREEN_TARGET; + start = 0; + end = h->targets[target].n; } - /* loop over the requested screens */ + /* find the target type index */ - for (screen = start_screen; screen < end_screen; screen++) { - - if (!h->h[screen]) continue; /* no handle on this screen; skip */ + target_type_index = 0; + + for (i = 0; targetTypeTable[i].name; i++) { + if (targetTypeTable[i].target_index == target) { + target_type_index = i; + break; + } + } + + /* loop over the requested targets */ + + for (i = start; i < end; i++) { + + t = &h->targets[target].t[i]; + + if (!t->h) continue; /* no handle on this target; silently skip */ if (a->flags & NV_PARSER_HAS_DISPLAY_DEVICE) { /* Expand any wildcards in the display device mask */ display_devices = expand_display_device_mask_wildcards - (a->display_device_mask, h->d[screen]); + (a->display_device_mask, t->d); - if ((display_devices == 0) || (display_devices & ~h->d[screen])) { + if ((display_devices == 0) || (display_devices & ~t->d)) { /* * use a->display_device_mask rather than @@ -903,14 +1241,12 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, tmp_d_str0 = display_device_mask_to_display_device_name (a->display_device_mask); - tmp_d_str1 = display_device_mask_to_display_device_name - (h->d[screen]); + tmp_d_str1 = display_device_mask_to_display_device_name(t->d); nv_error_msg("Invalid display device %s specified " "%s (the currently enabled display devices " "are %s on %s).", - tmp_d_str0, whence, tmp_d_str1, - h->screen_names[screen]); + tmp_d_str0, whence, tmp_d_str1, t->name); free(tmp_d_str0); free(tmp_d_str1); @@ -919,7 +1255,7 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, } else { - display_devices = h->d[screen]; + display_devices = t->d; } /* special case the color attributes */ @@ -939,11 +1275,12 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, v[0] = v[1] = v[2] = a->fval; - status = NvCtrlSetColorAttributes(h->h[screen], v, v, v, a->attr); + status = NvCtrlSetColorAttributes(t->h, v, v, v, a->attr); + if (status != NvCtrlSuccess) { nv_error_msg("Error assigning %f to attribute '%s' on %s " "specified %s (%s)", a->fval, a->name, - h->screen_names[screen], whence, + t->name, whence, NvCtrlAttributesStrError(status)); goto done; } @@ -951,23 +1288,138 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, continue; } + /* + * If we are assigning, and the value for this attribute is + * not allowed to be zero, check that the value is not zero. + */ + + if (assign && (a->flags & NV_PARSER_TYPE_NO_ZERO_VALUE)) { + + /* value must be non-zero */ + + if (!a->val) { + + if (a->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY) { + tmp_d_str0 = "display device"; + } else { + tmp_d_str0 = "value"; + } + + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned the value of 0 (a valid, non-zero, " + "%s must be specified).", + a->name, whence, tmp_d_str0); + continue; + } + } + + /* + * If we are assigning, and the value for this attribute is a + * display device, then we need to validate the value against + * the mask of enabled display devices. + */ + + if (assign && (a->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY)) { + + if ((t->d & a->val) != a->val) { + + tmp_d_str0 = + display_device_mask_to_display_device_name(a->val); + + tmp_d_str1 = display_device_mask_to_display_device_name(t->d); + + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned the value of %s (the currently enabled " + "display devices are %s on %s).", + a->name, whence, tmp_d_str0, tmp_d_str1, + t->name); + + free(tmp_d_str0); + free(tmp_d_str1); + + continue; + } + } + + /* + * If we are dealing with a frame lock attribute on a non-frame lock + * target type, make sure frame lock is available. + * + * Also, when setting frame lock attributes on non-frame lock targets, + * make sure frame lock is disabled. (Of course, don't check this for + * the "enable frame lock" attribute.) + */ + + if ((a->flags & NV_PARSER_TYPE_FRAMELOCK) && + (NvCtrlGetTargetType(t->h) != NV_CTRL_TARGET_TYPE_FRAMELOCK)) { + int available; + + status = NvCtrlGetAttribute(t->h, NV_CTRL_FRAMELOCK, &available); + if (status != NvCtrlSuccess) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "%s; error querying frame lock availablity on " + "%s (%s).", + a->name, whence, assign ? "assigned" : "queried", + t->name, NvCtrlAttributesStrError(status)); + continue; + } + + if (available != NV_CTRL_FRAMELOCK_SUPPORTED) { + nv_error_msg("The attribute '%s' specified %s cannot be %s; " + "frame lock is not supported/available on %s.", + a->name, whence, assign ? "assigned" : "queried", + t->name); + continue; + } + + /* Don't assign if frame lock is enabled */ + + if (assign && (a->attr != NV_CTRL_FRAMELOCK_SYNC)) { + int enabled; + + status = NvCtrlGetAttribute(t->h, NV_CTRL_FRAMELOCK_SYNC, + &enabled); + if (status != NvCtrlSuccess) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned; error querying frame lock sync " + "status on %s (%s).", + a->name, whence, t->name, + NvCtrlAttributesStrError(status)); + continue; + } + + if (enabled != NV_CTRL_FRAMELOCK_SYNC_DISABLE) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned; frame lock sync is currently " + "enabled on %s.", + a->name, whence, t->name); + continue; + } + } + } + + /* loop over the display devices */ + for (bit = 0; bit < 24; bit++) { mask = (1 << bit); - if ((mask & display_devices) == 0x0) continue; + if (((mask & display_devices) == 0x0) && + (targetTypeTable[target_type_index].uses_display_devices)) { + continue; + } - status = NvCtrlGetValidDisplayAttributeValues(h->h[screen], mask, + status = NvCtrlGetValidDisplayAttributeValues(t->h, mask, a->attr, &valid); if (status != NvCtrlSuccess) { - if(status == NvCtrlAttributeNotAvailable) { + if (status == NvCtrlAttributeNotAvailable) { nv_warning_msg("Attribute '%s' specified %s is not " "available on %s.", - a->name, whence, h->screen_names[screen]); + a->name, whence, t->name); } else { nv_error_msg("Error querying valid values for attribute " "'%s' on %s specified %s (%s).", - a->name, h->screen_names[screen], whence, + a->name, t->name, whence, NvCtrlAttributesStrError(status)); } goto done; @@ -985,17 +1437,25 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, goto done; } - ret = process_parsed_attribute_internal(h, a, mask, screen, - assign, verbose, - whence, valid); + ret = process_parsed_attribute_internal(t, a, mask, target, assign, + verbose, whence, valid); if (ret == NV_FALSE) goto done; - if (!(valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) bit = 25; + /* + * if this attribute is not per-display device, or this + * target does not know about display devices, then once + * through this loop is enough. + */ + + if ((!(valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) || + (!(targetTypeTable[target_type_index].uses_display_devices))) { + break; + } } /* bit */ - } /* screen */ - + } /* i - done looping over requested targets */ + val = NV_TRUE; done: diff --git a/src/query-assign.h b/src/query-assign.h index 286163f..38ee72f 100644 --- a/src/query-assign.h +++ b/src/query-assign.h @@ -37,25 +37,33 @@ /* - * The CtrlHandles struct contains an array of NvCtrlAttributeHandle's - * (one per X screen on this X server), as well as the number of X - * screens, an array of enabled display devices for each screen, and a - * string description of each screen. + * The CtrlHandles struct contains an array of target types for an X + * server. For each target type, we store the number of those targets + * on this X server. Per target, we store a NvCtrlAttributeHandle, a + * bitmask of what display devices are enabled on that target, and a + * string description of that target. */ typedef struct { - char *display; - Display *dpy; - int num_screens; - NvCtrlAttributeHandle **h; - uint32 *d; - char **screen_names; + NvCtrlAttributeHandle *h; /* handle for this target */ + uint32 d; /* display device mask for this target */ + char *name; /* name for this target */ +} CtrlHandleTarget; + +typedef struct { + int n; /* number of targets */ + CtrlHandleTarget *t; /* dynamically allocated array of targets */ +} CtrlHandleTargets; + +typedef struct { + char *display; /* string for XOpenDisplay */ + Display *dpy; /* X display connection */ + CtrlHandleTargets targets[MAX_TARGET_TYPES]; } CtrlHandles; int nv_process_assignments_and_queries(Options *op); -uint32 *nv_get_enabled_display_devices(int, NvCtrlAttributeHandle**); CtrlHandles *nv_alloc_ctrl_handles(const char *display); void nv_free_ctrl_handles(CtrlHandles *h); diff --git a/src/xpm_data/Makefile.inc b/src/xpm_data/Makefile.inc index 8930621..d50561d 100644 --- a/src/xpm_data/Makefile.inc +++ b/src/xpm_data/Makefile.inc @@ -28,12 +28,8 @@ EXTRA_DIST += \ blue_xpm.h \ green_xpm.h \ - led_green.h \ - led_grey.h \ - led_red.h \ mini_xpm.h \ red_xpm.h \ rgb_xpm.h \ - rj45_input.h \ - rj45_output.h \ x11_xpm.h + diff --git a/src/xpm_data/led_green.h b/src/xpm_data/led_green.h deleted file mode 100644 index 0ae1ae3..0000000 --- a/src/xpm_data/led_green.h +++ /dev/null @@ -1,210 +0,0 @@ -/* XPM */ -static const char * led_green_xpm[] = { -"20 20 187 2", -" c None", -". c #000000", -"+ c #030303", -"@ c #090C07", -"# c #36502D", -"$ c #547B48", -"% c #619152", -"& c #467039", -"* c #26421D", -"= c #030601", -"- c #080808", -"; c #405639", -"> c #85AA79", -", c #8CB281", -"' c #85AC79", -") c #729E65", -"! c #649455", -"~ c #598948", -"{ c #4A793C", -"] c #1D3516", -"^ c #0A0A0A", -"/ c #58704F", -"( c #9FBF94", -"_ c #AFC9A6", -": c #ABC7A2", -"< c #9CBC91", -"[ c #80A974", -"} c #69995A", -"| c #4E7E3F", -"1 c #487637", -"2 c #224019", -"3 c #040404", -"4 c #3E5439", -"5 c #9FC095", -"6 c #BCD2B5", -"7 c #C8D9C2", -"8 c #C0D3B8", -"9 c #A6C39C", -"0 c #89B07D", -"a c #679857", -"b c #558A45", -"c c #4D803D", -"d c #457736", -"e c #3F7030", -"f c #18300F", -"g c #0E110C", -"h c #88AD7C", -"i c #B5CEAD", -"j c #CDDDC8", -"k c #DFE8DB", -"l c #CCDCC7", -"m c #ADC8A5", -"n c #87AF7A", -"o c #669956", -"p c #518940", -"q c #4A8239", -"r c #447934", -"s c #3C6E2D", -"t c #346326", -"u c #020401", -"v c #3E5736", -"w c #9ABB8E", -"x c #BED3B6", -"y c #D2E0CD", -"z c #E4EDE2", -"A c #D1E0CD", -"B c #AAC6A1", -"C c #84AE77", -"D c #639653", -"E c #4D883B", -"F c #498235", -"G c #437930", -"H c #3A6F2A", -"I c #386827", -"J c #1A3411", -"K c #638657", -"L c #9BBC91", -"M c #B6CDAE", -"N c #C0D4B9", -"O c #C5D8BF", -"P c #B5CDAC", -"Q c #95B889", -"R c #7AA66B", -"S c #5C924B", -"T c #4B8639", -"U c #447F32", -"V c #40792E", -"W c #396E29", -"X c #386829", -"Y c #2F5623", -"Z c #6F9B62", -"` c #8FB384", -" . c #A1BF98", -".. c #A3C19A", -"+. c #A0BE95", -"@. c #92B687", -"#. c #80A972", -"$. c #679A57", -"%. c #528B40", -"&. c #478235", -"*. c #427D30", -"=. c #3F752C", -"-. c #427231", -";. c #4F7942", -">. c #517746", -",. c #567B4A", -"'. c #81A875", -"). c #8DB081", -"!. c #8BAF7E", -"~. c #76A269", -"{. c #679958", -"]. c #578C45", -"^. c #498437", -"/. c #417C2F", -"(. c #3E772C", -"_. c #417631", -":. c #57804B", -"<. c #719166", -"[. c #5A7651", -"}. c #334D2A", -"|. c #719964", -"1. c #799F6C", -"2. c #739D66", -"3. c #6C985D", -"4. c #5E904F", -"5. c #578A45", -"6. c #4B833A", -"7. c #427C31", -"8. c #3F782D", -"9. c #427831", -"0. c #537F46", -"a. c #74936A", -"b. c #829D7A", -"c. c #3E5336", -"d. c #040703", -"e. c #5B844F", -"f. c #679059", -"g. c #638E55", -"h. c #5C8B4E", -"i. c #588847", -"j. c #4D823D", -"k. c #477D36", -"l. c #427730", -"m. c #427732", -"n. c #568249", -"o. c #6F9065", -"p. c #87A07F", -"q. c #76916E", -"r. c #050704", -"s. c #253D1E", -"t. c #557F48", -"u. c #59824B", -"v. c #558148", -"w. c #4F7E41", -"x. c #4A7A3B", -"y. c #447734", -"z. c #477637", -"A. c #5B854E", -"B. c #76976C", -"C. c #85A07D", -"D. c #809A77", -"E. c #2F4429", -"F. c #2F4A27", -"G. c #4B723F", -"H. c #4A733E", -"I. c #4B753E", -"J. c #4B743D", -"K. c #4C763F", -"L. c #608554", -"M. c #77966D", -"N. c #7E9875", -"O. c #3B5433", -"P. c #203619", -"Q. c #436538", -"R. c #4E7142", -"S. c #587B4E", -"T. c #69865F", -"U. c #76926D", -"V. c #819A79", -"W. c #728D6A", -"X. c #2C4126", -"Y. c #030502", -"Z. c #2C4225", -"`. c #4F6A47", -" + c #6A8562", -".+ c #5E7756", -"++ c #374C2F", -" ", -" . . . . . ", -" + @ # $ % & * = . ", -" - ; > , ' ) ! ~ { ] . ", -" ^ / ( _ : < [ } ~ | 1 2 . ", -" 3 4 5 6 7 8 9 0 a b c d e f . ", -" g h i j k l m n o p q r s t u ", -" . v w x y z A B C D E F G H I J . ", -" . K L M N O P Q R S T U V W X Y . ", -" . Z ` ...+.@.#.$.%.&.*.=.-.;.>.. ", -" . ,.'.).!.[ ~.{.].^./.(._.:.<.[.. ", -" . }.|.1.2.3.4.5.6.7.8.9.0.a.b.c.. ", -" d.e.f.g.h.i.j.k.l.m.n.o.p.q.r. ", -" . s.t.u.v.w.x.y.z.A.B.C.D.E.. ", -" . F.G.H.I.J.K.L.M.p.N.O.. ", -" . P.Q.R.S.T.U.V.W.X.. ", -" . Y.Z.`. +.+++r.. ", -" . . . . . ", -" ", -" "}; diff --git a/src/xpm_data/led_grey.h b/src/xpm_data/led_grey.h deleted file mode 100644 index 4c6b68e..0000000 --- a/src/xpm_data/led_grey.h +++ /dev/null @@ -1,102 +0,0 @@ -/* XPM */ -static const char * led_grey_xpm[] = { -"20 20 79 1", -" c None", -". c #000000", -"+ c #030303", -"@ c #080808", -"# c #A0A0A0", -"$ c #B0B0B0", -"% c #B6B6B6", -"& c #A9A9A9", -"* c #999999", -"= c #020202", -"- c #A6A6A6", -"; c #C6C6C6", -"> c #CACACA", -", c #C7C7C7", -"' c #BFBFBF", -") c #B8B8B8", -"! c #B1B1B1", -"~ c #ABABAB", -"{ c #969696", -"] c #0A0A0A", -"^ c #D2D2D2", -"/ c #D9D9D9", -"( c #D8D8D8", -"_ c #D1D1D1", -": c #C5C5C5", -"< c #BABABA", -"[ c #ADADAD", -"} c #979797", -"| c #040404", -"1 c #D3D3D3", -"2 c #E0E0E0", -"3 c #E5E5E5", -"4 c #E1E1E1", -"5 c #D5D5D5", -"6 c #C9C9C9", -"7 c #B9B9B9", -"8 c #929292", -"9 c #0D0D0D", -"0 c #C8C8C8", -"a c #DDDDDD", -"b c #E8E8E8", -"c c #F0F0F0", -"d c #E7E7E7", -"e c #AFAFAF", -"f c #A5A5A5", -"g c #A1A1A1", -"h c #010101", -"i c #D0D0D0", -"j c #EAEAEA", -"k c #F3F3F3", -"l c #A7A7A7", -"m c #A4A4A4", -"n c #A2A2A2", -"o c #939393", -"p c #DCDCDC", -"q c #E4E4E4", -"r c #CDCDCD", -"s c #C1C1C1", -"t c #B4B4B4", -"u c #A8A8A8", -"v c #9F9F9F", -"w c #BDBDBD", -"x c #CCCCCC", -"y c #D4D4D4", -"z c #C4C4C4", -"A c #C0C0C0", -"B c #B2B2B2", -"C c #B5B5B5", -"D c #ACACAC", -"E c #B7B7B7", -"F c #AAAAAA", -"G c #BCBCBC", -"H c #AEAEAE", -"I c #B3B3B3", -"J c #C3C3C3", -"K c #9E9E9E", -"L c #C2C2C2", -"M c #9D9D9D", -"N c #9B9B9B", -" ", -" ..... ", -" +@#$%&*=. ", -" @-;>,')!~{. ", -" ]!^/(_:<![&}. ", -" |-1234567![&-8. ", -" 90abcd/07e~&fgh ", -" .fi2jkj(;)[&lmno. ", -" .%_p4qprst[&umnv. ", -" .wxy5^rz7$~uf-[e. ", -" .!:>6:A7!~u-uBwB. ", -" .vwA'<C!Du-u$':m. ", -" +t)Et![Flu!G,'| ", -" .*!!!H~&&IA;JK. ", -" .K~~~~D%A,Lm. ", -" .{lDB)'zwM. ", -" .=N[<t#|. ", -" ..... ", -" ", -" "}; diff --git a/src/xpm_data/led_red.h b/src/xpm_data/led_red.h deleted file mode 100644 index f8fa7ce..0000000 --- a/src/xpm_data/led_red.h +++ /dev/null @@ -1,209 +0,0 @@ -/* XPM */ -static const char * led_red_xpm[] = { -"20 20 186 2", -" c None", -". c #000000", -"+ c #030303", -"@ c #0C0707", -"# c #592924", -"$ c #88443B", -"% c #A04E43", -"& c #7E352B", -"* c #4B1A14", -"= c #070000", -"- c #080808", -"; c #5D3732", -"> c #B6756D", -", c #BF7D74", -"' c #B9756C", -") c #AD6056", -"! c #A45045", -"~ c #9A4037", -"{ c #88382D", -"] c #3D130E", -"^ c #0A0A0A", -"/ c #784C47", -"( c #CA9089", -"_ c #D1A29E", -": c #D0A099", -"< c #C68D87", -"[ c #B67067", -"} c #A8564B", -"| c #8E3A2F", -"1 c #853128", -"2 c #4A160F", -"3 c #040404", -"4 c #5B3832", -"5 c #CA928B", -"6 c #D9B3AE", -"7 c #DFBFBC", -"8 c #DAB4B1", -"9 c #CD9892", -"0 c #BC7971", -"a c #A85347", -"b c #9B4034", -"c c #92372B", -"d c #883125", -"e c #802B1F", -"f c #380C07", -"g c #120B0B", -"h c #B97970", -"i c #D6ABA5", -"j c #E2C7C3", -"k c #ECD9D7", -"l c #E2C4C1", -"m c #D1A29C", -"n c #BC776D", -"o c #A95146", -"p c #9B3B2E", -"q c #943327", -"r c #8B2E22", -"s c #7E281D", -"t c #722217", -"u c #050000", -"v c #5F342E", -"w c #C68A83", -"x c #DAB3AF", -"y c #E5CBC8", -"z c #EFE2E0", -"A c #CF9E98", -"B c #BC7369", -"C c #A74E42", -"D c #9B3628", -"E c #952D22", -"F c #8B281E", -"G c #802519", -"H c #791F16", -"I c #3D0D08", -"J c #92524B", -"K c #C78E86", -"L c #D5AAA6", -"M c #DBB6B2", -"N c #DFBCB8", -"O c #D5A9A4", -"P c #C4847D", -"Q c #B5645C", -"R c #A44539", -"S c #9A3325", -"T c #932C1E", -"U c #8C291B", -"V c #802317", -"W c #782419", -"X c #631F16", -"Y c #A95E54", -"Z c #BF8078", -"` c #C9958E", -" . c #CB9790", -".. c #C9908A", -"+. c #C2837B", -"@. c #B86B63", -"#. c #AB5246", -"$. c #9E3B2D", -"%. c #962F21", -"&. c #912A1C", -"*. c #882419", -"=. c #822A21", -"-. c #873E34", -";. c #83423A", -">. c #87473E", -",. c #B57168", -"'. c #BB7C76", -"). c #BB7972", -"!. c #B1645A", -"~. c #A95348", -"{. c #9E3D33", -"]. c #973124", -"^. c #90291B", -"/. c #8A2619", -"(. c #882B1F", -"_. c #8E473D", -":. c #9C615B", -"<. c #804C47", -"[. c #562621", -"}. c #A66057", -"|. c #AC665F", -"1. c #AB6258", -"2. c #A7564E", -"3. c #A04A3F", -"4. c #9B3D34", -"5. c #963427", -"6. c #8F2B1E", -"7. c #8B271A", -"8. c #8A2C1F", -"9. c #8E4137", -"0. c #9D6760", -"a. c #A57872", -"b. c #5A322F", -"c. c #080101", -"d. c #924B41", -"e. c #9D544C", -"f. c #9C5147", -"g. c #9B493E", -"h. c #984037", -"i. c #93382C", -"j. c #8F3124", -"k. c #8A281D", -"l. c #882D21", -"m. c #91443A", -"n. c #9B615A", -"o. c #A87D77", -"p. c #9A6B65", -"q. c #080303", -"r. c #451D16", -"s. c #8D443A", -"t. c #90453D", -"u. c #904339", -"v. c #8E3C31", -"w. c #8A362B", -"x. c #882F23", -"y. c #863027", -"z. c #934A40", -"A. c #A26961", -"B. c #A97A74", -"C. c #A2736F", -"D. c #4B2722", -"E. c #54241D", -"F. c #803B31", -"G. c #803A31", -"H. c #823A31", -"I. c #82372F", -"J. c #853A30", -"K. c #915148", -"L. c #A06A63", -"M. c #A1716C", -"N. c #5C312B", -"O. c #3D1712", -"P. c #71332C", -"Q. c #7D3D36", -"R. c #874A42", -"S. c #915A54", -"T. c #9B6B64", -"U. c #A27771", -"V. c #966761", -"W. c #48241F", -"X. c #060101", -"Y. c #4A211D", -"Z. c #73443E", -"`. c #8E5F59", -" + c #80524D", -".+ c #532C28", -" ", -" . . . . . ", -" + @ # $ % & * = . ", -" - ; > , ' ) ! ~ { ] . ", -" ^ / ( _ : < [ } ~ | 1 2 . ", -" 3 4 5 6 7 8 9 0 a b c d e f . ", -" g h i j k l m n o p q r s t u ", -" . v w x y z y A B C D E F G H I . ", -" . J K L M N O P Q R S T U V W X . ", -" . Y Z ` ...+.@.#.$.%.&.*.=.-.;.. ", -" . >.,.'.).[ !.~.{.].^./.(._.:.<.. ", -" . [.}.|.1.2.3.4.5.6.7.8.9.0.a.b.. ", -" c.d.e.f.g.h.i.j.k.l.m.n.o.p.q. ", -" . r.s.t.u.v.w.x.y.z.A.B.C.D.. ", -" . E.F.G.H.I.J.K.L.o.M.N.. ", -" . O.P.Q.R.S.T.U.V.W.. ", -" . X.Y.Z.`. +.+q.. ", -" . . . . . ", -" ", -" "}; diff --git a/src/xpm_data/rj45_input.h b/src/xpm_data/rj45_input.h deleted file mode 100644 index 5cd0fde..0000000 --- a/src/xpm_data/rj45_input.h +++ /dev/null @@ -1,102 +0,0 @@ -/* XPM */ -static const char * rj45_input_xpm[] = { -"25 20 79 1", -" c None", -". c #000000", -"+ c #565824", -"@ c #55571E", -"# c #53551D", -"$ c #585A1E", -"% c #5E6123", -"& c #585A21", -"* c #5E6122", -"= c #076B08", -"- c #07A107", -"; c #06A906", -"> c #06B106", -", c #08B008", -"' c #0AC00A", -") c #088608", -"! c #4D4F1D", -"~ c #636524", -"{ c #6F7228", -"] c #707329", -"^ c #666923", -"/ c #494B19", -"( c #2D2E10", -"_ c #069706", -": c #07C207", -"< c #09DB09", -"[ c #0DE60D", -"} c #0FF30F", -"| c #0CDB0C", -"1 c #077E07", -"2 c #494A1A", -"3 c #6B6D26", -"4 c #75782C", -"5 c #6E7127", -"6 c #51531C", -"7 c #0BA30B", -"8 c #12DC12", -"9 c #21F121", -"0 c #11F911", -"a c #11FF11", -"b c #0AC30A", -"c c #73762B", -"d c #71742A", -"e c #595B1E", -"f c #0D970F", -"g c #38E739", -"h c #ACF1AC", -"i c #8BF48B", -"j c #1AFE1A", -"k c #11FD11", -"l c #08BD08", -"m c #434519", -"n c #56591C", -"o c #686B24", -"p c #74772B", -"q c #646722", -"r c #414317", -"s c #089108", -"t c #4BEA4B", -"u c #CDF1CD", -"v c #C7F1C7", -"w c #38E338", -"x c #0ACA0B", -"y c #07A008", -"z c #535521", -"A c #3D4015", -"B c #51541B", -"C c #5F6220", -"D c #636622", -"E c #52551D", -"F c #484B1B", -"G c #064D06", -"H c #0F7812", -"I c #4DBD4D", -"J c #69D669", -"K c #1CAE1E", -"L c #0D7211", -"M c #067507", -"N c #000000", -"......... .........", -".+@#$%&*.........=-;>,').", -".!~{]^/(. ._:<[}|1.", -".2344456. .7890aab.", -".!^c44de. .fghijkl.", -".mnoppqr. .stuvwxy.", -".zABCDEF. .GHIJKLM.", -"......... .........", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . . . . . . ", -" . . . . . . . ", -" . . . . . . . ", -" . . . . . . . ", -" . . . . . . . ", -" . . . . . . . ", -" ..................... "}; diff --git a/src/xpm_data/rj45_output.h b/src/xpm_data/rj45_output.h deleted file mode 100644 index 48cd25c..0000000 --- a/src/xpm_data/rj45_output.h +++ /dev/null @@ -1,104 +0,0 @@ -/* XPM */ -static const char * rj45_output_xpm[] = { -"25 20 81 1", -" c None", -". c #000000", -"+ c #000000", -"@ c #A58826", -"# c #C6AA42", -"$ c #F8D53A", -"% c #FED60E", -"& c #FDD415", -"* c #DEB927", -"= c #A78A22", -"- c #0B4920", -"; c #06421A", -"> c #07531F", -", c #095B23", -"' c #075120", -") c #06441C", -"! c #094820", -"~ c #BA9F42", -"{ c #FBEBA2", -"] c #FEEE9A", -"^ c #FFDD25", -"/ c #FED700", -"( c #F9D11D", -"_ c #C1A027", -": c #063615", -"< c #0B5D26", -"[ c #106D30", -"} c #106E30", -"| c #0F6B2F", -"1 c #0A5C26", -"2 c #06411B", -"3 c #D2B649", -"4 c #FEF1AB", -"5 c #FFF2B0", -"6 c #FFE13E", -"7 c #FFD704", -"8 c #FFD420", -"9 c #F4CA33", -"0 c #0A5524", -"a c #117032", -"b c #0E6D2F", -"c c #095725", -"d c #F9D863", -"e c #FEF6D6", -"f c #FFF9E2", -"g c #FFED8F", -"h c #FFD927", -"i c #F9CE2F", -"j c #F4CB33", -"k c #094D20", -"l c #0C632B", -"m c #0F6E30", -"n c #0C672B", -"o c #0B6129", -"p c #D3B135", -"q c #FCDF73", -"r c #FEEC9E", -"s c #FEE685", -"t c #FBD343", -"u c #DAB32B", -"v c #B89924", -"w c #073F1B", -"x c #0A5425", -"y c #0C652B", -"z c #0D682D", -"A c #0B5E27", -"B c #0A5324", -"C c #8B721C", -"D c #D7B32F", -"E c #DBBA40", -"F c #F6D046", -"G c #CDA92C", -"H c #9B801E", -"I c #715C16", -"J c #0A3219", -"K c #0E3D22", -"L c #0B5124", -"M c #0B5825", -"N c #0B5624", -"O c #09421C", -"P c #09431D", -"......... +++++++++", -".@#$%&*=.........-;>,')!+", -".~{]^/(_. +:<[}|12+", -".3456789. +0aaaabc+", -".defghij. +klmaano+", -".pqrstuv. +wxybzAB+", -".CDEFGHI. +JKLMNOP+", -"......... +++++++++", -" . + ", -" . + ", -" . + ", -" . + ", -" . + ", -" . + + + + + + ", -" . + + + + + + ", -" . + + + + + + ", -" . + + + + + + ", -" . + + + + + + ", -" . + + + + + + ", -" +++++++++++++++++++++ "}; |