summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2008-02-12 21:28:55 -0800
committerAaron Plattner <aplattner@nvidia.com>2008-02-12 21:28:55 -0800
commit9cec52adf6e908620eeb819927b7395734e47f09 (patch)
treeb44fae751b5b6b4e4d21ed8f4dd54effbb2aa378
parent03dfb75016524ca18b3cf5cc71a60163150983d7 (diff)
1.0-87561.0-8756
-rw-r--r--Makefile26
-rw-r--r--doc/nvidia-settings.1.m4101
-rw-r--r--samples/Makefile11
-rw-r--r--samples/README15
-rw-r--r--samples/nv-control-dpy.c389
-rw-r--r--samples/nv-control-events.c264
-rw-r--r--samples/nv-control-framelock.c567
-rw-r--r--samples/nv-control-targets.c310
-rw-r--r--src/command-line.c35
-rw-r--r--src/config-file.c92
-rw-r--r--src/glxinfo.c36
-rw-r--r--src/gtk+-2.x/Makefile.inc8
-rw-r--r--src/gtk+-2.x/ctkclocks.c27
-rw-r--r--src/gtk+-2.x/ctkcolorcorrection.c28
-rw-r--r--src/gtk+-2.x/ctkconfig.c28
-rw-r--r--src/gtk+-2.x/ctkcursorshadow.c26
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-crt.c28
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-dfp.c46
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-tv.c26
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice.c23
-rw-r--r--src/gtk+-2.x/ctkedid.c4
-rw-r--r--src/gtk+-2.x/ctkevent.c95
-rw-r--r--src/gtk+-2.x/ctkframelock.c6626
-rw-r--r--src/gtk+-2.x/ctkframelock.h58
-rw-r--r--src/gtk+-2.x/ctkglx.c27
-rw-r--r--src/gtk+-2.x/ctkgvo-csc.c1047
-rw-r--r--src/gtk+-2.x/ctkgvo-csc.h100
-rw-r--r--src/gtk+-2.x/ctkgvo.c168
-rw-r--r--src/gtk+-2.x/ctkgvo.h2
-rw-r--r--src/gtk+-2.x/ctkhelp.c9
-rw-r--r--src/gtk+-2.x/ctkhelp.h7
-rw-r--r--src/gtk+-2.x/ctkimage.c124
-rw-r--r--src/gtk+-2.x/ctkimage.h40
-rw-r--r--src/gtk+-2.x/ctkopengl.c28
-rw-r--r--src/gtk+-2.x/ctkrandr.c23
-rw-r--r--src/gtk+-2.x/ctkthermal.c26
-rw-r--r--src/gtk+-2.x/ctkwindow.c43
-rw-r--r--src/gtk+-2.x/ctkwindow.h3
-rw-r--r--src/gtk+-2.x/ctkxvideo.c26
-rw-r--r--src/image_data/Makefile.inc9
-rw-r--r--src/image_data/bnc_cable.h480
-rw-r--r--src/image_data/led_green.h44
-rw-r--r--src/image_data/led_grey.h38
-rw-r--r--src/image_data/led_red.h42
-rw-r--r--src/image_data/rj45_input.h50
-rw-r--r--src/image_data/rj45_output.h53
-rw-r--r--src/image_data/rj45_unused.h21
-rw-r--r--src/libXNVCtrl/NVCtrl.c255
-rw-r--r--src/libXNVCtrl/NVCtrl.h637
-rw-r--r--src/libXNVCtrl/NVCtrlLib.h267
-rw-r--r--src/libXNVCtrl/libXNVCtrl.abin14058 -> 15984 bytes
-rw-r--r--src/libXNVCtrl/nv_control.h152
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributes.c182
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributes.h54
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesGlx.c464
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesNvControl.c143
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h115
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesVidMode.c24
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesXrandr.c505
-rw-r--r--src/libXNVCtrlAttributes/NvCtrlAttributesXv.c234
-rw-r--r--src/nvidia-settings.c25
-rw-r--r--src/parse.c372
-rw-r--r--src/parse.h88
-rw-r--r--src/query-assign.c816
-rw-r--r--src/query-assign.h30
-rw-r--r--src/xpm_data/Makefile.inc6
-rw-r--r--src/xpm_data/led_green.h210
-rw-r--r--src/xpm_data/led_grey.h102
-rw-r--r--src/xpm_data/led_red.h209
-rw-r--r--src/xpm_data/rj45_input.h102
-rw-r--r--src/xpm_data/rj45_output.h104
71 files changed, 11969 insertions, 4406 deletions
diff --git a/Makefile b/Makefile
index b3fd621..722d011 100644
--- a/Makefile
+++ b/Makefile
@@ -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
index 8cb374b..65f789f 100644
--- a/src/libXNVCtrl/libXNVCtrl.a
+++ b/src/libXNVCtrl/libXNVCtrl.a
Binary files differ
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+",
-"......... +++++++++",
-" . + ",
-" . + ",
-" . + ",
-" . + ",
-" . + ",
-" . + + + + + + ",
-" . + + + + + + ",
-" . + + + + + + ",
-" . + + + + + + ",
-" . + + + + + + ",
-" . + + + + + + ",
-" +++++++++++++++++++++ "};