summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2008-02-12 21:28:59 -0800
committerAaron Plattner <aplattner@nvidia.com>2008-02-12 21:28:59 -0800
commitbb33b26f8d104cb8c0acbff21d1f2b4638d81f20 (patch)
tree46d6c65cc2f2f2fc28cec5d20c89b7d2e3590f2c
parent818140c39f7818755070e3b853956b818c842f2e (diff)
100.14.03100.14.03
-rw-r--r--Makefile11
-rw-r--r--doc/nvidia-settings.1.m49
-rw-r--r--src/XF86Config-parser/Makefile3
-rw-r--r--src/XF86Config-parser/Makefile.inc1
-rw-r--r--src/XF86Config-parser/Merge.c712
-rw-r--r--src/XF86Config-parser/Monitor.c14
-rw-r--r--src/XF86Config-parser/xf86Parser.h11
-rw-r--r--src/command-line.c5
-rw-r--r--src/command-line.h5
-rw-r--r--src/config-file.c28
-rw-r--r--src/glxinfo.c33
-rw-r--r--src/glxinfo.h1
-rw-r--r--src/gtk+-2.x/Makefile.inc6
-rw-r--r--src/gtk+-2.x/ctkdisplayconfig-utils.c2229
-rw-r--r--src/gtk+-2.x/ctkdisplayconfig-utils.h100
-rw-r--r--src/gtk+-2.x/ctkdisplayconfig.c2823
-rw-r--r--src/gtk+-2.x/ctkdisplayconfig.h13
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-crt.c130
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-crt.h1
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-dfp.c309
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-dfp.h3
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-tv.c203
-rw-r--r--src/gtk+-2.x/ctkdisplaydevice-tv.h3
-rw-r--r--src/gtk+-2.x/ctkdisplaylayout.c10
-rw-r--r--src/gtk+-2.x/ctkevent.c5
-rw-r--r--src/gtk+-2.x/ctkframelock.c585
-rw-r--r--src/gtk+-2.x/ctkglx.c179
-rw-r--r--src/gtk+-2.x/ctkgvo.c130
-rw-r--r--src/gtk+-2.x/ctkgvo.h2
-rw-r--r--src/gtk+-2.x/ctkutils.c87
-rw-r--r--src/gtk+-2.x/ctkutils.h10
-rw-r--r--src/gtk+-2.x/ctkxvideo.c338
-rw-r--r--src/gtk+-2.x/ctkxvideo.h4
-rw-r--r--src/libXNVCtrl/NVCtrl.h95
-rw-r--r--src/libXNVCtrl/libXNVCtrl.abin17180 -> 17180 bytes
-rw-r--r--src/libXNVCtrl/nv_control.h2
-rw-r--r--src/nvidia-settings.c17
-rw-r--r--src/parse.c242
-rw-r--r--src/parse.h24
-rw-r--r--src/query-assign.c255
-rw-r--r--src/query-assign.h1
41 files changed, 5434 insertions, 3205 deletions
diff --git a/Makefile b/Makefile
index 6fe0c47..865a534 100644
--- a/Makefile
+++ b/Makefile
@@ -201,11 +201,20 @@ $(OBJS_DIR)/%.o: %.c
@ mkdir -p $(OBJS_DIR)
$(CC) -c $(ALL_CFLAGS) $< -o $@
+# to generate the dependency files, use the compiler's "-MM" option to
+# generate output of the form "foo.o : foo.c foo.h"; then, use sed to
+# replace the target with "$(OBJS_DIR)/foo.o $(DEPS_DIR)/foo.d", and
+# wrap the prerequisites with $(wildcard ...); the wildcard function
+# serves as an existence filter, so that files that are later removed
+# from the build do not cause stale references.
+
$(DEPS_DIR)/%.d: %.c
@ mkdir -p $(DEPS_DIR)
@ set -e; b=`basename $* .c` ; \
$(CC) -MM $(CPPFLAGS) $< \
- | sed "s%\\($$b\\)\\.o[ :]*%$(OBJS_DIR)/\\1.o $(DEPS_DIR)/\\1.d : %g" > $@; \
+ | sed \
+ -e "s%\\($$b\\)\\.o[ :]*%$(OBJS_DIR)/\\1.o $(DEPS_DIR)/\\1.d : $$\(wildcard %g" \
+ -e "s,\([^\\]\)$$,\1)," > $@; \
[ -s $@ ] || rm -f $@
$(STAMP_C): $(filter-out $(OBJS_DIR)/$(STAMP_C:.c=.o), $(OBJS))
diff --git a/doc/nvidia-settings.1.m4 b/doc/nvidia-settings.1.m4
index ae01609..d21eff5 100644
--- a/doc/nvidia-settings.1.m4
+++ b/doc/nvidia-settings.1.m4
@@ -85,6 +85,10 @@ has difficulties starting due to problems with applying settings in the configur
Load the configuration file, send the values specified therein to the X server, and exit.
This mode of operation is useful to place in your .xinitrc file, for example.
.TP
+.B \-r, \-\-rewrite\-config\-file
+Write the current X server configuration to the configuration file, and exit without starting
+a grpahical user interface.See Examples section.
+.TP
.BI "\-V, \-\-verbose=" verbosity
Controls how much information is printed.
By default, the verbosity is
@@ -609,6 +613,11 @@ Loads the settings stored in
.I ~/.nvidia\-settings\-rc
and exits.
.TP
+.B nvidia\-settings \-\-rewrite\-config\-file
+Writes the current X server configuration to
+.I ~/.nvidia\-settings\-rc
+file and exits.
+.TP
.B nvidia\-settings \-\-query FSAA
Query the value of the full-screen antialiasing setting.
.TP
diff --git a/src/XF86Config-parser/Makefile b/src/XF86Config-parser/Makefile
index ef973a6..721945d 100644
--- a/src/XF86Config-parser/Makefile
+++ b/src/XF86Config-parser/Makefile
@@ -17,7 +17,8 @@ SRC = \
Write.c \
Util.c \
Extensions.c \
- Generate.c
+ Generate.c \
+ Merge.c
OBJS = $(SRC:%.c=%.o)
DEPS = $(SRC:%.c=%.d)
diff --git a/src/XF86Config-parser/Makefile.inc b/src/XF86Config-parser/Makefile.inc
index d41889f..2215dfb 100644
--- a/src/XF86Config-parser/Makefile.inc
+++ b/src/XF86Config-parser/Makefile.inc
@@ -35,6 +35,7 @@ SRC += \
Input.c \
Keyboard.c \
Layout.c \
+ Merge.c \
Module.c \
Monitor.c \
Pointer.c \
diff --git a/src/XF86Config-parser/Merge.c b/src/XF86Config-parser/Merge.c
new file mode 100644
index 0000000..2931934
--- /dev/null
+++ b/src/XF86Config-parser/Merge.c
@@ -0,0 +1,712 @@
+/*
+ *
+ * Copyright (c) 1997 Metro Link Incorporated
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the Metro Link shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from Metro Link.
+ *
+ */
+
+#include "xf86Parser.h"
+#include "xf86tokens.h"
+#include "Configint.h"
+
+
+
+/*
+ * xconfigAddRemovedOptionComment() - Makes a note in the comment
+ * string "existing_comments" that a particular option has been
+ * removed.
+ *
+ */
+static void xconfigAddRemovedOptionComment(char **existing_comments,
+ XConfigOptionPtr option)
+{
+ int len;
+ char *str;
+
+ if (!option || !existing_comments)
+ return;
+
+ len = 32 + strlen(xconfigOptionName(option)) +
+ strlen(xconfigOptionValue(option));
+
+ str = (char *)malloc(len);
+
+ if (str) {
+ snprintf(str, len, "# Removed Option \"%s\" \"%s\"",
+ xconfigOptionName(option),
+ xconfigOptionValue(option));
+ *existing_comments = xconfigAddComment(*existing_comments, str);
+ }
+
+} /* xconfigAddRemovedOptionComment() */
+
+
+
+/*
+ * xconfigRemoveNamedOption() - Removes the named option from an option
+ * list and (if specified) adds a comment to an existing comments string
+ *
+ */
+static void xconfigRemoveNamedOption(XConfigOptionPtr *head, char *name,
+ char **comments)
+{
+ XConfigOptionPtr option;
+
+ option = xconfigFindOption(*head, name);
+ if (option) {
+ if (comments) {
+ xconfigAddRemovedOptionComment(comments, option);
+ }
+ *head = xconfigRemoveOption(*head, option);
+ }
+
+} /* xconfigRemoveNamedOption() */
+
+
+
+/*
+ * xconfigMergeOption() - Merge option "name" from option source
+ * list "srcHead" to option destination list "dstHead".
+ *
+ * Merging here means:
+ *
+ * If the option is not in the source config, remove it from the dest
+ * config.
+ *
+ * If the option is in the source config, make sure the dest config
+ * contains the option with the same value as the source config.
+ *
+ * if "comments" is given, a comment will be added to note when
+ * an option has been removed/replaced.
+ *
+ */
+static void xconfigMergeOption(XConfigOptionPtr *dstHead,
+ XConfigOptionPtr *srcHead,
+ const char *name, char **comments)
+{
+ XConfigOptionPtr srcOption = xconfigFindOption(*srcHead, name);
+ XConfigOptionPtr dstOption = xconfigFindOption(*dstHead, name);
+
+ if (!srcOption) {
+ if (dstOption) {
+ *dstHead = xconfigRemoveOption(*dstHead, dstOption);
+ }
+ } else {
+ if (!dstOption || strcmp(xconfigOptionValue(srcOption),
+ xconfigOptionValue(dstOption))) {
+
+ if (dstOption && comments) {
+ xconfigAddRemovedOptionComment(comments, dstOption);
+ }
+ *dstHead = xconfigAddNewOption
+ (*dstHead, xconfigStrdup(name),
+ xconfigStrdup(xconfigOptionValue(srcOption)));
+ }
+ }
+
+} /* xconfigMergeOption() */
+
+
+
+/*
+ * xconfigMergeFlags() - Updates the destination's list of server flag
+ * options with the options found in the source config.
+ *
+ * Optons in the destination are either added or updated. Options that
+ * are found in the destination config and not in the source config are
+ * not modified.
+ *
+ * Returns 1 if the merge was successful and 0 if not.
+ */
+static int xconfigMergeFlags(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ if (srcConfig->flags) {
+ XConfigOptionPtr option;
+
+ /* Flag section was not found, create a new one */
+ if (!dstConfig->flags) {
+ dstConfig->flags =
+ (XConfigFlagsPtr) calloc(1, sizeof(XConfigFlagsRec));
+ if (!dstConfig->flags) return 0;
+ }
+
+ option = srcConfig->flags->options;
+ while (option) {
+ xconfigMergeOption(&(dstConfig->flags->options),
+ &(srcConfig->flags->options),
+ xconfigOptionName(option),
+ &(dstConfig->flags->comment));
+ option = option->next;
+ }
+ }
+
+ return 1;
+
+} /* xconfigMergeFlags() */
+
+
+
+/*
+ * xconfigMergeMonitors() - Updates information in the destination monitor
+ * with that of the source monitor.
+ *
+ */
+static void xconfigMergeMonitors(XConfigMonitorPtr dstMonitor,
+ XConfigMonitorPtr srcMonitor)
+{
+ int i;
+
+
+ /* Update vendor */
+
+ free(dstMonitor->vendor);
+ dstMonitor->vendor = xconfigStrdup(srcMonitor->vendor);
+
+ /* Update modelname */
+
+ free(dstMonitor->modelname);
+ dstMonitor->modelname = xconfigStrdup(srcMonitor->modelname);
+
+ /* Update horizontal sync */
+
+ dstMonitor->n_hsync = srcMonitor->n_hsync;
+ for (i = 0; i < srcMonitor->n_hsync; i++) {
+ dstMonitor->hsync[i].lo = srcMonitor->hsync[i].lo;
+ dstMonitor->hsync[i].hi = srcMonitor->hsync[i].hi;
+ }
+
+ /* Update vertical sync */
+
+ dstMonitor->n_vrefresh = srcMonitor->n_vrefresh;
+ for (i = 0; i < srcMonitor->n_hsync; i++) {
+ dstMonitor->vrefresh[i].lo = srcMonitor->vrefresh[i].lo;
+ dstMonitor->vrefresh[i].hi = srcMonitor->vrefresh[i].hi;
+ }
+
+ /* XXX Remove the destination monitor's "UseModes" references to
+ * avoid having the wrong modelines tied to the new monitor.
+ */
+ xconfigFreeModesLinkList(dstMonitor->modes_sections);
+ dstMonitor->modes_sections = NULL;
+
+} /* xconfigMergeMonitors() */
+
+
+
+/*
+ * xconfigMergeAllMonitors() - This function ensures that all monitors in
+ * the source config appear in the destination config by adding and/or
+ * updating the "appropriate" destination monitor sections.
+ *
+ */
+static int xconfigMergeAllMonitors(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ XConfigMonitorPtr dstMonitor;
+ XConfigMonitorPtr srcMonitor;
+
+
+ /* Make sure all monitors in the src config are also in the dst config */
+
+ for (srcMonitor = srcConfig->monitors;
+ srcMonitor;
+ srcMonitor = srcMonitor->next) {
+
+ dstMonitor =
+ xconfigFindMonitor(srcMonitor->identifier, dstConfig->monitors);
+
+ /* Monitor section was not found, create a new one and add it */
+ if (!dstMonitor) {
+ dstMonitor =
+ (XConfigMonitorPtr) calloc(1, sizeof(XConfigMonitorRec));
+ if (!dstMonitor) return 0;
+
+ dstMonitor->identifier = xconfigStrdup(srcMonitor->identifier);
+
+ dstConfig->monitors = (XConfigMonitorPtr)
+ xconfigAddListItem((GenericListPtr)dstConfig->monitors,
+ (GenericListPtr)dstMonitor);
+ }
+
+ /* Do the merge */
+ xconfigMergeMonitors(dstMonitor, srcMonitor);
+ }
+
+ return 1;
+
+} /* xconfigMergeAllMonitors() */
+
+
+
+/*
+ * xconfigMergeDevices() - Updates information in the destination device
+ * with that of the source device.
+ *
+ */
+static void xconfigMergeDevices(XConfigDevicePtr dstDevice,
+ XConfigDevicePtr srcDevice)
+{
+ // XXX Zero out the device section?
+
+ /* Update driver */
+
+ free(dstDevice->driver);
+ dstDevice->driver = xconfigStrdup(srcDevice->driver);
+
+ /* Update vendor */
+
+ free(dstDevice->vendor);
+ dstDevice->vendor = xconfigStrdup(srcDevice->vendor);
+
+ /* Update bus ID */
+
+ free(dstDevice->busid);
+ dstDevice->busid = xconfigStrdup(srcDevice->busid);
+
+ /* Update board */
+
+ free(dstDevice->board);
+ dstDevice->board = xconfigStrdup(srcDevice->board);
+
+ /* Update chip info */
+
+ dstDevice->chipid = srcDevice->chipid;
+ dstDevice->chiprev = srcDevice->chiprev;
+
+ /* Update IRQ */
+
+ dstDevice->irq = srcDevice->irq;
+
+ /* Update screen */
+
+ dstDevice->screen = srcDevice->screen;
+
+} /* xconfigMergeDevices() */
+
+
+
+/*
+ * xconfigMergeAllDevices() - This function ensures that all devices in
+ * the source config appear in the destination config by adding and/or
+ * updating the "appropriate" destination device sections.
+ *
+ */
+static int xconfigMergeAllDevices(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ XConfigDevicePtr dstDevice;
+ XConfigDevicePtr srcDevice;
+
+
+ /* Make sure all monitors in the src config are also in the dst config */
+
+ for (srcDevice = srcConfig->devices;
+ srcDevice;
+ srcDevice = srcDevice->next) {
+
+ dstDevice =
+ xconfigFindDevice(srcDevice->identifier, dstConfig->devices);
+
+ /* Device section was not found, create a new one and add it */
+ if (!dstDevice) {
+ dstDevice =
+ (XConfigDevicePtr) calloc(1, sizeof(XConfigDeviceRec));
+ if (!dstDevice) return 0;
+
+ dstDevice->identifier = xconfigStrdup(srcDevice->identifier);
+
+ dstConfig->devices = (XConfigDevicePtr)
+ xconfigAddListItem((GenericListPtr)dstConfig->devices,
+ (GenericListPtr)dstDevice);
+ }
+
+ /* Do the merge */
+ xconfigMergeDevices(dstDevice, srcDevice);
+ }
+
+ return 1;
+
+} /* xconfigMergeAllDevices() */
+
+
+
+/*
+ * xconfigMergeDriverOptions() - Update the (Screen) driver options
+ * of the destination config with information from the source config.
+ *
+ * - Assumes the source options are all found in the srcScreen->options.
+ * - Updates only those options listed in the srcScreen->options.
+ *
+ */
+static int xconfigMergeDriverOptions(XConfigScreenPtr dstScreen,
+ XConfigScreenPtr srcScreen)
+{
+ XConfigOptionPtr option;
+ XConfigDisplayPtr display;
+
+ option = srcScreen->options;
+ while (option) {
+ char *name = xconfigOptionName(option);
+
+ /* Remove the option from all non-screen option lists */
+
+ if (dstScreen->device) {
+ xconfigRemoveNamedOption(&(dstScreen->device->options), name,
+ &(dstScreen->device->comment));
+ }
+ if (dstScreen->monitor) {
+ xconfigRemoveNamedOption(&(dstScreen->monitor->options), name,
+ &(dstScreen->monitor->comment));
+ }
+ for (display = dstScreen->displays; display; display = display->next) {
+ xconfigRemoveNamedOption(&(display->options), name,
+ &(display->comment));
+ }
+
+ /* Update/Add the option to the screen's option list */
+ {
+ // XXX Only add a comment if the value changed.
+ XConfigOptionPtr old =
+ xconfigFindOption(dstScreen->options, name);
+
+ if (!old || !strcmp(xconfigOptionValue(option),
+ xconfigOptionValue(old))) {
+ xconfigRemoveNamedOption(&(dstScreen->options), name,
+ NULL);
+ } else {
+ xconfigRemoveNamedOption(&(dstScreen->options), name,
+ &(dstScreen->comment));
+ }
+ }
+
+ /* Add the option to the screen->options list */
+
+ dstScreen->options =
+ xconfigAddNewOption(dstScreen->options,
+ xconfigStrdup(name),
+ xconfigStrdup(xconfigOptionValue(option)));
+
+ option = option->next;
+ }
+
+ return 1;
+
+} /* xconfigMergeDriverOptions() */
+
+
+
+/*
+ * xconfigMergeDisplays() - Duplicates display information from the
+ * source screen to the destination screen.
+ *
+ */
+static int xconfigMergeDisplays(XConfigScreenPtr dstScreen,
+ XConfigScreenPtr srcScreen)
+{
+ XConfigDisplayPtr dstDisplay;
+ XConfigDisplayPtr srcDisplay;
+ XConfigOptionPtr srcOption;
+ XConfigModePtr srcMode, dstMode, lastDstMode;
+
+ /* Free all the displays in the destination screen */
+
+ xconfigFreeDisplayList(dstScreen->displays);
+
+ /* Copy all te displays */
+
+ for (srcDisplay = srcScreen->displays;
+ srcDisplay;
+ srcDisplay = srcDisplay->next) {
+
+ /* Create a new display */
+
+ dstDisplay = xconfigAlloc(sizeof(XConfigDisplayRec));
+ if (!dstDisplay) return 0;
+
+ /* Copy display fields */
+
+ dstDisplay->frameX0 = srcDisplay->frameX0;
+ dstDisplay->frameY0 = srcDisplay->frameY0;
+ dstDisplay->virtualX = srcDisplay->virtualX;
+ dstDisplay->virtualY = srcDisplay->virtualY;
+ dstDisplay->depth = srcDisplay->depth;
+ dstDisplay->bpp = srcDisplay->bpp;
+ dstDisplay->visual = xconfigStrdup(srcDisplay->visual);
+ dstDisplay->weight = srcDisplay->weight;
+ dstDisplay->black = srcDisplay->black;
+ dstDisplay->white = srcDisplay->white;
+ dstDisplay->comment = xconfigStrdup(srcDisplay->comment);
+
+ /* Copy options over */
+
+ srcOption = srcDisplay->options;
+ while (srcOption) {
+ xconfigMergeOption(&(dstDisplay->options),
+ &(srcDisplay->options),
+ xconfigOptionName(srcOption),
+ NULL);
+ srcOption = srcOption->next;
+ }
+
+ /* Copy modes over */
+
+ lastDstMode = NULL;
+ srcMode = srcDisplay->modes;
+ while (srcMode) {
+
+ /* Copy the mode */
+
+ dstMode = xconfigAddMode(NULL, srcMode->mode_name);
+
+ /* Add mode at the end of the list */
+
+ if ( !lastDstMode ) {
+ dstDisplay->modes = dstMode;
+ } else {
+ lastDstMode->next = dstMode;
+ }
+ lastDstMode = dstMode;
+
+ srcMode = srcMode->next;
+ }
+ }
+
+ return 1;
+
+} /* xconfigMergeDisplays() */
+
+
+
+/*
+ * xconfigMergeScreens() - Updates information in the destination screen
+ * with that of the source screen.
+ *
+ * NOTE: This assumes the Monitor and Device sections have already been
+ * merged.
+ *
+ */
+static void xconfigMergeScreens(XConfigScreenPtr dstScreen,
+ XConfigPtr dstConfig,
+ XConfigScreenPtr srcScreen,
+ XConfigPtr srcConfig)
+{
+ /* Use the right device */
+
+ free(dstScreen->device_name);
+ dstScreen->device_name = xconfigStrdup(srcScreen->device_name);
+ dstScreen->device =
+ xconfigFindDevice(dstScreen->device_name, dstConfig->devices);
+
+
+ /* Use the right monitor */
+
+ free(dstScreen->monitor_name);
+ dstScreen->monitor_name = xconfigStrdup(srcScreen->monitor_name);
+ dstScreen->monitor =
+ xconfigFindMonitor(dstScreen->monitor_name, dstConfig->monitors);
+
+
+ /* Update the right default depth */
+
+ dstScreen->defaultdepth = srcScreen->defaultdepth;
+
+
+ /* Copy over the display section */
+
+ xconfigMergeDisplays(dstScreen, srcScreen);
+
+
+ /* Update the screen's driver options */
+
+ xconfigMergeDriverOptions(dstScreen, srcScreen);
+
+} /* xconfigMergeScreens() */
+
+
+
+/*
+ * xconfigMergeAllScreens() - This function ensures that all screens in
+ * the source config appear in the destination config by adding and/or
+ * updating the "appropriate" destination screen sections.
+ *
+ */
+static int xconfigMergeAllScreens(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ XConfigScreenPtr srcScreen;
+ XConfigScreenPtr dstScreen;
+
+
+ /* Make sure all src screens are in the dst config */
+
+ for (srcScreen = srcConfig->screens;
+ srcScreen;
+ srcScreen = srcScreen->next) {
+
+ dstScreen =
+ xconfigFindScreen(srcScreen->identifier, dstConfig->screens);
+
+ /* Screen section was not found, create a new one and add it */
+ if (!dstScreen) {
+ dstScreen =
+ (XConfigScreenPtr) calloc(1, sizeof(XConfigScreenRec));
+ if (!dstScreen) return 0;
+
+ dstScreen->identifier = xconfigStrdup(srcScreen->identifier);
+
+ dstConfig->screens = (XConfigScreenPtr)
+ xconfigAddListItem((GenericListPtr)dstConfig->screens,
+ (GenericListPtr)dstScreen);
+ }
+
+ /* Do the merge */
+ xconfigMergeScreens(dstScreen, dstConfig, srcScreen, srcConfig);
+ }
+
+ return 1;
+
+} /* xconfigMergeAllScreens() */
+
+
+
+/*
+ * xconfigMergeLayout() - Updates information in the destination's first
+ * layout with that of the source's first layout.
+ *
+ */
+static int xconfigMergeLayout(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ XConfigLayoutPtr srcLayout = srcConfig->layouts;
+ XConfigLayoutPtr dstLayout = dstConfig->layouts;
+
+ XConfigAdjacencyPtr srcAdj;
+ XConfigAdjacencyPtr dstAdj;
+ XConfigAdjacencyPtr lastDstAdj;
+
+ /* Clear the destination's adjacency list */
+
+ xconfigFreeAdjacencyList(dstLayout->adjacencies);
+
+ /* Copy adjacencies over */
+
+ lastDstAdj = NULL;
+ srcAdj = srcLayout->adjacencies;
+ while (srcAdj) {
+
+ /* Copy the adjacency */
+
+ dstAdj =
+ (XConfigAdjacencyPtr) calloc(1, sizeof(XConfigAdjacencyRec));
+
+ dstAdj->scrnum = srcAdj->scrnum;
+ dstAdj->screen_name = xconfigStrdup(srcAdj->screen_name);
+ dstAdj->top_name = xconfigStrdup(srcAdj->top_name);
+ dstAdj->bottom_name = xconfigStrdup(srcAdj->bottom_name);
+ dstAdj->left_name = xconfigStrdup(srcAdj->left_name);
+ dstAdj->right_name = xconfigStrdup(srcAdj->right_name);
+ dstAdj->where = srcAdj->where;
+ dstAdj->x = srcAdj->x;
+ dstAdj->y = srcAdj->y;
+ dstAdj->refscreen = xconfigStrdup(srcAdj->refscreen);
+
+ dstAdj->screen =
+ xconfigFindScreen(dstAdj->screen_name, dstConfig->screens);
+ dstAdj->top =
+ xconfigFindScreen(dstAdj->top_name, dstConfig->screens);
+ dstAdj->bottom =
+ xconfigFindScreen(dstAdj->bottom_name, dstConfig->screens);
+ dstAdj->left =
+ xconfigFindScreen(dstAdj->left_name, dstConfig->screens);
+ dstAdj->right =
+ xconfigFindScreen(dstAdj->right_name, dstConfig->screens);
+
+ /* Add adjacency at the end of the list */
+
+ if ( !lastDstAdj ) {
+ dstLayout->adjacencies = dstAdj;
+ } else {
+ lastDstAdj->next = dstAdj;
+ }
+ lastDstAdj = dstAdj;
+
+ srcAdj = srcAdj->next;
+ }
+
+ return 1;
+
+} /* xconfigMergeLayout() */
+
+
+
+/*
+ * xconfigMergeConfigs() - Merges the source X configuration with the
+ * destination X configuration.
+ *
+ * NOTE: This function is currently only used for merging X config files
+ * for display configuration reasons. As such, the merge assumes
+ * that the dst config file is the target config file and that
+ * mostly, only new display configuration information should be
+ * copied from the source X config to the destination X config.
+ *
+ */
+int xconfigMergeConfigs(XConfigPtr dstConfig, XConfigPtr srcConfig)
+{
+ /* Make sure the X config is falid */
+ // make_xconfig_usable(dstConfig);
+
+
+ /* Merge the server flag (Xinerama) section */
+
+ if (!xconfigMergeFlags(dstConfig, srcConfig)) {
+ return 0;
+ }
+
+
+ /* Merge the monitor sections */
+
+ if (!xconfigMergeAllMonitors(dstConfig, srcConfig)) {
+ return 0;
+ }
+
+
+ /* Merge the device sections */
+
+ if (!xconfigMergeAllDevices(dstConfig, srcConfig)) {
+ return 0;
+ }
+
+
+ /* Merge the screen sections */
+
+ if (!xconfigMergeAllScreens(dstConfig, srcConfig)) {
+ return 0;
+ }
+
+
+ /* Merge the first layout */
+
+ if (!xconfigMergeLayout(dstConfig, srcConfig)) {
+ return 0;
+ }
+
+ return 1;
+
+} /* xconfigMergeConfigs() */
diff --git a/src/XF86Config-parser/Monitor.c b/src/XF86Config-parser/Monitor.c
index cacc284..e8d8e3c 100644
--- a/src/XF86Config-parser/Monitor.c
+++ b/src/XF86Config-parser/Monitor.c
@@ -833,6 +833,20 @@ xconfigFreeModeLineList (XConfigModeLinePtr ptr)
}
}
+void
+xconfigFreeModesLinkList (XConfigModesLinkPtr ptr)
+{
+ XConfigModesLinkPtr prev;
+
+ while (ptr)
+ {
+ TEST_FREE (ptr->modes_name);
+ prev = ptr;
+ ptr = ptr->next;
+ free (prev);
+ }
+}
+
XConfigMonitorPtr
xconfigFindMonitor (const char *ident, XConfigMonitorPtr p)
{
diff --git a/src/XF86Config-parser/xf86Parser.h b/src/XF86Config-parser/xf86Parser.h
index 40b8162..7013b9b 100644
--- a/src/XF86Config-parser/xf86Parser.h
+++ b/src/XF86Config-parser/xf86Parser.h
@@ -652,6 +652,8 @@ void xconfigFreeVideoPortList(XConfigVideoPortPtr ptr);
void xconfigFreeBuffersList (XConfigBuffersPtr ptr);
void xconfigFreeDRI(XConfigDRIPtr ptr);
void xconfigFreeExtensions(XConfigExtensionsPtr ptr);
+void xconfigFreeModesLinkList(XConfigModesLinkPtr ptr);
+
/*
@@ -734,4 +736,13 @@ void xconfigGeneratePrintPossibleKeyboards(void);
int xconfigCheckCoreInputDevices(GenerateOptions *gop,
XConfigPtr config, XConfigLayoutPtr layout);
+
+/*
+ * X config tools
+ */
+
+int xconfigMergeConfigs(XConfigPtr dstConfig, XConfigPtr srcConfig);
+
+
+
#endif /* _xf86Parser_h_ */
diff --git a/src/command-line.c b/src/command-line.c
index 0a918e6..6161358 100644
--- a/src/command-line.c
+++ b/src/command-line.c
@@ -123,6 +123,10 @@ static const NVGetoptOption __options[] = {
"if nvidia-settings has difficulties starting due to problems with "
"applying settings in the configuration file." },
+ { "rewrite-config-file", 'r', 0, NULL,
+ "Write the X server configuration to the configuration file, and exit, "
+ "without starting the graphical user interface." },
+
{ "verbose", 'V', NVGETOPT_HAS_ARGUMENT, NULL,
"Controls how much information is printed. Valid values are 'errors' "
"(print error messages), 'warnings' (print error and warning messages), "
@@ -313,6 +317,7 @@ Options *parse_command_line(int argc, char *argv[], char *dpy)
case 'h': print_help(); exit(0); break;
case 'l': op->only_load = 1; break;
case 'n': op->no_load = 1; break;
+ case 'r': op->rewrite = 1; break;
case 'c': op->ctrl_display = strval; break;
case 'V':
__verbosity = VERBOSITY_DEFAULT;
diff --git a/src/command-line.h b/src/command-line.h
index fd1ed7f..c26e1c5 100644
--- a/src/command-line.h
+++ b/src/command-line.h
@@ -86,6 +86,11 @@ typedef struct {
* The attributes are not sent to the X Server.
*/
+ int rewrite; /*
+ * If true, write the X server configuration
+ * to the configuration file and exit.
+ */
+
} Options;
diff --git a/src/config-file.c b/src/config-file.c
index e21f409..86d26e5 100644
--- a/src/config-file.c
+++ b/src/config-file.c
@@ -55,8 +55,6 @@
#include "parse.h"
#include "msg.h"
-#define MAX_CONFIG_FILE_LINE_LEN 256
-
typedef struct {
ParsedAttribute a;
@@ -447,14 +445,16 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file,
const int length,
ConfigProperties *conf)
{
- int line, has_data, len, n, ret;
- char *cur, *c, *comment, tmp[MAX_CONFIG_FILE_LINE_LEN];
+ int line, has_data, current_tmp_len, len, n, ret;
+ char *cur, *c, *comment, *tmp;
ParsedAttributeWrapper *w;
cur = buf;
line = 1;
+ current_tmp_len = 0;
n = 0;
w = NULL;
+ tmp = NULL;
while (cur) {
c = cur;
@@ -470,16 +470,19 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file,
if (!isspace(*c)) has_data = NV_TRUE;
c++;
}
-
+
if (has_data) {
if (!comment) comment = c;
len = comment - cur;
- if (len >= MAX_CONFIG_FILE_LINE_LEN) {
- nv_error_msg("Error parsing configuration file '%s' on "
- "line %d: line length exceeds maximum "
- "length of %d.",
- file, line, MAX_CONFIG_FILE_LINE_LEN);
- goto failed;
+
+ /* grow the tmp buffer if it's too small */
+
+ if (len >= current_tmp_len) {
+ current_tmp_len = len + 1;
+ if (tmp) {
+ free(tmp);
+ }
+ tmp = malloc(sizeof(char) * current_tmp_len);
}
strncpy (tmp, cur, len);
@@ -511,7 +514,7 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file,
line++;
}
-
+ free(tmp);
/* mark the end of the array */
w = realloc(w, sizeof(ParsedAttributeWrapper) * (n+1));
@@ -521,6 +524,7 @@ static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file,
failed:
if (w) free(w);
+ free(tmp);
return NULL;
} /* parse_config_file() */
diff --git a/src/glxinfo.c b/src/glxinfo.c
index f9f0800..a555b1e 100644
--- a/src/glxinfo.c
+++ b/src/glxinfo.c
@@ -137,6 +137,28 @@ transparent_type_abbrev(int trans_type)
const char *
+x_visual_type_abbrev(int x_visual_type)
+{
+ switch (x_visual_type) {
+ case GLX_TRUE_COLOR:
+ return "tc";
+ case GLX_DIRECT_COLOR:
+ return "dc";
+ case GLX_PSEUDO_COLOR:
+ return "pc";
+ case GLX_STATIC_COLOR:
+ return "sc";
+ case GLX_GRAY_SCALE:
+ return "gs";
+ case GLX_STATIC_GRAY:
+ return "sg";
+ default:
+ return ".";
+ }
+}
+
+
+const char *
caveat_abbrev(int caveat)
{
if (caveat == GLX_NONE_EXT || caveat == 0)
@@ -160,12 +182,12 @@ print_fbconfig_attribs(GLXFBConfigAttr *fbca)
return;
}
- printf("-fc- -vi- buf lv rgb d s colorbuffer ax dp st "
+ printf("-fc- -vi- vt buf lv rgb d s colorbuffer ax dp st "
"accumbuffer -ms- cav -----pbuffer----- ---transparent----\n");
- printf(" id id siz l ci b t r g b a bf th en "
- "r g b a ns b eat widt hght max-pxs typ r g b a i\n");
+ printf(" id id siz l ci b t r g b a bf th en "
+ " r g b a ns b eat widt hght max-pxs typ r g b a i\n");
printf("----------------------------------------------"
- "---------------------------------------------------------\n");
+ "------------------------------------------------------------\n");
i = 0;
while ( fbca[i].fbconfig_id != 0 ) {
@@ -176,7 +198,8 @@ print_fbconfig_attribs(GLXFBConfigAttr *fbca)
} else {
printf(" . ");
}
- printf("%3d %2d %3.3s %1c %1c ",
+ printf("%2.2s %3d %2d %3.3s %1c %1c ",
+ x_visual_type_abbrev(fbca[i].x_visual_type),
fbca[i].buffer_size,
fbca[i].level,
render_type_abbrev(fbca[i].render_type),
diff --git a/src/glxinfo.h b/src/glxinfo.h
index fd8bca2..453df02 100644
--- a/src/glxinfo.h
+++ b/src/glxinfo.h
@@ -33,6 +33,7 @@
#else
const char * render_type_abbrev(int rend_type);
const char * transparent_type_abbrev(int trans_type);
+const char * x_visual_type_abbrev(int x_visual_type);
const char * caveat_abbrev(int caveat);
#endif
diff --git a/src/gtk+-2.x/Makefile.inc b/src/gtk+-2.x/Makefile.inc
index 90ca4a9..1d882bd 100644
--- a/src/gtk+-2.x/Makefile.inc
+++ b/src/gtk+-2.x/Makefile.inc
@@ -60,7 +60,8 @@ SRC += \
ctkscreen.c \
ctkgpu.c \
ctkbanner.c \
- ctkvcsc.c
+ ctkvcsc.c \
+ ctkdisplayconfig-utils.c
EXTRA_DIST += \
@@ -100,7 +101,8 @@ EXTRA_DIST += \
ctkscreen.h \
ctkgpu.h \
ctkbanner.h \
- ctkvcsc.h
+ ctkvcsc.h \
+ ctkdisplayconfig-utils.h
dist_list::
@ echo $(SRC) $(EXTRA_DIST)
diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.c b/src/gtk+-2.x/ctkdisplayconfig-utils.c
new file mode 100644
index 0000000..385f90b
--- /dev/null
+++ b/src/gtk+-2.x/ctkdisplayconfig-utils.c
@@ -0,0 +1,2229 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2006 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of Version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2
+ * of the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the:
+ *
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "msg.h"
+#include "parse.h"
+
+#include "ctkdisplayconfig-utils.h"
+
+
+
+
+/*****************************************************************************/
+/** TOKEN PARSING FUNCTIONS **************************************************/
+/*****************************************************************************/
+
+
+/** apply_modeline_token() *******************************************
+ *
+ * Modifies the modeline structure given with the token/value pair
+ * given.
+ *
+ **/
+void apply_modeline_token(char *token, char *value, void *data)
+{
+ nvModeLinePtr modeline = (nvModeLinePtr) data;
+
+ if (!modeline || !token || !strlen(token)) {
+ return;
+ }
+
+ /* Modeline source */
+ if (!strcasecmp("source", token)) {
+ if (!value || !strlen(value)) {
+ nv_warning_msg("Modeline 'source' token requires a value!");
+ } else if (!strcasecmp("xserver", value)) {
+ modeline->source |= MODELINE_SOURCE_XSERVER;
+ } else if (!strcasecmp("xconfig", value)) {
+ modeline->source |= MODELINE_SOURCE_XCONFIG;
+ } else if (!strcasecmp("builtin", value)) {
+ modeline->source |= MODELINE_SOURCE_BUILTIN;
+ } else if (!strcasecmp("vesa", value)) {
+ modeline->source |= MODELINE_SOURCE_VESA;
+ } else if (!strcasecmp("edid", value)) {
+ modeline->source |= MODELINE_SOURCE_EDID;
+ } else if (!strcasecmp("nv-control", value)) {
+ modeline->source |= MODELINE_SOURCE_NVCONTROL;
+ } else {
+ nv_warning_msg("Unknown modeline source '%s'", value);
+ }
+
+ /* X config name */
+ } else if (!strcasecmp("xconfig-name", token)) {
+ if (!value || !strlen(value)) {
+ nv_warning_msg("Modeline 'xconfig-name' token requires a value!");
+ } else {
+ if (modeline->xconfig_name) {
+ free(modeline->xconfig_name);
+ }
+ modeline->xconfig_name = g_strdup(value);
+ }
+
+ /* Unknown token */
+ } else {
+ nv_warning_msg("Unknown modeline token value pair: %s=%s",
+ token, value);
+ }
+
+} /* apply_modeline_token() */
+
+
+
+/** apply_metamode_token() *******************************************
+ *
+ * Modifies the metamode structure given with the token/value pair
+ * given.
+ *
+ **/
+void apply_metamode_token(char *token, char *value, void *data)
+{
+ nvMetaModePtr metamode = (nvMetaModePtr) data;
+
+ if (!metamode || !token || !strlen(token)) {
+ return;
+ }
+
+ /* Metamode ID */
+ if (!strcasecmp("id", token)) {
+ if (!value || !strlen(value)) {
+ nv_warning_msg("MetaMode 'id' token requires a value!");
+ } else {
+ metamode->id = atoi(value);
+ }
+
+ /* Modeline Source */
+ } else if (!strcasecmp("source", token)) {
+ if (!value || !strlen(value)) {
+ nv_warning_msg("MetaMode 'source' token requires a value!");
+ } else if (!strcasecmp("xconfig", value)) {
+ metamode->source |= METAMODE_SOURCE_XCONFIG;
+ } else if (!strcasecmp("implicit", value)) {
+ metamode->source |= METAMODE_SOURCE_IMPLICIT;
+ } else if (!strcasecmp("nv-control", value)) {
+ metamode->source |= METAMODE_SOURCE_NVCONTROL;
+ } else {
+ nv_warning_msg("Unknown MetaMode source '%s'", value);
+ }
+
+ /* Switchable */
+ } else if (!strcasecmp("switchable", token)) {
+ if (!value || !strlen(value)) {
+ nv_warning_msg("MetaMode 'switchable' token requires a value!");
+ } else {
+ if (!strcasecmp(value, "yes")) {
+ metamode->switchable = TRUE;
+ } else {
+ metamode->switchable = FALSE;
+ }
+ }
+
+ /* Unknown token */
+ } else {
+ nv_warning_msg("Unknown MetaMode token value pair: %s=%s",
+ token, value);
+ }
+
+} /* apply_metamode_token() */
+
+
+
+/** apply_monitor_token() ********************************************
+ *
+ * Reads the source of a refresh/sync range value
+ *
+ **/
+void apply_monitor_token(char *token, char *value, void *data)
+{
+ char **source = (char **)data;
+
+ if (!source || !token || !strlen(token)) {
+ return;
+ }
+
+ /* Vert sync or horiz refresh source */
+ if (!strcasecmp("source", token)) {
+ if (*source) free(*source);
+ *source = strdup(value);
+
+ /* Unknown token */
+ } else {
+ nv_warning_msg("Unknown monitor range token value pair: %s=%s",
+ token, value);
+ }
+
+} /* apply_monitor_token() */
+
+
+
+/** apply_screen_info_token() ****************************************
+ *
+ * Modifies the ScreenInfo structure (pointed to by data) with
+ * information from the token-value pair given. Currently accepts
+ * position and width/height data.
+ *
+ **/
+void apply_screen_info_token(char *token, char *value, void *data)
+{
+ ScreenInfo *screen_info = (ScreenInfo *)data;
+
+ if (!screen_info || !token || !strlen(token)) {
+ return;
+ }
+
+ /* X */
+ if (!strcasecmp("x", token)) {
+ screen_info->x = atoi(value);
+
+ /* Y */
+ } else if (!strcasecmp("y", token)) {
+ screen_info->y = atoi(value);
+
+ /* Width */
+ } else if (!strcasecmp("width", token)) {
+ screen_info->width = atoi(value);
+
+ /* Height */
+ } else if (!strcasecmp("height", token)) {
+ screen_info->height = atoi(value);
+
+ /* Unknown token */
+ } else {
+ nv_warning_msg("Unknown screen info token value pair: %s=%s",
+ token, value);
+ }
+
+} /* apply_screen_info_token() */
+
+
+
+
+/*****************************************************************************/
+/** MODELINE FUNCTIONS *******************************************************/
+/*****************************************************************************/
+
+
+/** modeline_parse() *************************************************
+ *
+ * Converts a modeline string to an modeline structure that the
+ * display configuration page can use
+ *
+ * Modeline strings have the following format:
+ *
+ * "mode_name" dot_clock timings flags
+ *
+ **/
+static nvModeLinePtr modeline_parse(const char *modeline_str)
+{
+ nvModeLinePtr modeline = NULL;
+ const char *str = modeline_str;
+ char *tmp;
+ char *tokens;
+
+
+ if (!str) return NULL;
+
+ modeline = (nvModeLinePtr)calloc(1, sizeof(nvModeLine));
+ if (!modeline) return NULL;
+
+ /* Parse the modeline tokens */
+ tmp = strstr(str, "::");
+ if (tmp) {
+ tokens = strdup(str);
+ tokens[ tmp-str ] = '\0';
+ str = tmp +2;
+ parse_token_value_pairs(tokens, apply_modeline_token,
+ (void *)modeline);
+ free(tokens);
+ }
+
+ /* Read the mode name */
+ str = parse_skip_whitespace(str);
+ if (!str || *str != '"') goto fail;
+ str++;
+ str = parse_read_name(str, &(modeline->data.identifier), '"');
+ if (!str) goto fail;
+
+ /* Read dot clock */
+ {
+ int digits = 100;
+
+ str = parse_read_integer(str, &(modeline->data.clock));
+ modeline->data.clock *= 1000;
+ if (*str == '.') {
+ str++;
+ while (digits &&
+ *str &&
+ *str != ' ' && *str != '\t' &&
+ *str != '\n' && *str != '\r') {
+
+ modeline->data.clock += digits * (*str - '0');
+ digits /= 10;
+ str++;
+ }
+ }
+ str = parse_skip_whitespace(str);
+ }
+
+ str = parse_read_integer(str, &(modeline->data.hdisplay));
+ str = parse_read_integer(str, &(modeline->data.hsyncstart));
+ str = parse_read_integer(str, &(modeline->data.hsyncend));
+ str = parse_read_integer(str, &(modeline->data.htotal));
+ str = parse_read_integer(str, &(modeline->data.vdisplay));
+ str = parse_read_integer(str, &(modeline->data.vsyncstart));
+ str = parse_read_integer(str, &(modeline->data.vsyncend));
+ str = parse_read_integer(str, &(modeline->data.vtotal));
+
+
+ /* Parse modeline flags */
+ while ((str = parse_read_name(str, &tmp, ' ')) && strlen(tmp)) {
+
+ if (!xconfigNameCompare(tmp, "+hsync")) {
+ modeline->data.flags |= XCONFIG_MODE_PHSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "-hsync")) {
+ modeline->data.flags |= XCONFIG_MODE_NHSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "+vsync")) {
+ modeline->data.flags |= XCONFIG_MODE_PVSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "-vsync")) {
+ modeline->data.flags |= XCONFIG_MODE_NVSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "interlace")) {
+ modeline->data.flags |= XCONFIG_MODE_INTERLACE;
+ }
+ else if (!xconfigNameCompare(tmp, "doublescan")) {
+ modeline->data.flags |= XCONFIG_MODE_DBLSCAN;
+ }
+ else if (!xconfigNameCompare(tmp, "composite")) {
+ modeline->data.flags |= XCONFIG_MODE_CSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "+csync")) {
+ modeline->data.flags |= XCONFIG_MODE_PCSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "-csync")) {
+ modeline->data.flags |= XCONFIG_MODE_NCSYNC;
+ }
+ else if (!xconfigNameCompare(tmp, "hskew")) {
+ str = parse_read_integer(str, &(modeline->data.hskew));
+ if (!str) {
+ free(tmp);
+ goto fail;
+ }
+ modeline->data.flags |= XCONFIG_MODE_HSKEW;
+ }
+ else if (!xconfigNameCompare(tmp, "bcast")) {
+ modeline->data.flags |= XCONFIG_MODE_BCAST;
+ }
+ else if (!xconfigNameCompare(tmp, "CUSTOM")) {
+ modeline->data.flags |= XCONFIG_MODE_CUSTOM;
+ }
+ else if (!xconfigNameCompare(tmp, "vscan")) {
+ str = parse_read_integer(str, &(modeline->data.vscan));
+ if (!str) {
+ free(tmp);
+ goto fail;
+ }
+ modeline->data.flags |= XCONFIG_MODE_VSCAN;
+ }
+ else {
+ nv_warning_msg("Invalid modeline keyword '%s' in modeline '%s'",
+ tmp, modeline_str);
+ goto fail;
+ }
+ free(tmp);
+ }
+
+ return modeline;
+
+
+ /* Handle failures */
+ fail:
+ free(modeline);
+ return NULL;
+
+} /* modeline_parse() */
+
+
+
+
+/*****************************************************************************/
+/** MODE FUNCTIONS ***********************************************************/
+/*****************************************************************************/
+
+
+/** mode_parse() *****************************************************
+ *
+ * Converts a mode string (dpy specific part of a metamode) to a
+ * mode structure that the display configuration page can use.
+ *
+ * Mode strings have the following format:
+ *
+ * "mode_name +X+Y @WxH"
+ *
+ **/
+nvModePtr mode_parse(nvDisplayPtr display, const char *mode_str)
+{
+ nvModePtr mode;
+ char *mode_name; /* Modeline reference name */
+ const char *str = mode_str;
+
+
+
+ if (!str || !display || !display->modelines) return NULL;
+
+
+ /* Allocate a Mode structure */
+ mode = (nvModePtr)calloc(1, sizeof(nvMode));
+ if (!mode) return NULL;
+
+ mode->display = display;
+
+
+ /* Read the mode name */
+ str = parse_read_name(str, &mode_name, ' ');
+ if (!str || !mode_name) goto fail;
+
+
+ /* Match the mode name to one of the modelines */
+ mode->modeline = display->modelines;
+ while (mode->modeline) {
+ if (!strcmp(mode_name, mode->modeline->data.identifier)) {
+ break;
+ }
+ mode->modeline = mode->modeline->next;
+ }
+ free(mode_name);
+
+
+ /* If we can't find a matching modeline, show device as off
+ * using the width & height of whatever the first modeline is.
+ * XXX Hopefully this is the default width/height.
+ */
+ if (!mode->modeline) {
+ if (strcmp(mode_str, "NULL")) {
+ nv_warning_msg("Mode name '%s' does not match any modelines for "
+ "display device '%s' in modeline '%s'.",
+ mode_name, display->name, mode_str);
+ }
+ mode->dim[W] = display->modelines->data.hdisplay;
+ mode->dim[H] = display->modelines->data.vdisplay;
+ mode->pan[W] = mode->dim[W];
+ mode->pan[H] = mode->dim[H];
+ return mode;
+ }
+
+
+ /* Setup default size and panning of display */
+ mode->dim[W] = mode->modeline->data.hdisplay;
+ mode->dim[H] = mode->modeline->data.vdisplay;
+ mode->pan[W] = mode->dim[W];
+ mode->pan[H] = mode->dim[H];
+
+
+ /* Read mode information */
+ while (*str) {
+
+ /* Read panning */
+ if (*str == '@') {
+ str++;
+ str = parse_read_integer_pair(str, 'x',
+ &(mode->pan[W]), &(mode->pan[H]));
+ }
+
+ /* Read position */
+ else if (*str == '+') {
+ str++;
+ str = parse_read_integer_pair(str, 0,
+ &(mode->dim[X]), &(mode->dim[Y]));
+ }
+
+ /* Mode parse error - Ack! */
+ else {
+ str = NULL;
+ }
+
+ /* Catch errors */
+ if (!str) goto fail;
+ }
+
+
+ /* These are the same for now */
+ mode->pan[X] = mode->dim[X];
+ mode->pan[Y] = mode->dim[Y];
+
+
+ /* Panning can't be smaller than dimensions */
+ if (mode->pan[W] < mode->dim[W]) {
+ mode->pan[W] = mode->dim[W];
+ }
+ if (mode->pan[W] < mode->dim[W]) {
+ mode->pan[W] = mode->dim[W];
+ }
+
+ return mode;
+
+
+ /* Handle failures */
+ fail:
+ if (mode) {
+ free(mode);
+ }
+
+ return NULL;
+
+} /* mode_parse() */
+
+
+
+/** mode_get_str() ***************************************************
+ *
+ * Returns the mode string of the given mode in the following format:
+ *
+ * "mode_name @WxH +X+Y"
+ *
+ **/
+static gchar *mode_get_str(nvModePtr mode, int be_generic)
+{
+ gchar *mode_str;
+ gchar *tmp;
+
+
+ /* Make sure the mode has everything it needs to be displayed */
+ if (!mode || !mode->display || !mode->display->gpu || !mode->metamode) {
+ return NULL;
+ }
+
+
+ /* Don't display dummy modes */
+ if (be_generic && mode->dummy && !mode->modeline) {
+ return NULL;
+ }
+
+
+ /* Only one display, be very generic (no 'CRT:' in metamode) */
+ if (be_generic && mode->display->gpu->num_displays == 1) {
+ mode_str = g_strdup("");
+
+ /* If there's more than one CRT/DFP/TV, we can't be generic. */
+ } else {
+ int generic = be_generic;
+
+ if ((mode->display->device_mask & 0x000000FF) &&
+ (mode->display->device_mask !=
+ (mode->display->gpu->connected_displays & 0x000000FF))) {
+ generic = 0;
+ }
+ if ((mode->display->device_mask & 0x0000FF00) &&
+ (mode->display->device_mask !=
+ (mode->display->gpu->connected_displays & 0x0000FF00))) {
+ generic = 0;
+ }
+ if ((mode->display->device_mask & 0x00FF0000) &&
+ (mode->display->device_mask !=
+ (mode->display->gpu->connected_displays & 0x00FF0000))) {
+ generic = 0;
+ }
+
+ /* Get the display type */
+ tmp = display_get_type_str(mode->display->device_mask, generic);
+ mode_str = g_strconcat(tmp, ": ", NULL);
+ g_free(tmp);
+ }
+
+
+ /* NULL mode */
+ if (!mode->modeline) {
+ tmp = g_strconcat(mode_str, "NULL", NULL);
+ g_free(mode_str);
+ return tmp;
+ }
+
+
+ /* Mode name */
+ tmp = g_strconcat(mode_str, mode->modeline->data.identifier, NULL);
+ g_free(mode_str);
+ mode_str = tmp;
+
+
+ /* Panning domain */
+ if (!be_generic || (mode->pan[W] != mode->dim[W] ||
+ mode->pan[H] != mode->dim[H])) {
+ tmp = g_strdup_printf("%s @%dx%d",
+ mode_str, mode->pan[W], mode->pan[H]);
+ g_free(mode_str);
+ mode_str = tmp;
+ }
+
+
+ /* Offset */
+
+ /*
+ * XXX Later, we'll want to allow the user to select how
+ * the metamodes are generated:
+ *
+ * Programability:
+ * make mode->dim relative to screen->dim
+ *
+ * Coherency:
+ * make mode->dim relative to mode->metamode->edim
+ *
+ *
+ * XXX Also, we may want to take in consideration the
+ * TwinViewOrientation when writing out position
+ * information.
+ */
+
+ tmp = g_strdup_printf("%s +%d+%d",
+ mode_str,
+ /* Make mode position relative */
+ mode->dim[X] - mode->metamode->edim[X],
+ mode->dim[Y] - mode->metamode->edim[Y]);
+ g_free(mode_str);
+ mode_str = tmp;
+
+
+ return mode_str;
+
+} /* mode_get_str() */
+
+
+
+
+/*****************************************************************************/
+/** DISPLAY FUNCTIONS ********************************************************/
+/*****************************************************************************/
+
+
+/** display_get_type_str() *******************************************
+ *
+ * Returns the type name of a display (CRT, CRT-1, DFP ..)
+ *
+ * If 'generic' is set to 1, then a generic version of the name is
+ * returned.
+ *
+ **/
+gchar *display_get_type_str(unsigned int device_mask, int be_generic)
+{
+ unsigned int bit = 0;
+ int num;
+ gchar *name = NULL;
+ gchar *type_name;
+
+
+ /* Get the generic type name of the display */
+ if (device_mask & 0x000000FF) {
+ name = g_strdup("CRT");
+ bit = (device_mask & 0x000000FF);
+
+ } else if (device_mask & 0x0000FF00) {
+ name = g_strdup("TV");
+ bit = (device_mask & 0x0000FF00) >> 8;
+
+ } else if (device_mask & 0x00FF0000) {
+ name = g_strdup("DFP");
+ bit = (device_mask & 0x00FF0000) >> 16;
+ }
+
+ if (be_generic || !name) {
+ return name;
+ }
+
+ /* Add the specific display number to the name */
+ num = 0;
+ while (bit) {
+ num++;
+ bit >>= 1;
+ }
+ if (num) {
+ num--;
+ }
+
+ type_name = g_strdup_printf("%s-%d", name, num);
+ g_free(name);
+
+ return type_name;
+
+} /* display_get_type_str() */
+
+
+
+/** display_find_closest_mode_matching_modeline() ********************
+ *
+ * Helper function that returns the mode index of the display's mode
+ * that best matches the given modeline.
+ *
+ * A best match is:
+ *
+ * - The modelines are the same.
+ * - The modelines match in width & height.
+ *
+ **/
+int display_find_closest_mode_matching_modeline(nvDisplayPtr display,
+ nvModeLinePtr modeline)
+{
+ nvModePtr mode;
+ int mode_idx;
+ int match_idx = -1;
+
+ mode_idx = 0;
+ for (mode = display->modes; mode; mode = mode->next) {
+ if (mode->modeline->data.vdisplay == modeline->data.vdisplay &&
+ mode->modeline->data.hdisplay == modeline->data.hdisplay) {
+ match_idx = mode_idx;
+ }
+ if (mode->modeline == modeline) break;
+ mode_idx++;
+ }
+
+ return match_idx;
+
+} /* display_find_closest_mode_matching_modeline() */
+
+
+
+/** display_remove_modelines() ***************************************
+ *
+ * Clears the display device's modeline list.
+ *
+ **/
+static void display_remove_modelines(nvDisplayPtr display)
+{
+ nvModeLinePtr modeline;
+
+ if (display) {
+ while (display->modelines) {
+ modeline = display->modelines;
+ display->modelines = display->modelines->next;
+ free(modeline);
+ }
+ display->num_modelines = 0;
+ }
+
+} /* display_remove_modelines() */
+
+
+
+/** display_add_modelines_from_server() ******************************
+ *
+ * Queries the display's current modepool (modelines list).
+ *
+ **/
+Bool display_add_modelines_from_server(nvDisplayPtr display, gchar **err_str)
+{
+ nvModeLinePtr modeline;
+ char *modeline_strs = NULL;
+ char *str;
+ int len;
+ ReturnStatus ret;
+
+
+ /* Free any old mode lines */
+ display_remove_modelines(display);
+
+
+ /* Get the validated modelines for the display */
+ ret = NvCtrlGetBinaryAttribute(display->gpu->handle,
+ display->device_mask,
+ NV_CTRL_BINARY_DATA_MODELINES,
+ (unsigned char **)&modeline_strs, &len);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query modelines of display "
+ "device 0x%08x '%s'\nconnected to "
+ "GPU-%d '%s'.",
+ display->device_mask, display->name,
+ NvCtrlGetTargetId(display->gpu->handle),
+ display->gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Parse each modeline */
+ str = modeline_strs;
+ while (strlen(str)) {
+
+ modeline = modeline_parse(str);
+ if (!modeline) {
+ *err_str = g_strdup_printf("Failed to parse the following "
+ "modeline of display device\n"
+ "0x%08x '%s' connected to GPU-%d "
+ "'%s':\n\n%s",
+ display->device_mask,
+ display->name,
+ NvCtrlGetTargetId(display->gpu->handle),
+ display->gpu->name,
+ str);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ /* Add the modeline at the end of the display's modeline list */
+ display->modelines = (nvModeLinePtr)xconfigAddListItem
+ ((GenericListPtr)display->modelines, (GenericListPtr)modeline);
+ display->num_modelines++;
+
+ /* Get next modeline string */
+ str += strlen(str) +1;
+ }
+
+ XFree(modeline_strs);
+ return TRUE;
+
+
+ /* Handle the failure case */
+ fail:
+ display_remove_modelines(display);
+ XFree(modeline_strs);
+ return FALSE;
+
+} /* display_add_modelines_from_server() */
+
+
+
+/** display_get_mode_str() *******************************************
+ *
+ * Returns the mode string of the display's 'mode_idx''s
+ * mode.
+ *
+ **/
+static gchar *display_get_mode_str(nvDisplayPtr display, int mode_idx,
+ int be_generic)
+{
+ nvModePtr mode = display->modes;
+
+ while (mode && mode_idx) {
+ mode = mode->next;
+ mode_idx--;
+ }
+
+ if (mode) {
+ return mode_get_str(mode, be_generic);
+ }
+
+ return NULL;
+
+} /* display_get_mode_str() */
+
+
+
+/** display_remove_modes() *******************************************
+ *
+ * Removes all modes currently referenced by this screen, also
+ * freeing any memory used.
+ *
+ **/
+void display_remove_modes(nvDisplayPtr display)
+{
+ nvModePtr mode;
+
+ if (display) {
+ while (display->modes) {
+ mode = display->modes;
+ display->modes = mode->next;
+ free(mode);
+ }
+ display->num_modes = 0;
+ display->cur_mode = NULL;
+ }
+
+} /* display_remove_modes() */
+
+
+
+/** display_free() ***************************************************
+ *
+ * Frees memory used by a display
+ *
+ **/
+static void display_free(nvDisplayPtr display)
+{
+ if (display) {
+ display_remove_modes(display);
+ display_remove_modelines(display);
+ XFree(display->name);
+ free(display);
+ }
+
+} /* display_free() */
+
+
+
+
+/*****************************************************************************/
+/** METAMODE FUNCTIONS *******************************************************/
+/*****************************************************************************/
+
+
+
+
+/*****************************************************************************/
+/** SCREEN FUNCTIONS *********************************************************/
+/*****************************************************************************/
+
+
+/** screen_remove_display() ******************************************
+ *
+ * Removes a display device from the screen
+ *
+ **/
+void screen_remove_display(nvDisplayPtr display)
+{
+ nvGpuPtr gpu;
+ nvScreenPtr screen;
+ nvDisplayPtr other;
+ nvModePtr mode;
+
+
+ if (display && display->screen) {
+ screen = display->screen;
+ gpu = display->gpu;
+
+ /* Make any display relative to this one use absolute position */
+ for (other = gpu->displays; other; other = other->next) {
+
+ if (other == display) continue;
+ if (other->screen != screen) continue;
+
+ for (mode = other->modes; mode; mode = mode->next) {
+ if (mode->relative_to == display) {
+ mode->position_type = CONF_ADJ_ABSOLUTE;
+ mode->relative_to = NULL;
+ }
+ }
+ }
+
+ /* Remove the display from the screen */
+ screen->displays_mask &= ~(display->device_mask);
+ screen->num_displays--;
+
+ /* Clean up old references to the screen in the display */
+ display_remove_modes(display);
+ display->screen = NULL;
+ }
+
+} /* screen_remove_display() */
+
+
+
+/** screen_remove_displays() *****************************************
+ *
+ * Removes all displays currently pointing at this screen, also
+ * freeing any memory used.
+ *
+ **/
+static void screen_remove_displays(nvScreenPtr screen)
+{
+ nvGpuPtr gpu;
+ nvDisplayPtr display;
+
+ if (screen && screen->gpu) {
+ gpu = screen->gpu;
+
+ for (display = gpu->displays; display; display = display->next) {
+
+ if (display->screen != screen) continue;
+
+ screen_remove_display(display);
+ }
+ }
+
+} /* screen_remove_displays() */
+
+
+
+/** screen_get_metamode_str() ****************************************
+ *
+ * Returns a screen's metamode string for the given metamode index
+ * as:
+ *
+ * "mode1_1, mode1_2, mode1_3 ... "
+ *
+ **/
+gchar *screen_get_metamode_str(nvScreenPtr screen, int metamode_idx,
+ int be_generic)
+{
+ nvDisplayPtr display;
+
+ gchar *metamode_str = NULL;
+ gchar *mode_str;
+ gchar *tmp;
+
+ for (display = screen->gpu->displays; display; display = display->next) {
+
+ if (display->screen != screen) continue; /* Display not in screen */
+
+ mode_str = display_get_mode_str(display, metamode_idx, be_generic);
+ if (!mode_str) continue;
+
+ if (!metamode_str) {
+ metamode_str = mode_str;
+ } else {
+ tmp = g_strdup_printf("%s, %s", metamode_str, mode_str);
+ g_free(mode_str);
+ g_free(metamode_str);
+ metamode_str = tmp;
+ }
+ }
+
+ return metamode_str;
+
+} /* screen_get_metamode_str() */
+
+
+
+/** screen_remove_metamodes() ****************************************
+ *
+ * Removes all metamodes currently referenced by this screen, also
+ * freeing any memory used.
+ *
+ **/
+static void screen_remove_metamodes(nvScreenPtr screen)
+{
+ nvGpuPtr gpu;
+ nvDisplayPtr display;
+ nvMetaModePtr metamode;
+
+ if (screen) {
+ gpu = screen->gpu;
+
+ /* Remove the modes from this screen's displays */
+ if (gpu) {
+ for (display = gpu->displays; display; display = display->next) {
+
+ if (display->screen != screen) continue;
+
+ display_remove_modes(display);
+ }
+ }
+
+ /* Clear the screen's metamode list */
+ while (screen->metamodes) {
+ metamode = screen->metamodes;
+ screen->metamodes = metamode->next;
+ free(metamode->string);
+ free(metamode);
+ }
+ screen->num_metamodes = 0;
+ screen->cur_metamode = NULL;
+ screen->cur_metamode_idx = -1;
+ }
+
+} /* screen_remove_metamodes() */
+
+
+
+/** screen_add_metamode() ********************************************
+ *
+ * Parses a metamode string and adds the appropreate modes to the
+ * screen's display devices (at the end of the list)
+ *
+ **/
+static Bool screen_add_metamode(nvScreenPtr screen, char *metamode_str,
+ gchar **err_str)
+{
+ char *mode_str;
+ char *str = NULL;
+ char *tmp;
+ char *tokens;
+ nvMetaModePtr metamode;
+
+
+ if (!screen || !screen->gpu || !metamode_str) goto fail;
+
+
+ metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode));
+ if (!metamode) goto fail;
+
+
+ /* Copy the string so we can split it up */
+ str = strdup(metamode_str);
+ if (!str) goto fail;
+
+
+ /* Read the MetaMode ID */
+ tmp = strstr(str, "::");
+ if (tmp) {
+ tokens = strdup(str);
+ tokens[ tmp-str ] = '\0';
+ tmp += 2;
+ parse_token_value_pairs(tokens, apply_metamode_token,
+ (void *)metamode);
+ free(tokens);
+ } else {
+ /* No tokens? Try the old "ID: METAMODE_STR" syntax */
+ tmp = (char *)parse_read_integer(str, &(metamode->id));
+ metamode->source = METAMODE_SOURCE_NVCONTROL;
+ if (*tmp == ':') {
+ tmp++;
+ }
+ }
+
+
+ /* Add the metamode at the end of the screen's metamode list */
+ screen->metamodes =
+ (nvMetaModePtr)xconfigAddListItem((GenericListPtr)screen->metamodes,
+ (GenericListPtr)metamode);
+
+
+ /* Split up the metamode into separate modes */
+ for (mode_str = strtok(tmp, ",");
+ mode_str;
+ mode_str = strtok(NULL, ",")) {
+
+ nvModePtr mode;
+ unsigned int device_mask;
+ nvDisplayPtr display;
+ const char *orig_mode_str = parse_skip_whitespace(mode_str);
+
+
+ /* Parse the display device bitmask from the name */
+ mode_str = (char *)parse_read_display_name(mode_str, &device_mask);
+ if (!mode_str) {
+ *err_str = g_strdup_printf("Failed to read a display device name "
+ "on screen %d (on GPU-%d)\nwhile "
+ "parsing metamode:\n\n'%s'",
+ screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle),
+ orig_mode_str);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Match device bitmask to an existing display */
+ display = gpu_get_display(screen->gpu, device_mask);
+ if (!display) {
+ *err_str = g_strdup_printf("Failed to find display device 0x%08x "
+ "on screen %d (on GPU-%d)\nwhile "
+ "parsing metamode:\n\n'%s'",
+ device_mask,
+ screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle),
+ orig_mode_str);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Parse the mode */
+ mode = mode_parse(display, mode_str);
+ if (!mode) {
+ *err_str = g_strdup_printf("Failed to parse mode '%s'\non "
+ "screen %d (on GPU-%d)\nfrom "
+ "metamode:\n\n'%s'",
+ mode_str, screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle),
+ orig_mode_str);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Make the mode part of the metamode */
+ mode->metamode = metamode;
+
+
+ /* Make the display part of the screen */
+ display->screen = screen;
+
+
+ /* Set the panning offset */
+ mode->pan[X] = mode->dim[X];
+ mode->pan[Y] = mode->dim[Y];
+
+
+ /* Add the mode at the end of the display's mode list */
+ display->modes =
+ (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes,
+ (GenericListPtr)mode);
+ display->num_modes++;
+
+ } /* Done parsing a single metamode */
+
+ free(str);
+ return TRUE;
+
+
+ /* Failure case */
+ fail:
+
+ /* XXX We should probably track which modes were added and remove
+ * them at this point. For now, just assume the caller will
+ * remove all the modes and bail.
+ */
+
+ free(str);
+ return FALSE;
+
+} /* screen_add_metamode() */
+
+
+
+/** screen_check_metamodes() *****************************************
+ *
+ * Makes sure all displays associated with the screen have the right
+ * number of mode entries.
+ *
+ **/
+static Bool screen_check_metamodes(nvScreenPtr screen)
+{
+ nvDisplayPtr display;
+ nvMetaModePtr metamode;
+ nvModePtr mode;
+ nvModePtr last_mode = NULL;
+
+
+ for (display = screen->gpu->displays; display; display = display->next) {
+
+ if (display->screen != screen) continue;
+
+ if (display->num_modes == screen->num_metamodes) continue;
+
+ mode = display->modes;
+ metamode = screen->metamodes;
+ while (mode && metamode) {
+ mode = mode->next;
+ metamode = metamode->next;
+ if (mode) {
+ last_mode = mode;
+ }
+ }
+
+ /* Each display must have as many modes as it's screen has metamodes */
+ while (metamode) {
+
+ /* Create a dumy mode */
+ mode = mode_parse(display, "NULL");
+ mode->dummy = 1;
+ mode->metamode = metamode;
+
+ /* Duplicate position information of the last mode */
+ if (last_mode) {
+ mode->dim[X] = last_mode->dim[X];
+ mode->dim[Y] = last_mode->dim[Y];
+ mode->pan[X] = last_mode->pan[X];
+ mode->pan[Y] = last_mode->pan[Y];
+ mode->position_type = last_mode->position_type;
+ mode->relative_to = last_mode->relative_to;
+ }
+
+ /* Add the mode at the end of display's mode list */
+ display->modes =
+ (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes,
+ (GenericListPtr)mode);
+ display->num_modes++;
+
+ metamode = metamode->next;
+ }
+
+ /* XXX Shouldn't need to remove extra modes.
+ while (mode) {
+ }
+ */
+ }
+
+ return TRUE;
+
+} /* screen_check_metamodes() */
+
+
+
+/** screen_assign_dummy_metamode_positions() *************************
+ *
+ * Assign the initial (top left) position of dummy modes to
+ * match the top left of the first non-dummy mode
+ *
+ **/
+void screen_assign_dummy_metamode_positions(nvScreenPtr screen)
+{
+ nvDisplayPtr display;
+ nvModePtr ok_mode;
+ nvModePtr mode;
+
+
+ for (display = screen->gpu->displays; display; display = display->next) {
+ if (display->screen != screen) continue;
+
+ /* Get the first non-dummy mode */
+ for (ok_mode = display->modes; ok_mode; ok_mode = ok_mode->next) {
+ if (!ok_mode->dummy) break;
+ }
+
+ if (ok_mode) {
+ for (mode = display->modes; mode; mode = mode->next) {
+ if (!mode->dummy) continue;
+ mode->dim[X] = ok_mode->dim[X];
+ mode->pan[X] = ok_mode->dim[X];
+ mode->dim[Y] = ok_mode->dim[Y];
+ mode->pan[Y] = ok_mode->dim[Y];
+ }
+ }
+ }
+
+} /* screen_assign_dummy_metamode_positions() */
+
+
+
+/** screen_add_metamodes() *******************************************
+ *
+ * Adds all the appropreate modes on all display devices of this
+ * screen by parsing all the metamode strings.
+ *
+ **/
+static Bool screen_add_metamodes(nvScreenPtr screen, gchar **err_str)
+{
+ nvDisplayPtr display;
+
+ char *metamode_strs = NULL; /* Screen's list metamode strings */
+ char *cur_metamode_str; /* Current metamode */
+
+ char *str; /* Temp pointer for parsing */
+ int len;
+ ReturnStatus ret;
+ int i;
+
+
+
+ /* Get the list of metamodes for the screen */
+ ret = NvCtrlGetBinaryAttribute(screen->handle, 0,
+ NV_CTRL_BINARY_DATA_METAMODES,
+ (unsigned char **)&metamode_strs,
+ &len);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query list of metamodes on\n"
+ "screen %d (on GPU-%d).",
+ screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle));
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Get the current metamode for the screen */
+ ret = NvCtrlGetStringAttribute(screen->handle,
+ NV_CTRL_STRING_CURRENT_METAMODE,
+ &cur_metamode_str);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query current metamode of\n"
+ "screen %d (on GPU-%d).",
+ screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle));
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Remove any existing modes on all displays */
+ screen_remove_metamodes(screen);
+
+
+ /* Parse each mode in the metamode strings */
+ str = metamode_strs;
+ while (str && strlen(str)) {
+
+ /* Add the individual metamodes to the screen,
+ * This populates the display device's mode list.
+ */
+ if (!screen_add_metamode(screen, str, err_str)) {
+ nv_warning_msg("Failed to add metamode '%s' to screen %d (on "
+ "GPU-%d).",
+ str, screen->scrnum,
+ NvCtrlGetTargetId(screen->gpu->handle));
+ goto fail;
+ }
+
+ /* Keep track of the current metamode */
+ if (!strcmp(str, cur_metamode_str)) {
+ screen->cur_metamode_idx = screen->num_metamodes;
+ }
+
+ /* Keep count of the metamode */
+ screen->num_metamodes++;
+
+ /* Make sure each display device gets a mode */
+ screen_check_metamodes(screen);
+
+ /* Go to the next metamode */
+ str += strlen(str) +1;
+ }
+ XFree(metamode_strs);
+
+
+ /* Assign the top left position of dummy modes */
+ screen_assign_dummy_metamode_positions(screen);
+
+
+ /* Make the screen point at the current metamode */
+ screen->cur_metamode = screen->metamodes;
+ for (i = 0; i < screen->cur_metamode_idx; i++) {
+ screen->cur_metamode = screen->cur_metamode->next;
+ }
+
+
+ /* Make each display within the screen point to the current mode.
+ * Also, count the number of displays on the screen
+ */
+ screen->num_displays = 0;
+ for (display = screen->gpu->displays; display; display = display->next) {
+
+ if (display->screen != screen) continue; /* Display not in screen */
+
+ screen->num_displays++;
+ screen->displays_mask |= display->device_mask;
+
+ display->cur_mode = display->modes;
+ for (i = 0; i < screen->cur_metamode_idx; i++) {
+ display->cur_mode = display->cur_mode->next;
+ }
+ }
+
+ return TRUE;
+
+
+ /* Failure case */
+ fail:
+
+ /* Remove modes we may have added */
+ screen_remove_metamodes(screen);
+
+ XFree(metamode_strs);
+ return FALSE;
+
+} /* screen_add_metamodes() */
+
+
+
+/** screen_free() ****************************************************
+ *
+ * Frees memory used by a screen structure
+ *
+ **/
+static void screen_free(nvScreenPtr screen)
+{
+ if (screen) {
+
+ screen_remove_metamodes(screen);
+ screen_remove_displays(screen);
+
+ if (screen->handle) {
+ NvCtrlAttributeClose(screen->handle);
+ }
+
+ free(screen);
+ }
+
+} /* screen_free() */
+
+
+
+
+/*****************************************************************************/
+/** GPU FUNCTIONS ************************************************************/
+/*****************************************************************************/
+
+
+/** gpu_get_display() ************************************************
+ *
+ * Returns the display with the matching device_mask or NULL if not
+ * found.
+ *
+ **/
+nvDisplayPtr gpu_get_display(nvGpuPtr gpu, unsigned int device_mask)
+{
+ nvDisplayPtr display;
+
+ for (display = gpu->displays; display; display = display->next) {
+ if (display->device_mask == device_mask) return display;
+ }
+
+ return NULL;
+
+} /* gpu_get_display() */
+
+
+
+/** gpu_remove_and_free_display() ************************************
+ *
+ * Removes a display from the GPU and frees it.
+ *
+ **/
+void gpu_remove_and_free_display(nvDisplayPtr display)
+{
+ nvGpuPtr gpu;
+ nvScreenPtr screen;
+
+
+ if (display && display->gpu) {
+ gpu = display->gpu;
+ screen = display->screen;
+
+ /* Remove the display from the screen it may be in */
+ if (screen) {
+ screen_remove_display(display);
+
+ /* If the screen is empty, remove it too */
+ if (!screen->num_displays) {
+ gpu_remove_and_free_screen(screen);
+ }
+ }
+
+ /* Remove the display from the GPU */
+ gpu->displays =
+ (nvDisplayPtr)xconfigRemoveListItem((GenericListPtr)gpu->displays,
+ (GenericListPtr)display);
+ gpu->connected_displays &= ~(display->device_mask);
+ gpu->num_displays--;
+ }
+
+ display_free(display);
+
+} /* gpu_remove_and_free_display() */
+
+
+
+/** gpu_remove_displays() ********************************************
+ *
+ * Removes all displays from the gpu
+ *
+ **/
+static void gpu_remove_displays(nvGpuPtr gpu)
+{
+ nvDisplayPtr display;
+
+ if (gpu) {
+ while (gpu->displays) {
+ display = gpu->displays;
+ screen_remove_display(display);
+ gpu->displays = display->next;
+ display_free(display);
+ }
+ //gpu->connected_displays = 0;
+ gpu->num_displays = 0;
+ }
+
+} /* gpu_remove_displays() */
+
+
+
+/** gpu_add_display_from_server() ************************************
+ *
+ * Adds the display with the device mask given to the GPU structure.
+ *
+ **/
+nvDisplayPtr gpu_add_display_from_server(nvGpuPtr gpu,
+ unsigned int device_mask,
+ gchar **err_str)
+{
+ ReturnStatus ret;
+ nvDisplayPtr display = NULL;
+
+
+ /* Create the display structure */
+ display = (nvDisplayPtr)calloc(1, sizeof(nvDisplay));
+ if (!display) goto fail;
+
+
+ /* Init the display structure */
+ display->gpu = gpu;
+ display->device_mask = device_mask;
+
+
+ /* Query the display information */
+ ret = NvCtrlGetStringDisplayAttribute(gpu->handle,
+ device_mask,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &(display->name));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query name of display device\n"
+ "0x%08x connected to GPU-%d '%s'.",
+ device_mask, NvCtrlGetTargetId(gpu->handle),
+ gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Query the modelines for the display device */
+ if (!display_add_modelines_from_server(display, err_str)) {
+ nv_warning_msg("Failed to add modelines to display device 0x%08x "
+ "'%s'\nconnected to GPU-%d '%s'.",
+ device_mask, display->name,
+ NvCtrlGetTargetId(gpu->handle), gpu->name);
+ goto fail;
+ }
+
+
+ /* Add the display at the end of gpu's display list */
+ gpu->displays =
+ (nvDisplayPtr)xconfigAddListItem((GenericListPtr)gpu->displays,
+ (GenericListPtr)display);
+ gpu->connected_displays |= device_mask;
+ gpu->num_displays++;
+ return display;
+
+
+ /* Failure case */
+ fail:
+ display_free(display);
+ return NULL;
+
+} /* gpu_add_display_from_server() */
+
+
+
+/** gpu_add_displays_from_server() ***********************************
+ *
+ * Adds the display devices connected on the GPU to the GPU structure
+ *
+ **/
+static Bool gpu_add_displays_from_server(nvGpuPtr gpu, gchar **err_str)
+{
+ unsigned int mask;
+
+
+ /* Clean up the GPU list */
+ gpu_remove_displays(gpu);
+
+
+ // XXX Query connected_displays here...
+
+
+ /* Add each connected display */
+ for (mask = 1; mask; mask <<= 1) {
+
+ if (!(mask & (gpu->connected_displays))) continue;
+
+ if (!gpu_add_display_from_server(gpu, mask, err_str)) {
+ nv_warning_msg("Failed to add display device 0x%08x to GPU-%d "
+ "'%s'.",
+ mask, NvCtrlGetTargetId(gpu->handle), gpu->name);
+ goto fail;
+ }
+ }
+
+ return TRUE;
+
+
+ /* Failure case */
+ fail:
+ gpu_remove_displays(gpu);
+ return FALSE;
+
+} /* gpu_add_displays_from_server() */
+
+
+
+/** gpu_remove_and_free_screen() *************************************
+ *
+ * Removes a screen from its GPU and frees it.
+ *
+ **/
+void gpu_remove_and_free_screen(nvScreenPtr screen)
+{
+ nvGpuPtr gpu;
+ nvScreenPtr other;
+
+ if (screen && screen->gpu) {
+
+ /* Remove the screen from the GPU */
+ gpu = screen->gpu;
+
+ gpu->screens =
+ (nvScreenPtr)xconfigRemoveListItem((GenericListPtr)gpu->screens,
+ (GenericListPtr)screen);
+ gpu->num_screens--;
+
+ /* Make sure other screens in the layout aren't relative
+ * to this screen
+ */
+ for (gpu = screen->gpu->layout->gpus; gpu; gpu = gpu->next) {
+ for (other = gpu->screens; other; other = other->next) {
+ if (other->relative_to == screen) {
+ other->position_type = CONF_ADJ_ABSOLUTE;
+ other->relative_to = NULL;
+ }
+ }
+ }
+ }
+
+ screen_free(screen);
+
+} /* gpu_remove_and_free_screen() */
+
+
+
+/** gpu_remove_screens() *********************************************
+ *
+ * Removes all screens from a gpu and frees them
+ *
+ **/
+static void gpu_remove_screens(nvGpuPtr gpu)
+{
+ nvScreenPtr screen;
+
+ if (gpu) {
+ while (gpu->screens) {
+ screen = gpu->screens;
+ gpu->screens = screen->next;
+ screen_free(screen);
+ }
+ gpu->num_screens = 0;
+ }
+
+} /* gpu_remove_screens() */
+
+
+
+/** gpu_add_screen_from_server() *************************************
+ *
+ * Adds screen 'screen_id' that is connected to the gpu.
+ *
+ **/
+static int gpu_add_screen_from_server(nvGpuPtr gpu, int screen_id,
+ gchar **err_str)
+{
+ Display *display;
+ nvScreenPtr screen;
+ int val;
+ ReturnStatus ret;
+
+
+ /* Create the screen structure */
+ screen = (nvScreenPtr)calloc(1, sizeof(nvScreen));
+ if (!screen) goto fail;
+
+ screen->gpu = gpu;
+ screen->scrnum = screen_id;
+
+
+ /* Make an NV-CONTROL handle to talk to the screen */
+ display = NvCtrlGetDisplayPtr(gpu->handle);
+ screen->handle =
+ NvCtrlAttributeInit(display,
+ NV_CTRL_TARGET_TYPE_X_SCREEN,
+ screen_id,
+ NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM |
+ NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM);
+ if (!screen->handle) {
+ *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for\n"
+ "screen %d (on GPU-%d).",
+ screen_id, NvCtrlGetTargetId(gpu->handle));
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Make sure this screen supports dynamic twinview */
+ ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_DYNAMIC_TWINVIEW,
+ &val);
+ if (ret != NvCtrlSuccess || !val) {
+ *err_str = g_strdup_printf("Dynamic TwinView is disabled on "
+ "screen %d.",
+ screen_id);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* The display owner GPU gets the screen(s) */
+ ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_MULTIGPU_DISPLAY_OWNER,
+ &val);
+ if (ret != NvCtrlSuccess || val != NvCtrlGetTargetId(gpu->handle)) {
+ screen_free(screen);
+ return TRUE;
+ }
+
+
+ /* Listen to NV-CONTROL events on this screen handle */
+ screen->ctk_event = CTK_EVENT(ctk_event_new(screen->handle));
+
+
+ /* Query the depth of the screen */
+ screen->depth = NvCtrlGetScreenPlanes(screen->handle);
+
+
+ /* Parse the screen's metamodes (ties displays on the gpu to the screen) */
+ if (!screen_add_metamodes(screen, err_str)) {
+ nv_warning_msg("Failed to add metamodes to screen %d (on GPU-%d).",
+ screen_id, NvCtrlGetTargetId(gpu->handle));
+ goto fail;
+ }
+
+
+ /* Add the screen at the end of the gpu's screen list */
+ gpu->screens =
+ (nvScreenPtr)xconfigAddListItem((GenericListPtr)gpu->screens,
+ (GenericListPtr)screen);
+ gpu->num_screens++;
+ return TRUE;
+
+
+ fail:
+ screen_free(screen);
+ return FALSE;
+
+} /* gpu_add_screen_from_server() */
+
+
+
+/** gpu_add_screens_from_server() ************************************
+ *
+ * Queries the list of screens on the gpu.
+ *
+ */
+static Bool gpu_add_screens_from_server(nvGpuPtr gpu, gchar **err_str)
+{
+ ReturnStatus ret;
+ int *pData;
+ int len;
+ int i;
+
+
+ /* Clean up the GPU list */
+ gpu_remove_screens(gpu);
+
+
+ /* Query the list of X screens this GPU is driving */
+ ret = NvCtrlGetBinaryAttribute(gpu->handle, 0,
+ NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU,
+ (unsigned char **)(&pData), &len);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query list of screens driven\n"
+ "by GPU-%d '%s'.",
+ NvCtrlGetTargetId(gpu->handle), gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Add each X screen */
+ for (i = 1; i <= pData[0]; i++) {
+ if (!gpu_add_screen_from_server(gpu, pData[i], err_str)) {
+ nv_warning_msg("Failed to add screen %d to GPU-%d '%s'.",
+ pData[i], NvCtrlGetTargetId(gpu->handle),
+ gpu->name);
+ goto fail;
+ }
+ }
+
+ return TRUE;
+
+
+ /* Failure case */
+ fail:
+ gpu_remove_screens(gpu);
+ return FALSE;
+
+} /* gpu_add_screens_from_server() */
+
+
+
+/** gpu_add_screenless_modes_to_displays() ***************************
+ *
+ * Adds fake modes to display devices that have no screens so we
+ * can show them on the layout page.
+ *
+ **/
+Bool gpu_add_screenless_modes_to_displays(nvGpuPtr gpu)
+{
+ nvDisplayPtr display;
+ nvModePtr mode;
+
+ for (display = gpu->displays; display; display = display->next) {
+ if (display->screen) continue;
+
+ /* Create a fake mode */
+ mode = (nvModePtr)calloc(1, sizeof(nvMode));
+ if (!mode) return FALSE;
+
+ mode->display = display;
+ mode->dummy = 1;
+
+ mode->dim[W] = 800;
+ mode->dim[H] = 600;
+ mode->pan[W] = mode->dim[W];
+ mode->pan[H] = mode->dim[H];
+
+ /* Add the mode to the display */
+ display->modes = mode;
+ display->cur_mode = mode;
+ display->num_modes = 1;
+ }
+
+ return TRUE;
+
+} /* gpu_add_screenless_modes_to_displays() */
+
+
+
+/** gpu_free() *******************************************************
+ *
+ * Frees memory used by the gpu.
+ *
+ **/
+static void gpu_free(nvGpuPtr gpu)
+{
+ if (gpu) {
+ gpu_remove_screens(gpu);
+ gpu_remove_displays(gpu);
+ XFree(gpu->name);
+ if (gpu->handle) {
+ NvCtrlAttributeClose(gpu->handle);
+ }
+ free(gpu);
+ }
+
+} /* gpu_free() */
+
+
+
+
+/*****************************************************************************/
+/** LAYOUT FUNCTIONS *********************************************************/
+/*****************************************************************************/
+
+
+/** layout_remove_gpus() *********************************************
+ *
+ * Removes all GPUs from the layout structure.
+ *
+ **/
+static void layout_remove_gpus(nvLayoutPtr layout)
+{
+ if (layout) {
+ while (layout->gpus) {
+ nvGpuPtr gpu = layout->gpus;
+ layout->gpus = gpu->next;
+ gpu_free(gpu);
+ }
+ layout->num_gpus = 0;
+ }
+
+} /* layout_remove_gpus() */
+
+
+
+/** layout_add_gpu_from_server() *************************************
+ *
+ * Adds a GPU to the layout structure.
+ *
+ **/
+static Bool layout_add_gpu_from_server(nvLayoutPtr layout, unsigned int gpu_id,
+ gchar **err_str)
+{
+ ReturnStatus ret;
+ Display *dpy;
+ nvGpuPtr gpu = NULL;
+
+
+ /* Create the GPU structure */
+ gpu = (nvGpuPtr)calloc(1, sizeof(nvGpu));
+ if (!gpu) goto fail;
+
+
+ /* Make an NV-CONTROL handle to talk to the GPU */
+ dpy = NvCtrlGetDisplayPtr(layout->handle);
+ gpu->layout = layout;
+ gpu->handle = NvCtrlAttributeInit(dpy, NV_CTRL_TARGET_TYPE_GPU, gpu_id,
+ NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM);
+ if (!gpu->handle) {
+ *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for "
+ "GPU-%d.", gpu_id);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ gpu->ctk_event = CTK_EVENT(ctk_event_new(gpu->handle));
+
+
+ /* Query the GPU information */
+ ret = NvCtrlGetStringAttribute(gpu->handle, NV_CTRL_STRING_PRODUCT_NAME,
+ &gpu->name);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query GPU name of GPU-%d.",
+ gpu_id);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_CONNECTED_DISPLAYS,
+ (int *)&(gpu->connected_displays));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query connected display "
+ "devices on GPU-%d '%s'.",
+ gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_BUS,
+ (int *)&(gpu->pci_bus));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query PCI BUS on GPU-%d '%s'.",
+ gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_DEVICE,
+ (int *)&(gpu->pci_device));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query PCI DEVICE on "
+ "GPU-%d '%s'.", gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_FUNCTION,
+ (int *)&(gpu->pci_func));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query PCI FUNCTION on "
+ "GPU-%d '%s'.", gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_WIDTH,
+ (int *)&(gpu->max_width));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query MAX SCREEN WIDTH on "
+ "GPU-%d '%s'.", gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_HEIGHT,
+ (int *)&(gpu->max_height));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query MAX SCREEN HEIGHT on "
+ "GPU-%d '%s'.", gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+ ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_DISPLAYS,
+ (int *)&(gpu->max_displays));
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup_printf("Failed to query MAX DISPLAYS on "
+ "GPU-%d '%s'.", gpu_id, gpu->name);
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Add the display devices to the GPU */
+ if (!gpu_add_displays_from_server(gpu, err_str)) {
+ nv_warning_msg("Failed to add displays to GPU-%d '%s'.",
+ gpu_id, gpu->name);
+ goto fail;
+ }
+
+
+ /* Add the X screens to the GPU */
+ if (!gpu_add_screens_from_server(gpu, err_str)) {
+ nv_warning_msg("Failed to add screens to GPU-%d '%s'.",
+ gpu_id, gpu->name);
+ goto fail;
+ }
+
+
+ /* Add fake modes to screenless display devices */
+ if (!gpu_add_screenless_modes_to_displays(gpu)) {
+ nv_warning_msg("Failed to add screenless modes to GPU-%d '%s'.",
+ gpu_id, gpu->name);
+ goto fail;
+ }
+
+
+ /* Add the GPU at the end of the layout's GPU list */
+ layout->gpus = (nvGpuPtr)xconfigAddListItem((GenericListPtr)layout->gpus,
+ (GenericListPtr)gpu);
+ layout->num_gpus++;
+ return TRUE;
+
+
+ /* Failure case */
+ fail:
+ gpu_free(gpu);
+ return FALSE;
+
+} /* layout_add_gpu_from_server() */
+
+
+
+/** layout_add_gpus_from_server() ************************************
+ *
+ * Adds the GPUs found on the server to the layout structure.
+ *
+ **/
+static int layout_add_gpus_from_server(nvLayoutPtr layout, gchar **err_str)
+{
+ ReturnStatus ret;
+ int ngpus;
+ int i;
+
+
+ /* Clean up the GPU list */
+ layout_remove_gpus(layout);
+
+
+ /* Query the number of GPUs on the server */
+ ret = NvCtrlQueryTargetCount(layout->handle, NV_CTRL_TARGET_TYPE_GPU,
+ &ngpus);
+ if (ret != NvCtrlSuccess || !ngpus) {
+ *err_str = g_strdup("Failed to query number of GPUs (or no GPUs "
+ "found) in the system.");
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Add each GPU */
+ for (i = 0; i < ngpus; i++) {
+ if (!layout_add_gpu_from_server(layout, i, err_str)) {
+ nv_warning_msg("Failed to add GPU-%d to layout.", i);
+ goto fail;
+ }
+ }
+
+ return layout->num_gpus;
+
+
+ /* Failure case */
+ fail:
+ layout_remove_gpus(layout);
+ return 0;
+
+} /* layout_add_gpus_from_server() */
+
+
+
+/** layout_free() ****************************************************
+ *
+ * Frees a layout structure.
+ *
+ **/
+void layout_free(nvLayoutPtr layout)
+{
+ if (layout) {
+ layout_remove_gpus(layout);
+ free(layout);
+ }
+
+} /* layout_free() */
+
+
+
+/** layout_load_from_server() ****************************************
+ *
+ * Loads layout information from the X server.
+ *
+ **/
+nvLayoutPtr layout_load_from_server(NvCtrlAttributeHandle *handle,
+ gchar **err_str)
+{
+ nvLayoutPtr layout = NULL;
+ ReturnStatus ret;
+
+
+ /* Allocate the layout structure */
+ layout = (nvLayoutPtr)calloc(1, sizeof(nvLayout));
+ if (!layout) goto fail;
+
+
+ /* Cache the handle for talking to the X server */
+ layout->handle = handle;
+
+
+ /* Is Xinerma enabled? */
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA,
+ &layout->xinerama_enabled);
+ if (ret != NvCtrlSuccess) {
+ *err_str = g_strdup("Failed to query status of Xinerama.");
+ nv_error_msg(*err_str);
+ goto fail;
+ }
+
+
+ /* Add GPUs to the layout */
+ if (!layout_add_gpus_from_server(layout, err_str)) {
+ nv_warning_msg("Failed to add GPU(s) to layout for display "
+ "configuration page.");
+ goto fail;
+ }
+
+ return layout;
+
+
+ /* Failure case */
+ fail:
+ layout_free(layout);
+ return NULL;
+
+} /* layout_load_from_server() */
+
+
+
+/** layout_get_a_screen() ********************************************
+ *
+ * Returns a screen from the layout. if 'preferred_gpu' is set,
+ * screens from that gpu are preferred. The screen with the lowest
+ * number is returned.
+ *
+ **/
+nvScreenPtr layout_get_a_screen(nvLayoutPtr layout, nvGpuPtr preferred_gpu)
+{
+ nvGpuPtr gpu;
+ nvScreenPtr screen = NULL;
+ nvScreenPtr other;
+
+ if (!layout) return NULL;
+
+ if (preferred_gpu && preferred_gpu->screens) {
+ gpu = preferred_gpu;
+ } else {
+ preferred_gpu = NULL;
+ gpu = layout->gpus;
+ }
+
+ for (; gpu; gpu = gpu->next) {
+ for (other = gpu->screens; other; other = other->next) {
+ if (!screen || screen->scrnum > other->scrnum) {
+ screen = other;
+ }
+ }
+
+ /* We found a preferred screen */
+ if (gpu == preferred_gpu) break;
+ }
+
+ return screen;
+
+} /* layout_get_a_screen() */
diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.h b/src/gtk+-2.x/ctkdisplayconfig-utils.h
new file mode 100644
index 0000000..1e6f87c
--- /dev/null
+++ b/src/gtk+-2.x/ctkdisplayconfig-utils.h
@@ -0,0 +1,100 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2006 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of Version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2
+ * of the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the:
+ *
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ */
+
+#ifndef __CTK_DISPLAYCONFIG_UTILS_H__
+#define __CTK_DISPLAYCONFIG_UTILS_H__
+
+#include <gtk/gtk.h>
+
+#include "ctkdisplaylayout.h"
+
+
+
+
+G_BEGIN_DECLS
+
+/* Token parsing handlers */
+
+typedef struct _ScreenInfo {
+ int x;
+ int y;
+ int width;
+ int height;
+} ScreenInfo;
+
+void apply_modeline_token(char *token, char *value, void *data);
+void apply_metamode_token(char *token, char *value, void *data);
+void apply_monitor_token(char *token, char *value, void *data);
+void apply_screen_info_token(char *token, char *value, void *data);
+
+
+/* Mode functions */
+
+nvModePtr mode_parse(nvDisplayPtr display, const char *mode_str);
+
+
+/* Display functions */
+
+gchar * display_get_type_str(unsigned int device_mask, int be_generic);
+int display_find_closest_mode_matching_modeline(nvDisplayPtr display,
+ nvModeLinePtr modeline);
+Bool display_add_modelines_from_server(nvDisplayPtr display, gchar **err_str);
+void display_remove_modes(nvDisplayPtr display);
+
+
+/* Metamode functions */
+
+
+/* Screen functions */
+
+void screen_remove_display(nvDisplayPtr display);
+gchar * screen_get_metamode_str(nvScreenPtr screen, int metamode_idx,
+ int be_generic);
+
+
+/* GPU functions */
+
+nvDisplayPtr gpu_get_display(nvGpuPtr gpu, unsigned int device_mask);
+void gpu_remove_and_free_display(nvDisplayPtr display);
+nvDisplayPtr gpu_add_display_from_server(nvGpuPtr gpu,
+ unsigned int device_mask,
+ gchar **err_str);
+
+void gpu_remove_and_free_screen(nvScreenPtr screen);
+Bool gpu_add_screenless_modes_to_displays(nvGpuPtr gpu);
+
+
+/* Layout functions */
+
+void layout_free(nvLayoutPtr layout);
+nvLayoutPtr layout_load_from_server(NvCtrlAttributeHandle *handle,
+ gchar **err_str);
+nvScreenPtr layout_get_a_screen(nvLayoutPtr layout, nvGpuPtr preferred_gpu);
+
+
+
+
+G_END_DECLS
+
+#endif /* __CTK_DISPLAYCONFIG_UTILS_H__ */
diff --git a/src/gtk+-2.x/ctkdisplayconfig.c b/src/gtk+-2.x/ctkdisplayconfig.c
index 17efc31..0993d44 100644
--- a/src/gtk+-2.x/ctkdisplayconfig.c
+++ b/src/gtk+-2.x/ctkdisplayconfig.c
@@ -41,19 +41,21 @@
#include <X11/Xproto.h>
#include "msg.h"
+#include "parse.h"
+
+#include "ctkutils.h"
#include "ctkimage.h"
#include "ctkevent.h"
#include "ctkhelp.h"
#include "ctkdisplayconfig.h"
#include "ctkdisplaylayout.h"
+#include "ctkdisplayconfig-utils.h"
void layout_selected_callback(nvLayoutPtr layout, void *data);
void layout_modified_callback(nvLayoutPtr layout, void *data);
-static GtkWidget * get_window_parent(GtkWidget *child);
-
static void setup_layout_frame(CtkDisplayConfig *ctk_object);
static void setup_display_frame(CtkDisplayConfig *ctk_object);
@@ -84,6 +86,9 @@ static void screen_metamode_delete_clicked(GtkWidget *widget, gpointer user_data
static void xconfig_preview_clicked(GtkWidget *widget, gpointer user_data);
static void xconfig_file_clicked(GtkWidget *widget, gpointer user_data);
+static void xconfig_merge_toggled(GtkWidget *widget, gpointer user_data);
+static void xconfig_file_activate(GtkWidget *widget, gpointer user_data);
+static gboolean update_xconfig_save_buffer(CtkDisplayConfig *ctk_object);
static void xinerama_state_toggled(GtkWidget *widget, gpointer user_data);
static void apply_clicked(GtkWidget *widget, gpointer user_data);
@@ -93,6 +98,9 @@ static void advanced_clicked(GtkWidget *widget, gpointer user_data);
static void reset_clicked(GtkWidget *widget, gpointer user_data);
static void validation_details_clicked(GtkWidget *widget, gpointer user_data);
+static int generateXConfig(CtkDisplayConfig *ctk_object, XConfigPtr *pConfig);
+static void update_banner(XConfigPtr config);
+
@@ -111,9 +119,6 @@ static void validation_details_clicked(GtkWidget *widget, gpointer user_data);
#define GTK_RESPONSE_USER_DISPLAY_ENABLE_TWINVIEW 1
#define GTK_RESPONSE_USER_DISPLAY_ENABLE_XSCREEN 2
-typedef void (* apply_token_func)(char *token, char *value,
- void *data);
-
typedef struct SwitchModeCallbackInfoRec {
CtkDisplayConfig *ctk_object;
int screen;
@@ -241,196 +246,6 @@ static const char * __save_button_help =
/*** F U N C T I O N S *******************************************************/
-/** get_display_type_str() *******************************************
- *
- * Returns the type name of a display (CRT, CRT-1, DFP ..)
- *
- * If 'generic' is set to 1, then a generic version of the name is
- * returned.
- *
- **/
-
-static gchar *get_display_type_str(unsigned int device_mask, int be_generic)
-{
- unsigned int bit = 0;
- int num;
- gchar *name = NULL;
- gchar *type_name;
-
-
- /* Get the generic type name of the display */
- if (device_mask & 0x000000FF) {
- name = g_strdup("CRT");
- bit = (device_mask & 0x000000FF);
-
- } else if (device_mask & 0x0000FF00) {
- name = g_strdup("TV");
- bit = (device_mask & 0x0000FF00) >> 8;
-
- } else if (device_mask & 0x00FF0000) {
- name = g_strdup("DFP");
- bit = (device_mask & 0x00FF0000) >> 16;
- }
-
- if (be_generic || !name) {
- return name;
- }
-
-
- /* Add the specific display number to the name */
- num = 0;
- while (bit) {
- num++;
- bit >>= 1;
- }
- if (num) {
- num--;
- }
-
- type_name = g_strdup_printf("%s-%d", name, num);
- g_free(name);
-
- return type_name;
-
-} /* get_display_type_str() */
-
-
-
-/** get_mode_str() ***************************************************
- *
- * Returns the mode string of a mode:
- *
- * "mode_name @WxH +X+Y"
- *
- **/
-
-static gchar * get_mode_str(nvModePtr mode, int be_generic)
-{
- gchar *mode_str;
- gchar *tmp;
-
-
- /* Make sure the mode has everything it needs to be displayed */
- if (!mode || !mode->display || !mode->display->gpu || !mode->metamode) {
- return NULL;
- }
-
-
- /* Don't display dummy modes */
- if (be_generic && mode->dummy && !mode->modeline) {
- return NULL;
- }
-
-
- /* Only one display, be very generic (no 'CRT:' in metamode) */
- if (be_generic && mode->display->gpu->num_displays == 1) {
- mode_str = g_strdup("");
-
- /* If there's more than one CRT/DFP/TV, we can't be generic. */
- } else {
- int generic = be_generic;
-
- if ((mode->display->device_mask & 0x000000FF) &&
- (mode->display->device_mask !=
- (mode->display->gpu->connected_displays & 0x000000FF))) {
- generic = 0;
- }
- if ((mode->display->device_mask & 0x0000FF00) &&
- (mode->display->device_mask !=
- (mode->display->gpu->connected_displays & 0x0000FF00))) {
- generic = 0;
- }
- if ((mode->display->device_mask & 0x00FF0000) &&
- (mode->display->device_mask !=
- (mode->display->gpu->connected_displays & 0x00FF0000))) {
- generic = 0;
- }
-
- /* Get the display type */
- tmp = get_display_type_str(mode->display->device_mask, generic);
- mode_str = g_strconcat(tmp, ": ", NULL);
- g_free(tmp);
- }
-
-
- /* NULL mode */
- if (!mode->modeline) {
- tmp = g_strconcat(mode_str, "NULL", NULL);
- g_free(mode_str);
- return tmp;
- }
-
-
- /* Mode name */
- tmp = g_strconcat(mode_str, mode->modeline->data.identifier, NULL);
- g_free(mode_str);
- mode_str = tmp;
-
-
- /* Panning domain */
- if (!be_generic || (mode->pan[W] != mode->dim[W] ||
- mode->pan[H] != mode->dim[H])) {
- tmp = g_strdup_printf("%s @%dx%d",
- mode_str, mode->pan[W], mode->pan[H]);
- g_free(mode_str);
- mode_str = tmp;
- }
-
-
- /* Offset */
-
- /*
- * XXX Later, we'll want to allow the user to select how
- * the metamodes are generated:
- *
- * Programability:
- * make mode->dim relative to screen->dim
- *
- * Coherency:
- * make mode->dim relative to mode->metamode->edim
- *
- *
- * XXX Also, we may want to take in consideration the
- * TwinViewOrientation when writing out position
- * information.
- */
-
- tmp = g_strdup_printf("%s +%d+%d",
- mode_str,
- /* Make mode position relative */
- mode->dim[X] - mode->metamode->edim[X],
- mode->dim[Y] - mode->metamode->edim[Y]);
- g_free(mode_str);
- mode_str = tmp;
-
-
- return mode_str;
-
-} /* get_mode_str() */
-
-
-
-/** get_display_from_gpu() *******************************************
- *
- * Returns the display with the matching device_mask
- *
- **/
-
-static nvDisplayPtr get_display_from_gpu(nvGpuPtr gpu,
- unsigned int device_mask)
-{
- nvDisplayPtr display;
-
- for (display = gpu->displays; display; display = display->next) {
- if (display->device_mask == device_mask) return display;
- }
-
- return NULL;
-
-} /* get_display_from_gpu() */
-
-
-
/** get_cur_screen_pos() *********************************************
*
* Grabs a copy of the currently selected screen position.
@@ -477,80 +292,6 @@ static void check_screen_pos_changed(CtkDisplayConfig *ctk_object)
} /* check_screen_pos_changed() */
-/** find_closest_mode_with_modeline() ********************************
- *
- * Helper function that returns the mode index of the display's mode
- * that best matches the given modeline.
- *
- * A best match is:
- *
- * - The modelines are the same.
- * - The modelines match in width & height.
- *
- **/
-
-static int find_closest_mode_with_modeline(nvDisplayPtr display,
- nvModeLinePtr modeline)
-{
- nvModePtr mode;
- int mode_idx;
- int match_idx = -1;
-
- mode_idx = 0;
- for (mode = display->modes; mode; mode = mode->next) {
- if (mode->modeline->data.vdisplay == modeline->data.vdisplay &&
- mode->modeline->data.hdisplay == modeline->data.hdisplay) {
- match_idx = mode_idx;
- }
- if (mode->modeline == modeline) break;
- mode_idx++;
- }
-
- return match_idx;
-
-} /* find_closest_mode_with_modeline() */
-
-
-
-/** get_a_screen() ***************************************************
- *
- * Returns a screen from the layout. if 'preferred_gpu' is set,
- * screens from that gpu are preferred. The screen with the lowest
- * number is returned.
- *
- **/
-
-static nvScreenPtr get_a_screen(nvLayoutPtr layout, nvGpuPtr preferred_gpu)
-{
- nvGpuPtr gpu;
- nvScreenPtr screen = NULL;
- nvScreenPtr other;
-
- if (!layout) return NULL;
-
- if (preferred_gpu && preferred_gpu->screens) {
- gpu = preferred_gpu;
- } else {
- preferred_gpu = NULL;
- gpu = layout->gpus;
- }
-
- for (; gpu; gpu = gpu->next) {
- for (other = gpu->screens; other; other = other->next) {
- if (!screen || screen->scrnum > other->scrnum) {
- screen = other;
- }
- }
-
- /* We found a preferred screen */
- if (gpu == preferred_gpu) break;
- }
-
- return screen;
-
-} /* get_a_screen() */
-
-
/** consolidate_xinerama() *******************************************
*
@@ -570,7 +311,7 @@ static void consolidate_xinerama(CtkDisplayConfig *ctk_object,
/* If no screen was given, pick one */
if (!screen) {
- screen = get_a_screen(layout, NULL);
+ screen = layout_get_a_screen(layout, NULL);
}
if (!screen) return;
@@ -586,653 +327,6 @@ static void consolidate_xinerama(CtkDisplayConfig *ctk_object,
-/** Parsing Tools ****************************************************
- *
- * Some tools for parsing strings
- *
- */
-
-static const char *skip_whitespace(const char *str)
-{
- while (*str &&
- (*str == ' ' || *str == '\t' ||
- *str == '\n' || *str == '\r')) {
- str++;
- }
- return str;
-}
-
-static void chop_whitespace(char *str)
-{
- char *tmp = str + strlen(str) -1;
-
- while (tmp >= str &&
- (*tmp == ' ' || *tmp == '\t' ||
- *tmp == '\n' || *tmp == '\r')) {
- *tmp = '\0';
- tmp++;
- }
-}
-
-static const char *skip_integer(const char *str)
-{
- if (*str == '-' || *str == '+') {
- str++;
- }
- while (*str && *str >= '0' && *str <= '9') {
- str++;
- }
- return str;
-}
-
-static const char *read_integer(const char *str, int *num)
-{
- str = skip_whitespace(str);
- *num = atoi(str);
- str = skip_integer(str);
- return skip_whitespace(str);
-}
-
-static const char *read_pair(const char *str, char separator, int *a, int *b)
-{
- str = read_integer(str, a);
- if (!str) return NULL;
- if (separator) {
- if (*str != separator) return NULL;
- str++;
- }
- return read_integer(str, b);
-}
-
-static const char *read_name(const char *str, char **name, char term)
-{
- const char *tmp;
-
- str = skip_whitespace(str);
- tmp = str;
- while (*str && *str != term) {
- str++;
- }
- *name = (char *)calloc(1, str -tmp +1);
- if (!(*name)) {
- return NULL;
- }
- strncpy(*name, tmp, str -tmp);
- if (*str == term) {
- str++;
- }
- return skip_whitespace(str);
-}
-
-/* Convert 'CRT-1' display device type names into a device_mask
- * '0x00000002' bitmask
- */
-static const char *read_display_name(const char *str, unsigned int *bit)
-{
- if (!str || !bit) {
- return NULL;
- }
-
- str = skip_whitespace(str);
- if (!strncmp(str, "CRT-", 4)) {
- *bit = 1 << (atoi(str+4));
-
- } else if (!strncmp(str, "TV-", 3)) {
- *bit = (1 << (atoi(str+3))) << 8;
-
- } else if (!strncmp(str, "DFP-", 4)) {
- *bit = (1 << (atoi(str+4))) << 16;
-
- } else {
- return NULL;
- }
-
- while (*str && *str != ':') {
- str++;
- }
- if (*str == ':') {
- str++;
- }
-
- return skip_whitespace(str);
-}
-
-/*
- * read_float_range()
- *
- * Reads the maximun/minimum information from a string in the
- * following format:
- * "MIN-MAX"
- * or
- * "MIN"
- */
-
-static int read_float_range(char *str, float *min, float *max)
-{
- if (!str) return 0;
-
- str = (char *)skip_whitespace(str);
- *min = atof(str);
- str = strstr(str, "-");
- if (!str) {
- *max = *min;
- return 1;
- }
- str++;
- *max = atof(str);
-
- return 1;
-}
-
-
-
-/** apply_modeline_token() *******************************************
- *
- * Modifies the modeline structure given with the token/value pair
- * given.
- *
- **/
-
-static void apply_modeline_token(char *token, char *value, void *data)
-{
- nvModeLinePtr modeline = (nvModeLinePtr) data;
-
- if (!modeline || !token || !strlen(token)) {
- return;
- }
-
- /* Modeline source */
- if (!strcasecmp("source", token)) {
- if (!value || !strlen(value)) {
- nv_warning_msg("Modeline 'source' token requires a value!");
- } else if (!strcasecmp("xserver", value)) {
- modeline->source |= MODELINE_SOURCE_XSERVER;
- } else if (!strcasecmp("xconfig", value)) {
- modeline->source |= MODELINE_SOURCE_XCONFIG;
- } else if (!strcasecmp("builtin", value)) {
- modeline->source |= MODELINE_SOURCE_BUILTIN;
- } else if (!strcasecmp("vesa", value)) {
- modeline->source |= MODELINE_SOURCE_VESA;
- } else if (!strcasecmp("edid", value)) {
- modeline->source |= MODELINE_SOURCE_EDID;
- } else if (!strcasecmp("nv-control", value)) {
- modeline->source |= MODELINE_SOURCE_NVCONTROL;
- } else {
- nv_warning_msg("Unknown modeline source '%s'", value);
- }
-
- /* X config name */
- } else if (!strcasecmp("xconfig-name", token)) {
- if (!value || !strlen(value)) {
- nv_warning_msg("Modeline 'xconfig-name' token requires a value!");
- } else {
- if (modeline->xconfig_name) {
- free(modeline->xconfig_name);
- }
- modeline->xconfig_name = g_strdup(value);
- }
-
- /* Unknown token */
- } else {
- nv_warning_msg("Unknown modeline token value pair: %s=%s",
- token, value);
- }
-
-} /* apply_modeline_token() */
-
-
-
-/** apply_metamode_token() *******************************************
- *
- * Modifies the metamode structure given with the token/value pair
- * given.
- *
- **/
-
-static void apply_metamode_token(char *token, char *value, void *data)
-{
- nvMetaModePtr metamode = (nvMetaModePtr) data;
-
- if (!metamode || !token || !strlen(token)) {
- return;
- }
-
- /* Metamode ID */
- if (!strcasecmp("id", token)) {
- if (!value || !strlen(value)) {
- nv_warning_msg("MetaMode 'id' token requires a value!");
- } else {
- metamode->id = atoi(value);
- }
-
- /* Modeline Source */
- } else if (!strcasecmp("source", token)) {
- if (!value || !strlen(value)) {
- nv_warning_msg("MetaMode 'source' token requires a value!");
- } else if (!strcasecmp("xconfig", value)) {
- metamode->source |= METAMODE_SOURCE_XCONFIG;
- } else if (!strcasecmp("implicit", value)) {
- metamode->source |= METAMODE_SOURCE_IMPLICIT;
- } else if (!strcasecmp("nv-control", value)) {
- metamode->source |= METAMODE_SOURCE_NVCONTROL;
- } else {
- nv_warning_msg("Unknown MetaMode source '%s'", value);
- }
-
- /* Switchable */
- } else if (!strcasecmp("switchable", token)) {
- if (!value || !strlen(value)) {
- nv_warning_msg("MetaMode 'switchable' token requires a value!");
- } else {
- if (!strcasecmp(value, "yes")) {
- metamode->switchable = TRUE;
- } else {
- metamode->switchable = FALSE;
- }
- }
-
- /* Unknown token */
- } else {
- nv_warning_msg("Unknown MetaMode token value pair: %s=%s",
- token, value);
- }
-
-} /* apply_metamode_token */
-
-
-
-/** apply_monitor_token() ********************************************
- *
- * Returns the source string of a refresh/sync range.
- *
- **/
-
-static void apply_monitor_token(char *token, char *value, void *data)
-{
- char **source = (char **)data;
-
- if (!source || !token || !strlen(token)) {
- return;
- }
-
- /* Metamode ID */
- if (!strcasecmp("source", token)) {
- if (*source) free(*source);
- *source = strdup(value);
-
- /* Unknown token */
- } else {
- nv_warning_msg("Unknown monitor range token value pair: %s=%s",
- token, value);
- }
-
-} /* apply_monitor_token() */
-
-
-
-/** apply_screen_info_token() ****************************************
- *
- * Modifies the ScreenInfo structure (pointed to by data) with
- * information from the token-value pair given. Currently accepts
- * position and width/height data.
- *
- **/
-
-typedef struct _ScreenInfo {
- int x;
- int y;
- int width;
- int height;
-} ScreenInfo;
-
-static void apply_screen_info_token(char *token, char *value, void *data)
-{
- ScreenInfo *screen_info = (ScreenInfo *)data;
-
- if (!screen_info || !token || !strlen(token)) {
- return;
- }
-
- /* X */
- if (!strcasecmp("x", token)) {
- screen_info->x = atoi(value);
-
- /* Y */
- } else if (!strcasecmp("y", token)) {
- screen_info->y = atoi(value);
-
- /* Width */
- } else if (!strcasecmp("width", token)) {
- screen_info->width = atoi(value);
-
- /* Height */
- } else if (!strcasecmp("height", token)) {
- screen_info->height = atoi(value);
-
- /* Unknown token */
- } else {
- nv_warning_msg("Unknown screen info token value pair: %s=%s",
- token, value);
- }
-
-} /* apply_screen_info_token() */
-
-
-
-/** parse_tokens() ***************************************************
- *
- * Parses the given tring for "token=value, token=value, ..." pairs
- * and dispatches the handeling of tokens to the given function with
- * the given data as an extra argument.
- *
- **/
-
-static Bool parse_tokens(const char *str, apply_token_func func, void *data)
-{
- char *token;
- char *value;
-
-
- if (str) {
-
- /* Parse each token */
- while (*str) {
-
- /* Read the token */
- str = read_name(str, &token, '=');
- if (!str) return FALSE;
-
- /* Read the value */
- str = read_name(str, &value, ',');
- if (!str) return FALSE;
-
- /* Remove trailing whitespace */
- chop_whitespace(token);
- chop_whitespace(value);
-
- func(token, value, data);
-
- free(token);
- free(value);
- }
- }
-
- return TRUE;
-
-} /* parse_tokens() */
-
-
-
-/** parse_modeline() *************************************************
- *
- * Converts a modeline string to an X config modeline structure that
- * the XF86Parser backend can read.
- *
- *
- * Modeline strings have this format:
- *
- * "mode_name" dot_clock timings flags
- *
- **/
-
-nvModeLinePtr parse_modeline(const char *modeline_str)
-{
- nvModeLinePtr modeline = NULL;
- const char *str = modeline_str;
- char *tmp;
- char *tokens;
-
-
- if (!str) return NULL;
-
- modeline = (nvModeLinePtr)calloc(1, sizeof(nvModeLine));
- if (!modeline) return NULL;
-
- /* Parse the modeline tokens */
- tmp = strstr(str, "::");
- if (tmp) {
- tokens = strdup(str);
- tokens[ tmp-str ] = '\0';
- str = tmp +2;
- parse_tokens(tokens, apply_modeline_token, (void *)modeline);
- free(tokens);
- }
-
- /* Read the mode name */
- str = skip_whitespace(str);
- if (!str || *str != '"') goto fail;
- str++;
- str = read_name(str, &(modeline->data.identifier), '"');
- if (!str) goto fail;
-
- /* Read dot clock */
- {
- int digits = 100;
-
- str = read_integer(str, &(modeline->data.clock));
- modeline->data.clock *= 1000;
- if (*str == '.') {
- str++;
- while (digits &&
- *str &&
- *str != ' ' && *str != '\t' &&
- *str != '\n' && *str != '\r') {
-
- modeline->data.clock += digits * (*str - '0');
- digits /= 10;
- str++;
- }
- }
- str = skip_whitespace(str);
- }
-
- str = read_integer(str, &(modeline->data.hdisplay));
- str = read_integer(str, &(modeline->data.hsyncstart));
- str = read_integer(str, &(modeline->data.hsyncend));
- str = read_integer(str, &(modeline->data.htotal));
- str = read_integer(str, &(modeline->data.vdisplay));
- str = read_integer(str, &(modeline->data.vsyncstart));
- str = read_integer(str, &(modeline->data.vsyncend));
- str = read_integer(str, &(modeline->data.vtotal));
-
-
- /* Parse modeline flags */
- while ((str = read_name(str, &tmp, ' ')) && strlen(tmp)) {
-
- if (!xconfigNameCompare(tmp, "+hsync")) {
- modeline->data.flags |= XCONFIG_MODE_PHSYNC;
- }
- else if (!xconfigNameCompare(tmp, "-hsync")) {
- modeline->data.flags |= XCONFIG_MODE_NHSYNC;
- }
- else if (!xconfigNameCompare(tmp, "+vsync")) {
- modeline->data.flags |= XCONFIG_MODE_PVSYNC;
- }
- else if (!xconfigNameCompare(tmp, "-vsync")) {
- modeline->data.flags |= XCONFIG_MODE_NVSYNC;
- }
- else if (!xconfigNameCompare(tmp, "interlace")) {
- modeline->data.flags |= XCONFIG_MODE_INTERLACE;
- }
- else if (!xconfigNameCompare(tmp, "doublescan")) {
- modeline->data.flags |= XCONFIG_MODE_DBLSCAN;
- }
- else if (!xconfigNameCompare(tmp, "composite")) {
- modeline->data.flags |= XCONFIG_MODE_CSYNC;
- }
- else if (!xconfigNameCompare(tmp, "+csync")) {
- modeline->data.flags |= XCONFIG_MODE_PCSYNC;
- }
- else if (!xconfigNameCompare(tmp, "-csync")) {
- modeline->data.flags |= XCONFIG_MODE_NCSYNC;
- }
- else if (!xconfigNameCompare(tmp, "hskew")) {
- str = read_integer(str, &(modeline->data.hskew));
- if (!str) {
- free(tmp);
- goto fail;
- }
- modeline->data.flags |= XCONFIG_MODE_HSKEW;
- }
- else if (!xconfigNameCompare(tmp, "bcast")) {
- modeline->data.flags |= XCONFIG_MODE_BCAST;
- }
- else if (!xconfigNameCompare(tmp, "CUSTOM")) {
- modeline->data.flags |= XCONFIG_MODE_CUSTOM;
- }
- else if (!xconfigNameCompare(tmp, "vscan")) {
- str = read_integer(str, &(modeline->data.vscan));
- if (!str) {
- free(tmp);
- goto fail;
- }
- modeline->data.flags |= XCONFIG_MODE_VSCAN;
- }
- else {
- nv_warning_msg("Invalid modeline keyword '%s' in modeline '%s'",
- tmp, modeline_str);
- goto fail;
- }
- free(tmp);
- }
-
- return modeline;
-
-
- /* Handle failures */
- fail:
- free(modeline);
- return NULL;
-
-} /* parse_modeline() */
-
-
-
-/** parse_mode() *****************************************************
- *
- * Makes a mode structure from the mode string given.
- *
- *
- * Currently supported mode syntax:
- *
- * "mode_name" +X+Y @WxH
- *
- **/
-
-nvModePtr parse_mode(nvDisplayPtr display, const char *mode_str)
-{
- nvModePtr mode;
- char *mode_name; /* Modeline reference name */
- const char *str = mode_str;
-
-
-
- if (!str || !display || !display->modelines) return NULL;
-
-
- /* Allocate a Mode structure */
- mode = (nvModePtr)calloc(1, sizeof(nvMode));
- if (!mode) return NULL;
-
- mode->display = display;
-
-
- /* Read the mode name */
- str = read_name(str, &mode_name, ' ');
- if (!str || !mode_name) goto fail;
-
-
- /* Match the mode name to one of the modelines */
- mode->modeline = display->modelines;
- while (mode->modeline) {
- if (!strcmp(mode_name, mode->modeline->data.identifier)) {
- break;
- }
- mode->modeline = mode->modeline->next;
- }
- free(mode_name);
-
-
- /* If we can't find a matching modeline, show device as off
- * using the width & height of whatever the first modeline is.
- * XXX Hopefully this is the default width/height.
- */
- if (!mode->modeline) {
- if (strcmp(mode_str, "NULL")) {
- nv_warning_msg("Mode name '%s' does not match any modelines for "
- "display device '%s' in modeline '%s'.",
- mode_name, display->name, mode_str);
- }
- mode->dim[W] = display->modelines->data.hdisplay;
- mode->dim[H] = display->modelines->data.vdisplay;
- mode->pan[W] = mode->dim[W];
- mode->pan[H] = mode->dim[H];
- return mode;
- }
-
-
- /* Setup default size and panning of display */
- mode->dim[W] = mode->modeline->data.hdisplay;
- mode->dim[H] = mode->modeline->data.vdisplay;
- mode->pan[W] = mode->dim[W];
- mode->pan[H] = mode->dim[H];
-
-
- /* Read mode information */
- while (*str) {
-
- /* Read panning */
- if (*str == '@') {
- str++;
- str = read_pair(str, 'x',
- &(mode->pan[W]), &(mode->pan[H]));
- }
-
- /* Read position */
- else if (*str == '+') {
- str++;
- str = read_pair(str, 0,
- &(mode->dim[X]), &(mode->dim[Y]));
- }
-
- /* Mode parse error - Ack! */
- else {
- str = NULL;
- }
-
- /* Catch errors */
- if (!str) goto fail;
- }
-
-
- /* These are the same for now */
- mode->pan[X] = mode->dim[X];
- mode->pan[Y] = mode->dim[Y];
-
-
- /* Panning can't be smaller than dimensions */
- if (mode->pan[W] < mode->dim[W]) {
- mode->pan[W] = mode->dim[W];
- }
- if (mode->pan[W] < mode->dim[W]) {
- mode->pan[W] = mode->dim[W];
- }
-
- return mode;
-
-
- /* Handle failures */
- fail:
- if (mode) {
- free(mode);
- }
-
- return NULL;
-
-} /* parse_mode() */
-
-
-
/** xconfigPrint() ******************************************************
*
* xconfigPrint() - this is the one entry point that a user of the
@@ -1282,76 +376,6 @@ void xconfigPrint(MsgType t, const char *msg)
-/* Layout save/write functions ***************************************/
-
-
-/** get_display_mode_str() *******************************************
- *
- * Returns the mode string of the display's 'mode_idx''s
- * mode.
- *
- **/
-static gchar *get_display_mode_str(nvDisplayPtr display, int mode_idx,
- int be_generic)
-{
- nvModePtr mode = display->modes;
-
- while (mode && mode_idx) {
- mode = mode->next;
- mode_idx--;
- }
-
- if (mode) {
- return get_mode_str(mode, be_generic);
- }
-
- return NULL;
-
-} /* get_display_mode_str() */
-
-
-
-/** get_screen_metamode_str() ****************************************
- *
- * Returns a screen's metamode string for the given metamode index
- * as:
- *
- * "mode1_1, mode1_2, mode1_3 ... "
- *
- **/
-
-static gchar *get_screen_metamode_str(nvScreenPtr screen, int metamode_idx,
- int be_generic)
-{
- nvDisplayPtr display;
-
- gchar *metamode_str = NULL;
- gchar *mode_str;
- gchar *tmp;
-
- for (display = screen->gpu->displays; display; display = display->next) {
-
- if (display->screen != screen) continue; /* Display not in screen */
-
- mode_str = get_display_mode_str(display, metamode_idx, be_generic);
- if (!mode_str) continue;
-
- if (!metamode_str) {
- metamode_str = mode_str;
- } else {
- tmp = g_strdup_printf("%s, %s", metamode_str, mode_str);
- g_free(mode_str);
- g_free(metamode_str);
- metamode_str = tmp;
- }
- }
-
- return metamode_str;
-
-} /* get_screen_metamode_str() */
-
-
-
/** generate_xconf_metamode_str() ************************************
*
* Returns the metamode strings of a screen:
@@ -1397,7 +421,7 @@ static int generate_xconf_metamode_str(CtkDisplayConfig *ctk_object,
* in this mode.
*/
if (!ctk_object->advanced_mode) {
- metamode_strs = get_screen_metamode_str(screen,
+ metamode_strs = screen_get_metamode_str(screen,
screen->cur_metamode_idx, 1);
len = strlen(metamode_strs);
start_width = screen->cur_metamode->edim[W];
@@ -1432,7 +456,7 @@ static int generate_xconf_metamode_str(CtkDisplayConfig *ctk_object,
(metamode->edim[H] > start_height)))
continue;
- metamode_str = get_screen_metamode_str(screen, metamode_idx, 1);
+ metamode_str = screen_get_metamode_str(screen, metamode_idx, 1);
if (!metamode_str) continue;
@@ -1457,7 +481,7 @@ static int generate_xconf_metamode_str(CtkDisplayConfig *ctk_object,
"X server.",
metamode_idx);
- parent = get_window_parent(GTK_WIDGET(ctk_object));
+ parent = ctk_get_parent_window(GTK_WIDGET(ctk_object));
if (!parent) {
nv_warning_msg(msg);
g_free(msg);
@@ -1512,1334 +536,6 @@ static int generate_xconf_metamode_str(CtkDisplayConfig *ctk_object,
-
-/* Metamode functions ************************************************/
-
-
-/** remove_modes_from_display() **************************************
- *
- * Removes all modes currently referenced by this screen, also
- * freeing any memory used.
- *
- **/
-
-static void remove_modes_from_display(nvDisplayPtr display)
-{
- nvModePtr mode;
-
- if (display) {
- while (display->modes) {
- mode = display->modes;
- display->modes = mode->next;
- free(mode);
- }
- display->num_modes = 0;
- display->cur_mode = NULL;
- }
-
-} /* remove_modes_from_display() */
-
-
-
-/** add_metamode_to_screen() *****************************************
- *
- * Parses a metamode string and adds the appropreate modes to the
- * screen's display devices (at the end of the list)
- *
- */
-
-static Bool add_metamode_to_screen(nvScreenPtr screen, char *metamode_str,
- gchar **err_str)
-{
- char *mode_str;
- char *str = NULL;
- char *tmp;
- char *tokens;
- nvMetaModePtr metamode;
-
-
- if (!screen || !screen->gpu || !metamode_str) goto fail;
-
-
- metamode = (nvMetaModePtr)calloc(1, sizeof(nvMetaMode));
- if (!metamode) goto fail;
-
-
- /* Copy the string so we can split it up */
- str = strdup(metamode_str);
- if (!str) goto fail;
-
-
- /* Read the MetaMode ID */
- tmp = strstr(str, "::");
- if (tmp) {
- tokens = strdup(str);
- tokens[ tmp-str ] = '\0';
- tmp += 2;
- parse_tokens(tokens, apply_metamode_token, (void *)metamode);
- free(tokens);
- } else {
- /* No tokens? Try the old "ID: METAMODE_STR" syntax */
- tmp = (char *)read_integer(str, &(metamode->id));
- metamode->source = METAMODE_SOURCE_NVCONTROL;
- if (*tmp == ':') {
- tmp++;
- }
- }
-
-
- /* Add the metamode at the end of the screen's metamode list */
- screen->metamodes =
- (nvMetaModePtr)xconfigAddListItem((GenericListPtr)screen->metamodes,
- (GenericListPtr)metamode);
-
-
- /* Split up the metamode into separate modes */
- for (mode_str = strtok(tmp, ",");
- mode_str;
- mode_str = strtok(NULL, ",")) {
-
- nvModePtr mode;
- unsigned int device_mask;
- nvDisplayPtr display;
- const char *orig_mode_str = skip_whitespace(mode_str);
-
-
- /* Parse the display device bitmask from the name */
- mode_str = (char *)read_display_name(mode_str, &device_mask);
- if (!mode_str) {
- *err_str = g_strdup_printf("Failed to read a display device name "
- "on screen %d (on GPU-%d)\nwhile "
- "parsing metamode:\n\n'%s'",
- screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle),
- orig_mode_str);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Match device bitmask to an existing display */
- display = get_display_from_gpu(screen->gpu, device_mask);
- if (!display) {
- *err_str = g_strdup_printf("Failed to find display device 0x%08x "
- "on screen %d (on GPU-%d)\nwhile "
- "parsing metamode:\n\n'%s'",
- device_mask,
- screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle),
- orig_mode_str);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Parse the mode */
- mode = parse_mode(display, mode_str);
- if (!mode) {
- *err_str = g_strdup_printf("Failed to parse mode '%s'\non "
- "screen %d (on GPU-%d)\nfrom "
- "metamode:\n\n'%s'",
- mode_str, screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle),
- orig_mode_str);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Make the mode part of the metamode */
- mode->metamode = metamode;
-
-
- /* Make the display part of the screen */
- display->screen = screen;
-
-
- /* Set the panning offset */
- mode->pan[X] = mode->dim[X];
- mode->pan[Y] = mode->dim[Y];
-
-
- /* Add the mode at the end of the display's mode list */
- display->modes =
- (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes,
- (GenericListPtr)mode);
- display->num_modes++;
-
- } /* Done parsing a single metamode */
-
- free(str);
- return TRUE;
-
-
- /* Failure case */
- fail:
-
- /* XXX We should probably track which modes were added and remove
- * them at this point. For now, just assume the caller will
- * remove all the modes and bail.
- */
-
- free(str);
- return FALSE;
-
-} /* add_metamode_to_screen() */
-
-
-
-/** check_screen_metamodes() *****************************************
- *
- * Makes sure all displays associated with the screen have the right
- * number of mode entries.
- *
- **/
-
-static Bool check_screen_metamodes(nvScreenPtr screen)
-{
- nvDisplayPtr display;
- nvMetaModePtr metamode;
- nvModePtr mode;
- nvModePtr last_mode = NULL;
-
-
- for (display = screen->gpu->displays; display; display = display->next) {
-
- if (display->screen != screen) continue;
-
- if (display->num_modes == screen->num_metamodes) continue;
-
- mode = display->modes;
- metamode = screen->metamodes;
- while (mode && metamode) {
- mode = mode->next;
- metamode = metamode->next;
- if (mode) {
- last_mode = mode;
- }
- }
-
- /* Each display must have as many modes as it's screen has metamodes */
- while (metamode) {
-
- /* Create a dumy mode */
- mode = parse_mode(display, "NULL");
- mode->dummy = 1;
- mode->metamode = metamode;
-
- /* Duplicate position information of the last mode */
- if (last_mode) {
- mode->dim[X] = last_mode->dim[X];
- mode->dim[Y] = last_mode->dim[Y];
- mode->pan[X] = last_mode->pan[X];
- mode->pan[Y] = last_mode->pan[Y];
- mode->position_type = last_mode->position_type;
- mode->relative_to = last_mode->relative_to;
- }
-
- /* Add the mode at the end of display's mode list */
- display->modes =
- (nvModePtr)xconfigAddListItem((GenericListPtr)display->modes,
- (GenericListPtr)mode);
- display->num_modes++;
-
- metamode = metamode->next;
- }
-
- /* XXX Shouldn't need to remove extra modes.
- while (mode) {
- }
- */
- }
-
- return TRUE;
-
-} /* check_screen_metamodes() */
-
-
-
-/** assign_dummy_metamode_positions() ********************************
- *
- * Assign the initial (top left) position of dummy modes to
- * match the top left of the first non-dummy mode
- *
- */
-
-static void assign_dummy_metamode_positions(nvScreenPtr screen)
-{
- nvDisplayPtr display;
- nvModePtr ok_mode;
- nvModePtr mode;
-
-
- for (display = screen->gpu->displays; display; display = display->next) {
- if (display->screen != screen) continue;
-
- /* Get the first non-dummy mode */
- for (ok_mode = display->modes; ok_mode; ok_mode = ok_mode->next) {
- if (!ok_mode->dummy) break;
- }
-
- if (ok_mode) {
- for (mode = display->modes; mode; mode = mode->next) {
- if (!mode->dummy) continue;
- mode->dim[X] = ok_mode->dim[X];
- mode->pan[X] = ok_mode->dim[X];
- mode->dim[Y] = ok_mode->dim[Y];
- mode->pan[Y] = ok_mode->dim[Y];
- }
- }
- }
-
-} /* assign_dummy_metamode_positions() */
-
-
-
-/** remove_metamodes_from_screen() ***********************************
- *
- * Removes all metamodes currently referenced by this screen, also
- * freeing any memory used.
- *
- **/
-
-static void remove_metamodes_from_screen(nvScreenPtr screen)
-{
- nvGpuPtr gpu;
- nvDisplayPtr display;
- nvMetaModePtr metamode;
-
- if (screen) {
- gpu = screen->gpu;
-
- /* Remove the modes from this screen's displays */
- if (gpu) {
- for (display = gpu->displays; display; display = display->next) {
-
- if (display->screen != screen) continue;
-
- remove_modes_from_display(display);
- }
- }
-
- /* Clear the screen's metamode list */
- while (screen->metamodes) {
- metamode = screen->metamodes;
- screen->metamodes = metamode->next;
- free(metamode->string);
- free(metamode);
- }
- screen->num_metamodes = 0;
- screen->cur_metamode = NULL;
- screen->cur_metamode_idx = -1;
- }
-
-} /* remove_metamodes_from_screen() */
-
-
-
-/** add_metamodes_to_screen() ****************************************
- *
- * Adds all the appropreate modes on all display devices of this
- * screen by parsing all the metamode strings.
- *
- */
-
-static Bool add_metamodes_to_screen(nvScreenPtr screen, gchar **err_str)
-{
- nvDisplayPtr display;
-
- char *metamode_strs = NULL; /* Screen's list metamode strings */
- char *cur_metamode_str; /* Current metamode */
-
- char *str; /* Temp pointer for parsing */
- int len;
- ReturnStatus ret;
- int i;
-
-
-
- /* Get the list of metamodes for the screen */
- ret = NvCtrlGetBinaryAttribute(screen->handle, 0,
- NV_CTRL_BINARY_DATA_METAMODES,
- (unsigned char **)&metamode_strs,
- &len);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query list of metamodes on\n"
- "screen %d (on GPU-%d).",
- screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle));
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Get the current metamode for the screen */
- ret = NvCtrlGetStringAttribute(screen->handle,
- NV_CTRL_STRING_CURRENT_METAMODE,
- &cur_metamode_str);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query current metamode of\n"
- "screen %d (on GPU-%d).",
- screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle));
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Remove any existing modes on all displays */
- remove_metamodes_from_screen(screen);
-
-
- /* Parse each mode in the metamode strings */
- str = metamode_strs;
- while (str && strlen(str)) {
-
- /* Add the individual metamodes to the screen,
- * This populates the display device's mode list.
- */
- if (!add_metamode_to_screen(screen, str, err_str)) {
- nv_warning_msg("Failed to add metamode '%s' to screen %d (on "
- "GPU-%d).",
- str, screen->scrnum,
- NvCtrlGetTargetId(screen->gpu->handle));
- goto fail;
- }
-
- /* Keep track of the current metamode */
- if (!strcmp(str, cur_metamode_str)) {
- screen->cur_metamode_idx = screen->num_metamodes;
- }
-
- /* Keep count of the metamode */
- screen->num_metamodes++;
-
- /* Make sure each display device gets a mode */
- check_screen_metamodes(screen);
-
- /* Go to the next metamode */
- str += strlen(str) +1;
- }
- XFree(metamode_strs);
-
-
- /* Assign the top left position of dummy modes */
- assign_dummy_metamode_positions(screen);
-
-
- /* Make the screen point at the current metamode */
- screen->cur_metamode = screen->metamodes;
- for (i = 0; i < screen->cur_metamode_idx; i++) {
- screen->cur_metamode = screen->cur_metamode->next;
- }
-
-
- /* Make each display within the screen point to the current mode.
- * Also, count the number of displays on the screen
- */
- screen->num_displays = 0;
- for (display = screen->gpu->displays; display; display = display->next) {
-
- if (display->screen != screen) continue; /* Display not in screen */
-
- screen->num_displays++;
- screen->displays_mask |= display->device_mask;
-
- display->cur_mode = display->modes;
- for (i = 0; i < screen->cur_metamode_idx; i++) {
- display->cur_mode = display->cur_mode->next;
- }
- }
-
- return TRUE;
-
-
- /* Failure case */
- fail:
-
- /* Remove modes we may have added */
- remove_metamodes_from_screen(screen);
-
- XFree(metamode_strs);
- return FALSE;
-
-} /* add_metamodes_to_screen() */
-
-
-
-/* Screen functions **************************************************/
-
-
-/** remove_display_from_screen() *************************************
- *
- * Removes a display device from the screen
- *
- */
-static void remove_display_from_screen(nvDisplayPtr display)
-{
- nvGpuPtr gpu;
- nvScreenPtr screen;
- nvDisplayPtr other;
- nvModePtr mode;
-
-
- if (display && display->screen) {
- screen = display->screen;
- gpu = display->gpu;
-
- /* Make any display relative to this one use absolute position */
- for (other = gpu->displays; other; other = other->next) {
-
- if (other == display) continue;
- if (other->screen != screen) continue;
-
- for (mode = other->modes; mode; mode = mode->next) {
- if (mode->relative_to == display) {
- mode->position_type = CONF_ADJ_ABSOLUTE;
- mode->relative_to = NULL;
- }
- }
- }
-
- /* Remove the display from the screen */
- screen->displays_mask &= ~(display->device_mask);
- screen->num_displays--;
-
- /* Clean up old references to the screen in the display */
- remove_modes_from_display(display);
- display->screen = NULL;
- }
-
-} /* remove_display_from_screen() */
-
-
-
-/** remove_displays_from_screen() ************************************
- *
- * Removes all displays currently pointing at this screen, also
- * freeing any memory used.
- *
- **/
-
-void remove_displays_from_screen(nvScreenPtr screen)
-{
- nvGpuPtr gpu;
- nvDisplayPtr display;
-
- if (screen && screen->gpu) {
- gpu = screen->gpu;
-
- for (display = gpu->displays; display; display = display->next) {
-
- if (display->screen != screen) continue;
-
- remove_display_from_screen(display);
- }
- }
-
-} /* remove_displays_from_screen() */
-
-
-
-/** free_screen() ****************************************************
- *
- * Frees memory used by a screen structure
- *
- */
-static void free_screen(nvScreenPtr screen)
-{
- if (screen) {
-
- remove_metamodes_from_screen(screen);
- remove_displays_from_screen(screen);
-
- if (screen->handle) {
- NvCtrlAttributeClose(screen->handle);
- }
-
- free(screen);
- }
-
-} /* free_screens() */
-
-
-
-/** add_screen_to_gpu() **********************************************
- *
- * Adds screen 'screen_id' that is connected to the gpu.
- *
- */
-static int add_screen_to_gpu(nvGpuPtr gpu, int screen_id, gchar **err_str)
-{
- Display *display;
- nvScreenPtr screen;
- int val;
- ReturnStatus ret;
-
-
- /* Create the screen structure */
- screen = (nvScreenPtr)calloc(1, sizeof(nvScreen));
- if (!screen) goto fail;
-
- screen->gpu = gpu;
- screen->scrnum = screen_id;
-
-
- /* Make an NV-CONTROL handle to talk to the screen */
- display = NvCtrlGetDisplayPtr(gpu->handle);
- screen->handle =
- NvCtrlAttributeInit(display,
- NV_CTRL_TARGET_TYPE_X_SCREEN,
- screen_id,
- NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM |
- NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM);
- if (!screen->handle) {
- *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for\n"
- "screen %d (on GPU-%d).",
- screen_id, NvCtrlGetTargetId(gpu->handle));
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Make sure this screen supports dynamic twinview */
- ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_DYNAMIC_TWINVIEW,
- &val);
- if (ret != NvCtrlSuccess || !val) {
- *err_str = g_strdup_printf("Dynamic TwinView is disabled on "
- "screen %d.",
- screen_id);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* The display owner GPU gets the screen(s) */
- ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_MULTIGPU_DISPLAY_OWNER,
- &val);
- if (ret != NvCtrlSuccess || val != NvCtrlGetTargetId(gpu->handle)) {
- free_screen(screen);
- return TRUE;
- }
-
-
- /* Listen to NV-CONTROL events on this screen handle */
- screen->ctk_event = CTK_EVENT(ctk_event_new(screen->handle));
-
-
- /* Query the depth of the screen */
- screen->depth = NvCtrlGetScreenPlanes(screen->handle);
-
-
- /* Parse the screen's metamodes (ties displays on the gpu to the screen) */
- if (!add_metamodes_to_screen(screen, err_str)) {
- nv_warning_msg("Failed to add metamodes to screen %d (on GPU-%d).",
- screen_id, NvCtrlGetTargetId(gpu->handle));
- goto fail;
- }
-
-
- /* Add the screen at the end of the gpu's screen list */
- gpu->screens =
- (nvScreenPtr)xconfigAddListItem((GenericListPtr)gpu->screens,
- (GenericListPtr)screen);
- gpu->num_screens++;
- return TRUE;
-
-
- fail:
- free_screen(screen);
- return FALSE;
-
-} /* add_screen_to_gpu() */
-
-
-
-/** remove_screen_from_gpu() *****************************************
- *
- * Removes a screen from a gpu.
- *
- */
-static void remove_screen_from_gpu(nvScreenPtr screen)
-{
- nvGpuPtr gpu;
- nvScreenPtr other;
-
- if (!screen || !screen->gpu) return;
-
- /* Remove the screen from the GPU */
- gpu = screen->gpu;
-
- gpu->screens =
- (nvScreenPtr)xconfigRemoveListItem((GenericListPtr)gpu->screens,
- (GenericListPtr)screen);
- gpu->num_screens--;
-
- /* Make sure other screens in the layout aren't relative
- * to this screen
- */
- for (gpu = screen->gpu->layout->gpus; gpu; gpu = gpu->next) {
- for (other = gpu->screens; other; other = other->next) {
- if (other->relative_to == screen) {
- other->position_type = CONF_ADJ_ABSOLUTE;
- other->relative_to = NULL;
- }
- }
- }
-
- screen->gpu = NULL;
-
- /* XXX May want to remove metamodes here */
- /* XXX May want to remove displays here */
-
-} /* remove_screen_from_gpu() */
-
-
-
-/** remove_screens_from_gpu() ****************************************
- *
- * Removes all screens from a gpu.
- *
- */
-static void remove_screens_from_gpu(nvGpuPtr gpu)
-{
- nvScreenPtr screen;
-
- if (gpu) {
- while (gpu->screens) {
- screen = gpu->screens;
- gpu->screens = screen->next;
- free_screen(screen);
- }
- gpu->num_screens = 0;
- }
-
-} /* remove_screens_from_gpu() */
-
-
-
-/** add_screens_to_gpu() *********************************************
- *
- * Queries the list of screens on the gpu.
- *
- */
-static Bool add_screens_to_gpu(nvGpuPtr gpu, gchar **err_str)
-{
- ReturnStatus ret;
- int *pData;
- int len;
- int i;
-
-
- /* Clean up the GPU list */
- remove_screens_from_gpu(gpu);
-
-
- /* Query the list of X screens this GPU is driving */
- ret = NvCtrlGetBinaryAttribute(gpu->handle, 0,
- NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU,
- (unsigned char **)(&pData), &len);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query list of screens driven\n"
- "by GPU-%d '%s'.",
- NvCtrlGetTargetId(gpu->handle), gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Add each X screen */
- for (i = 1; i <= pData[0]; i++) {
- if (!add_screen_to_gpu(gpu, pData[i], err_str)) {
- nv_warning_msg("Failed to add screen %d to GPU-%d '%s'.",
- pData[i], NvCtrlGetTargetId(gpu->handle),
- gpu->name);
- goto fail;
- }
- }
-
- return TRUE;
-
-
- /* Failure case */
- fail:
- remove_screens_from_gpu(gpu);
- return FALSE;
-
-} /* add_screens_to_gpu() */
-
-
-
-/* Display device functions ******************************************/
-
-
-/** remove_modelines_from_display() **********************************
- *
- * Clears the display device's modeline list.
- *
- **/
-
-static void remove_modelines_from_display(nvDisplayPtr display)
-{
- nvModeLinePtr modeline;
-
- if (display) {
- while (display->modelines) {
- modeline = display->modelines;
- display->modelines = display->modelines->next;
- free(modeline);
- }
- display->num_modelines = 0;
- }
-
-} /* remove_modelines_from_display() */
-
-
-
-/** add_modelines_to_display() ***************************************
- *
- * Queries the display's current modepool (modelines list).
- *
- **/
-
-static Bool add_modelines_to_display(nvDisplayPtr display, gchar **err_str)
-{
- nvModeLinePtr modeline;
- char *modeline_strs = NULL;
- char *str;
- int len;
- ReturnStatus ret;
-
-
- /* Free any old mode lines */
- remove_modelines_from_display(display);
-
-
- /* Get the validated modelines for the display */
- ret = NvCtrlGetBinaryAttribute(display->gpu->handle,
- display->device_mask,
- NV_CTRL_BINARY_DATA_MODELINES,
- (unsigned char **)&modeline_strs, &len);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query modelines of display "
- "device 0x%08x '%s'\nconnected to "
- "GPU-%d '%s'.",
- display->device_mask, display->name,
- NvCtrlGetTargetId(display->gpu->handle),
- display->gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Parse each modeline */
- str = modeline_strs;
- while (strlen(str)) {
-
- modeline = parse_modeline(str);
- if (!modeline) {
- *err_str = g_strdup_printf("Failed to parse the following "
- "modeline of display device\n"
- "0x%08x '%s' connected to GPU-%d "
- "'%s':\n\n%s",
- display->device_mask,
- display->name,
- NvCtrlGetTargetId(display->gpu->handle),
- display->gpu->name,
- str);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- /* Add the modeline at the end of the display's modeline list */
- display->modelines = (nvModeLinePtr)xconfigAddListItem
- ((GenericListPtr)display->modelines, (GenericListPtr)modeline);
- display->num_modelines++;
-
- /* Get next modeline string */
- str += strlen(str) +1;
- }
-
- XFree(modeline_strs);
- return TRUE;
-
-
- /* Handle the failure case */
- fail:
- remove_modelines_from_display(display);
- XFree(modeline_strs);
- return FALSE;
-
-} /* add_modelines_to_display() */
-
-
-
-/** free_display() ***************************************************
- *
- * Frees memory used by a display
- *
- */
-static void free_display(nvDisplayPtr display)
-{
- if (display) {
- remove_modes_from_display(display);
- remove_modelines_from_display(display);
- XFree(display->name);
- free(display);
- }
-
-} /* free_display(display) */
-
-
-
-/** add_display_to_gpu() *********************************************
- *
- * Adds the display with the device mask given to the GPU structure.
- *
- */
-static nvDisplayPtr add_display_to_gpu(nvGpuPtr gpu, unsigned int device_mask,
- gchar **err_str)
-{
- ReturnStatus ret;
- nvDisplayPtr display = NULL;
-
-
- /* Create the display structure */
- display = (nvDisplayPtr)calloc(1, sizeof(nvDisplay));
- if (!display) goto fail;
-
-
- /* Init the display structure */
- display->gpu = gpu;
- display->device_mask = device_mask;
-
-
- /* Query the display information */
- ret = NvCtrlGetStringDisplayAttribute(gpu->handle,
- device_mask,
- NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
- &(display->name));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query name of display device\n"
- "0x%08x connected to GPU-%d '%s'.",
- device_mask, NvCtrlGetTargetId(gpu->handle),
- gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Query the modelines for the display device */
- if (!add_modelines_to_display(display, err_str)) {
- nv_warning_msg("Failed to add modelines to display device 0x%08x "
- "'%s'\nconnected to GPU-%d '%s'.",
- device_mask, display->name,
- NvCtrlGetTargetId(gpu->handle), gpu->name);
- goto fail;
- }
-
-
- /* Add the display at the end of gpu's display list */
- gpu->displays =
- (nvDisplayPtr)xconfigAddListItem((GenericListPtr)gpu->displays,
- (GenericListPtr)display);
- gpu->connected_displays |= device_mask;
- gpu->num_displays++;
- return display;
-
-
- /* Failure case */
- fail:
- free_display(display);
- return NULL;
-
-} /* add_display_to_gpu() */
-
-
-
-/** remove_display_from_gpu() ****************************************
- *
- * Removes a display from the gpu
- *
- */
-static void remove_display_from_gpu(nvDisplayPtr display)
-{
- nvGpuPtr gpu;
- nvScreenPtr screen;
-
-
- if (display && display->gpu) {
- gpu = display->gpu;
- screen = display->screen;
-
- /* Remove the display from the screen it may be in */
- if (screen) {
- remove_display_from_screen(display);
-
- /* If the screen is empty, remove it too */
- if (!screen->num_displays) {
- remove_screen_from_gpu(screen);
- free_screen(screen);
- }
- }
-
- /* Remove the display from the gpu */
- gpu->displays =
- (nvDisplayPtr)xconfigRemoveListItem((GenericListPtr)gpu->displays,
- (GenericListPtr)display);
- gpu->connected_displays &= ~(display->device_mask);
- gpu->num_displays--;
- }
-
-} /* remove_display_from_gpu() */
-
-
-
-/** remove_displays_from_gpu() ***************************************
- *
- * Removes all displays from the gpu
- *
- */
-static void remove_displays_from_gpu(nvGpuPtr gpu)
-{
- nvDisplayPtr display;
-
- if (gpu) {
- while (gpu->displays) {
- display = gpu->displays;
- remove_display_from_screen(display);
- gpu->displays = display->next;
- free_display(display);
- }
- gpu->num_displays = 0;
- }
-
-} /* remove_displays_from_gpu() */
-
-
-
-/** add_displays_to_gpu() ********************************************
- *
- * Adds the display devices connected on the GPU to the GPU structure
- *
- */
-static Bool add_displays_to_gpu(nvGpuPtr gpu, gchar **err_str)
-{
- unsigned int mask;
-
-
- /* Clean up the GPU list */
- remove_displays_from_gpu(gpu);
-
-
- /* Add each connected display */
- for (mask = 1; mask; mask <<= 1) {
-
- if (!(mask & (gpu->connected_displays))) continue;
-
- if (!add_display_to_gpu(gpu, mask, err_str)) {
- nv_warning_msg("Failed to add display device 0x%08x to GPU-%d "
- "'%s'.",
- mask, NvCtrlGetTargetId(gpu->handle), gpu->name);
- goto fail;
- }
- }
-
- return TRUE;
-
-
- /* Failure case */
- fail:
- remove_displays_from_gpu(gpu);
- return FALSE;
-
-} /* add_displays_to_gpu() */
-
-
-
-/* GPU functions *****************************************************/
-
-
-/** add_screenless_modes_to_displays() *******************************
- *
- * Adds fake modes to display devices that have no screens so we
- * can show them on the layout page.
- *
- */
-static Bool add_screenless_modes_to_displays(nvGpuPtr gpu)
-{
- nvDisplayPtr display;
- nvModePtr mode;
-
- for (display = gpu->displays; display; display = display->next) {
- if (display->screen) continue;
-
- /* Create a fake mode */
- mode = (nvModePtr)calloc(1, sizeof(nvMode));
- if (!mode) return FALSE;
-
- mode->display = display;
- mode->dummy = 1;
-
- mode->dim[W] = 800;
- mode->dim[H] = 600;
- mode->pan[W] = mode->dim[W];
- mode->pan[H] = mode->dim[H];
-
- /* Add the mode to the display */
- display->modes = mode;
- display->cur_mode = mode;
- display->num_modes = 1;
- }
-
- return TRUE;
-
-} /* add_screenless_modes_to_displays() */
-
-
-
-/** free_gpu() *******************************************************
- *
- * Frees memory used by the gpu.
- *
- **/
-static void free_gpu(nvGpuPtr gpu)
-{
- if (gpu) {
- remove_screens_from_gpu(gpu);
- remove_displays_from_gpu(gpu);
- XFree(gpu->name);
- if (gpu->handle) {
- NvCtrlAttributeClose(gpu->handle);
- }
- free(gpu);
- }
-
-} /* free_gpu() */
-
-
-
-/** add_gpu_to_layout() **********************************************
- *
- * Adds a GPU to the layout structure.
- *
- **/
-static Bool add_gpu_to_layout(nvLayoutPtr layout, unsigned int gpu_id,
- gchar **err_str)
-{
- ReturnStatus ret;
- Display *dpy;
- nvGpuPtr gpu = NULL;
-
-
- /* Create the GPU structure */
- gpu = (nvGpuPtr)calloc(1, sizeof(nvGpu));
- if (!gpu) goto fail;
-
-
- /* Make an NV-CONTROL handle to talk to the GPU */
- dpy = NvCtrlGetDisplayPtr(layout->handle);
- gpu->layout = layout;
- gpu->handle = NvCtrlAttributeInit(dpy, NV_CTRL_TARGET_TYPE_GPU, gpu_id,
- NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM);
- if (!gpu->handle) {
- *err_str = g_strdup_printf("Failed to create NV-CONTROL handle for "
- "GPU-%d.", gpu_id);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- gpu->ctk_event = CTK_EVENT(ctk_event_new(gpu->handle));
-
-
- /* Query the GPU information */
- ret = NvCtrlGetStringAttribute(gpu->handle, NV_CTRL_STRING_PRODUCT_NAME,
- &gpu->name);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query GPU name of GPU-%d.",
- gpu_id);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_CONNECTED_DISPLAYS,
- (int *)&(gpu->connected_displays));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query connected display "
- "devices on GPU-%d '%s'.",
- gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_BUS,
- (int *)&(gpu->pci_bus));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query PCI BUS on GPU-%d '%s'.",
- gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_DEVICE,
- (int *)&(gpu->pci_device));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query PCI DEVICE on "
- "GPU-%d '%s'.", gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_PCI_FUNCTION,
- (int *)&(gpu->pci_func));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query PCI FUNCTION on "
- "GPU-%d '%s'.", gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_WIDTH,
- (int *)&(gpu->max_width));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query MAX SCREEN WIDTH on "
- "GPU-%d '%s'.", gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_HEIGHT,
- (int *)&(gpu->max_height));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query MAX SCREEN HEIGHT on "
- "GPU-%d '%s'.", gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
- ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_DISPLAYS,
- (int *)&(gpu->max_displays));
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup_printf("Failed to query MAX DISPLAYS on "
- "GPU-%d '%s'.", gpu_id, gpu->name);
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Add the display devices to the GPU */
- if (!add_displays_to_gpu(gpu, err_str)) {
- nv_warning_msg("Failed to add displays to GPU-%d '%s'.",
- gpu_id, gpu->name);
- goto fail;
- }
-
-
- /* Add the X screens to the GPU */
- if (!add_screens_to_gpu(gpu, err_str)) {
- nv_warning_msg("Failed to add screens to GPU-%d '%s'.",
- gpu_id, gpu->name);
- goto fail;
- }
-
-
- /* Add fake modes to screenless display devices */
- if (!add_screenless_modes_to_displays(gpu)) {
- nv_warning_msg("Failed to add screenless modes to GPU-%d '%s'.",
- gpu_id, gpu->name);
- goto fail;
- }
-
-
- /* Add the GPU at the end of the layout's GPU list */
- layout->gpus = (nvGpuPtr)xconfigAddListItem((GenericListPtr)layout->gpus,
- (GenericListPtr)gpu);
- layout->num_gpus++;
- return TRUE;
-
-
- /* Failure case */
- fail:
- free_gpu(gpu);
- return FALSE;
-
-} /* add_gpu_to_layout() */
-
-
-
-/** remove_gpus_from_layout() ****************************************
- *
- * Removes all GPUs from the layout structure.
- *
- **/
-static void remove_gpus_from_layout(nvLayoutPtr layout)
-{
- nvGpuPtr gpu;
-
- if (layout) {
- while (layout->gpus) {
- gpu = layout->gpus;
- layout->gpus = gpu->next;
- free_gpu(gpu);
- }
- layout->num_gpus = 0;
- }
-
-} /* remove_gpus_from_layout() */
-
-
-
-/** add_gpus_to_layout() *********************************************
- *
- * Adds the GPUs found on the server to the layout structure.
- *
- **/
-
-static int add_gpus_to_layout(nvLayoutPtr layout, gchar **err_str)
-{
- ReturnStatus ret;
- int ngpus;
- int i;
-
-
- /* Clean up the GPU list */
- remove_gpus_from_layout(layout);
-
-
- /* Query the number of GPUs on the server */
- ret = NvCtrlQueryTargetCount(layout->handle, NV_CTRL_TARGET_TYPE_GPU,
- &ngpus);
- if (ret != NvCtrlSuccess || !ngpus) {
- *err_str = g_strdup("Failed to query number of GPUs (or no GPUs "
- "found) in the system.");
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Add each GPU */
- for (i = 0; i < ngpus; i++) {
- if (!add_gpu_to_layout(layout, i, err_str)) {
- nv_warning_msg("Failed to add GPU-%d to layout.", i);
- goto fail;
- }
- }
-
- return layout->num_gpus;
-
-
- /* Failure case */
- fail:
- remove_gpus_from_layout(layout);
- return 0;
-
-} /* add_gpus_to_layout() */
-
-
-
-/* Layout functions **************************************************/
-
-
/** assign_screen_positions() ****************************************
*
* Assign the initial position of the X screens.
@@ -2895,8 +591,8 @@ static void assign_screen_positions(CtkDisplayConfig *ctk_object)
screen_parsed_info.width = -1;
screen_parsed_info.height = -1;
- parse_tokens(screen_info, apply_screen_info_token,
- &screen_parsed_info);
+ parse_token_value_pairs(screen_info, apply_screen_info_token,
+ &screen_parsed_info);
if (screen_parsed_info.x >= 0 &&
screen_parsed_info.y >= 0 &&
@@ -2926,58 +622,6 @@ static void assign_screen_positions(CtkDisplayConfig *ctk_object)
-/** load_server_layout() *********************************************
- *
- * Loads layout information from the X server.
- *
- **/
-
-nvLayoutPtr load_server_layout(NvCtrlAttributeHandle *handle, gchar **err_str)
-{
- nvLayoutPtr layout;
- ReturnStatus ret;
-
-
- /* Allocate the layout structure */
- layout = (nvLayoutPtr)calloc(1, sizeof(nvLayout));
- if (!layout) goto fail;
-
-
- /* Cache the handle for talking to the X server */
- layout->handle = handle;
-
-
- /* Is Xinerma enabled? */
- ret = NvCtrlGetAttribute(handle, NV_CTRL_XINERAMA,
- &layout->xinerama_enabled);
- if (ret != NvCtrlSuccess) {
- *err_str = g_strdup("Failed to query status of Xinerama.");
- nv_error_msg(*err_str);
- goto fail;
- }
-
-
- /* Add GPUs to the layout */
- if (!add_gpus_to_layout(layout, err_str)) {
- nv_warning_msg("Failed to add GPU(s) to layout for display "
- "configuration page.");
- goto fail;
- }
-
- return layout;
-
-
- /* Failure case */
- fail:
- if (layout) {
- remove_gpus_from_layout(layout);
- free(layout);
- }
- return NULL;
-
-} /* load_server_layout() */
-
-
/* Widget creation functions *****************************************/
@@ -3162,7 +806,7 @@ GtkWidget * create_validation_apply_dialog(CtkDisplayConfig *ctk_object)
str = g_strdup_printf("The current settings cannot be completely applied\n"
"due to one or more of the following reasons:\n"
"\n"
- "%s The location an X screen has changed.\n"
+ "%s The location of an X screen has changed.\n"
"%s The location type of an X screen has changed.\n"
"%s The color depth of an X screen has changed.\n"
"%s An X screen has been added or removed.\n"
@@ -3249,7 +893,7 @@ GtkWidget* ctk_display_config_new(NvCtrlAttributeHandle *handle,
*/
/* Load the layout structure from the X server */
- ctk_object->layout = load_server_layout(handle, &err_str);
+ ctk_object->layout = layout_load_from_server(handle, &err_str);
/* If we failed to load, tell the user why */
if (err_str || !ctk_object->layout) {
@@ -3603,6 +1247,9 @@ GtkWidget* ctk_display_config_new(NvCtrlAttributeHandle *handle,
ctk_object->txt_xconfig_file = gtk_entry_new();
gtk_widget_set_size_request(ctk_object->txt_xconfig_file, 300, -1);
+ g_signal_connect(G_OBJECT(ctk_object->txt_xconfig_file), "activate",
+ G_CALLBACK(xconfig_file_activate),
+ (gpointer) ctk_object);
ctk_object->btn_xconfig_file = gtk_button_new_with_label("Browse...");
g_signal_connect(G_OBJECT(ctk_object->btn_xconfig_file), "clicked",
@@ -3611,6 +1258,13 @@ GtkWidget* ctk_display_config_new(NvCtrlAttributeHandle *handle,
ctk_object->dlg_xconfig_file = gtk_file_selection_new
("Please select the X configuration file");
+ ctk_object->btn_xconfig_merge =
+ gtk_check_button_new_with_label("Merge with existing file.");
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(ctk_object->btn_xconfig_merge), TRUE);
+ g_signal_connect(G_OBJECT(ctk_object->btn_xconfig_merge), "toggled",
+ G_CALLBACK(xconfig_merge_toggled),
+ (gpointer) ctk_object);
/* Apply button */
@@ -3994,6 +1648,12 @@ GtkWidget* ctk_display_config_new(NvCtrlAttributeHandle *handle,
hbox,
FALSE, FALSE, 5);
+ /* Merge checkbox */
+ gtk_box_pack_start
+ (GTK_BOX(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox),
+ ctk_object->btn_xconfig_merge,
+ FALSE, FALSE, 5);
+
gtk_widget_show_all(GTK_DIALOG(ctk_object->dlg_xconfig_save)->vbox);
}
@@ -4124,34 +1784,6 @@ GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *table,
/* Widget setup & helper functions ***********************************/
-/** get_window_parent() **********************************************
- *
- * Returns the parent window of a widget, if one exists
- *
- **/
-
-static GtkWidget * get_window_parent(GtkWidget *child)
-{
- GtkWidget *parent = gtk_widget_get_parent(child);
-
-
- while (parent && !GTK_IS_WINDOW(parent)) {
- GtkWidget *last = parent;
-
- parent = gtk_widget_get_parent(last);
- if (!parent || parent == last) {
- /* GTK Error, can't find parent window! */
- parent = NULL;
- break;
- }
- }
-
- return parent;
-
-} /* get_window_parent() */
-
-
-
/** setup_layout_frame() *********************************************
*
* Sets up the layout frame to reflect the currently selected layout.
@@ -4956,7 +2588,7 @@ static void setup_display_frame(CtkDisplayConfig *ctk_object)
/* Setup the display name */
- type = get_display_type_str(display->device_mask, 0);
+ type = display_get_type_str(display->device_mask, 0);
str = g_strdup_printf("%s (%s)", display->name, type);
g_free(type);
gtk_label_set_text(GTK_LABEL(ctk_object->txt_display_model), str);
@@ -5498,10 +3130,10 @@ static gint validation_remove_dupe_metamodes(CtkDisplayConfig *ctk_object,
/* Verify each metamode with the metamodes that come before it */
for (i = 1; i < screen->num_metamodes; i++) {
- metamode_str = get_screen_metamode_str(screen, i, 0);
+ metamode_str = screen_get_metamode_str(screen, i, 0);
for (j = 0; j < i; j++) {
char *tmp;
- tmp = get_screen_metamode_str(screen, j, 0);
+ tmp = screen_get_metamode_str(screen, j, 0);
/* Remove duplicates */
if (!strcmp(metamode_str, tmp)) {
@@ -5675,9 +3307,9 @@ static gchar * validate_screen(nvScreenPtr screen)
/* Verify that the metamode is unique */
- metamode_str = get_screen_metamode_str(screen, i, 0);
+ metamode_str = screen_get_metamode_str(screen, i, 0);
for (j = 0; j < i; j++) {
- char *tmp = get_screen_metamode_str(screen, j, 0);
+ char *tmp = screen_get_metamode_str(screen, j, 0);
/* Make sure the metamode is unique */
if (!strcmp(metamode_str, tmp)) {
@@ -5748,7 +3380,7 @@ static int validate_layout(CtkDisplayConfig *ctk_object, int validation_type)
*/
if (num_absolute > 1) {
GtkWidget *dlg;
- GtkWidget *parent = get_window_parent(GTK_WIDGET(ctk_object));
+ GtkWidget *parent = ctk_get_parent_window(GTK_WIDGET(ctk_object));
if (parent) {
dlg = gtk_message_dialog_new
@@ -6043,7 +3675,7 @@ void do_enable_display_for_xscreen(CtkDisplayConfig *ctk_object,
screen->scrnum = scrnum;
screen->gpu = display->gpu;
- other = get_a_screen(layout, display->gpu);
+ other = layout_get_a_screen(layout, display->gpu);
screen->depth = other ? other->depth : 24;
screen->displays_mask = display->device_mask;
@@ -6192,7 +3824,7 @@ static void do_enable_display_for_twinview(CtkDisplayConfig *ctk_object,
"display devices.",
display->name, screen->scrnum);
- parent = get_window_parent(GTK_WIDGET(ctk_object));
+ parent = ctk_get_parent_window(GTK_WIDGET(ctk_object));
if (parent) {
dlg = gtk_message_dialog_new
@@ -6224,7 +3856,7 @@ static void do_enable_display_for_twinview(CtkDisplayConfig *ctk_object,
prepare_gpu_for_twinview(ctk_object, gpu);
/* Fix up the display's metamode list */
- remove_modes_from_display(display);
+ display_remove_modes(display);
for (metamode = screen->metamodes; metamode; metamode = metamode->next) {
@@ -6246,7 +3878,7 @@ static void do_enable_display_for_twinview(CtkDisplayConfig *ctk_object,
/* Create the nvidia-auto-select mode fo the display */
- mode = parse_mode(display, "nvidia-auto-select");
+ mode = mode_parse(display, "nvidia-auto-select");
mode->metamode = metamode;
@@ -6510,7 +4142,7 @@ static void do_configure_display_for_twinview(CtkDisplayConfig *ctk_object,
/* Add dummy modes */
while (metamode) {
- mode = parse_mode(display, "NULL");
+ mode = mode_parse(display, "NULL");
mode->dummy = 1;
mode->metamode = metamode;
@@ -6654,7 +4286,7 @@ void do_disable_display(CtkDisplayConfig *ctk_object, nvDisplayPtr display)
nvGpuPtr gpu = display->gpu;
nvScreenPtr screen = display->screen;
gchar *str;
- gchar *type = get_display_type_str(display->device_mask, 0);
+ gchar *type = display_get_type_str(display->device_mask, 0);
/* Setup the remove display dialog */
@@ -6683,19 +4315,18 @@ void do_disable_display(CtkDisplayConfig *ctk_object, nvDisplayPtr display)
if (do_query_remove_display(ctk_object, display)) {
/* Remove display from the X screen */
- remove_display_from_screen(display);
+ screen_remove_display(display);
/* If the screen is empty, remove it */
if (!screen->num_displays) {
- remove_screen_from_gpu(screen);
- free_screen(screen);
+ gpu_remove_and_free_screen(screen);
/* Make sure screen numbers are consistent */
renumber_xscreens(ctk_object->layout);
}
/* Add the fake mode to the display */
- add_screenless_modes_to_displays(display->gpu);
+ gpu_add_screenless_modes_to_displays(display->gpu);
}
} /* do_disable_display() */
@@ -6848,7 +4479,7 @@ static void display_config_clicked(GtkWidget *widget, gpointer user_data)
NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL,
"", &tokens);
update = TRUE;
- if (!add_modelines_to_display(display, &err_str)) {
+ if (!display_add_modelines_from_server(display, &err_str)) {
nv_warning_msg(err_str);
g_free(err_str);
return;
@@ -6949,7 +4580,8 @@ static void display_refresh_changed(GtkWidget *widget, gpointer user_data)
* to change which metamode is being used.
*/
if (!ctk_object->advanced_mode && (display->screen->num_displays == 1)) {
- int metamode_idx = find_closest_mode_with_modeline(display, modeline);
+ int metamode_idx =
+ display_find_closest_mode_matching_modeline(display, modeline);
/* Select the new metamode */
if (metamode_idx >= 0) {
@@ -7006,7 +4638,8 @@ static void display_resolution_changed(GtkWidget *widget, gpointer user_data)
* to change which metamode is being used.
*/
if (!ctk_object->advanced_mode && (display->screen->num_displays == 1)) {
- int metamode_idx = find_closest_mode_with_modeline(display, modeline);
+ int metamode_idx =
+ display_find_closest_mode_matching_modeline(display, modeline);
/* Select the new metamode */
if (metamode_idx >= 0) {
@@ -7176,7 +4809,7 @@ static void display_position_offset_activate(GtkWidget *widget,
if (!display) return;
/* Parse user input */
- str = read_pair(str, 0, &x, &y);
+ str = parse_read_integer_pair(str, 0, &x, &y);
if (!str) {
/* Reset the display position */
setup_display_position_offset(ctk_object);
@@ -7218,7 +4851,7 @@ static void display_panning_activate(GtkWidget *widget, gpointer user_data)
return;
}
- str = read_pair(str, 'x', &x, &y);
+ str = parse_read_integer_pair(str, 'x', &x, &y);
if (!str) {
/* Reset the display panning */
setup_display_panning(ctk_object);
@@ -7402,7 +5035,7 @@ static void screen_position_offset_activate(GtkWidget *widget,
/* Parse user input */
- str = read_pair(str, 0, &x, &y);
+ str = parse_read_integer_pair(str, 0, &x, &y);
if (!str) {
/* Reset the display position */
setup_screen_position_offset(ctk_object);
@@ -7449,7 +5082,7 @@ static void screen_metamode_clicked(GtkWidget *widget, gpointer user_data)
for (i = 0; i < screen->num_metamodes; i++) {
/* Setup the menu item text */
- tmp = get_screen_metamode_str(screen, i, 1);
+ tmp = screen_get_metamode_str(screen, i, 1);
str = g_strdup_printf("%d - \"%s\"", i+1, tmp);
menu_item = gtk_menu_item_new_with_label(str);
g_free(str);
@@ -7684,7 +5317,7 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object,
/* Find the parent window for displaying dialogs */
- parent = get_window_parent(GTK_WIDGET(ctk_object));
+ parent = ctk_get_parent_window(GTK_WIDGET(ctk_object));
if (!parent) goto fail;
@@ -7867,7 +5500,7 @@ static char *find_metamode_string(char *metamode_str, char *metamode_strs)
/* Skip tokens if any */
str = strstr(m, "::");
if (str) {
- str = (char *)skip_whitespace(str +2);
+ str = (char *)parse_skip_whitespace(str +2);
} else {
str = m;
}
@@ -7913,7 +5546,7 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs)
/* Generate the metamode's string */
free(metamode->string);
- metamode->string = get_screen_metamode_str(screen, metamode_idx, 0);
+ metamode->string = screen_get_metamode_str(screen, metamode_idx, 0);
if (!metamode->string) continue;
/* Look for the metamode string in metamode_strs */
@@ -7926,7 +5559,8 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs)
char *tmp = strstr(tokens, "::");
if (tmp) {
*tmp = '\0';
- parse_tokens(tokens, apply_metamode_token, metamode);
+ parse_token_value_pairs(tokens, apply_metamode_token,
+ metamode);
}
free(tokens);
}
@@ -7950,7 +5584,8 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs)
/* Grab the metamode ID from the returned tokens */
if (ret == NvCtrlSuccess) {
if (tokens) {
- parse_tokens(tokens, apply_metamode_token, metamode);
+ parse_token_value_pairs(tokens, apply_metamode_token,
+ metamode);
free(tokens);
}
nv_info_msg(TAB, "Added > %s", metamode->string);
@@ -7982,7 +5617,7 @@ static void order_metamodes(nvScreenPtr screen)
metamode;
metamode = metamode->next, metamode_idx++) {
- metamode_str = get_screen_metamode_str(screen, metamode_idx,
+ metamode_str = screen_get_metamode_str(screen, metamode_idx,
0);
if (!metamode_str) continue;
@@ -8029,7 +5664,7 @@ static void postprocess_metamodes(nvScreenPtr screen, char *metamode_strs)
str = strstr(metamode_str, "::");
if (!str) continue;
- str = (char *)skip_whitespace(str +2);
+ str = (char *)parse_skip_whitespace(str +2);
/* Delete the metamode */
@@ -8107,7 +5742,7 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object,
/* Skip tokens */
metamode_str = strstr(cur_metamode_str, "::");
if (metamode_str) {
- metamode_str = (char *)skip_whitespace(metamode_str +2);
+ metamode_str = (char *)parse_skip_whitespace(metamode_str +2);
} else {
metamode_str = cur_metamode_str;
}
@@ -8246,6 +5881,8 @@ static void xconfig_file_clicked(GtkWidget *widget, gpointer user_data)
gtk_entry_set_text(GTK_ENTRY(ctk_object->txt_xconfig_file),
filename);
+
+ update_xconfig_save_buffer(ctk_object);
break;
default:
return;
@@ -8255,6 +5892,22 @@ static void xconfig_file_clicked(GtkWidget *widget, gpointer user_data)
+/** xconfig_file_activate() ******************************************
+ *
+ * Called when the user selects a new X config filename.
+ *
+ **/
+
+static void xconfig_file_activate(GtkWidget *widget, gpointer user_data)
+{
+ CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data);
+
+ update_xconfig_save_buffer(ctk_object);
+
+} /* xconfig_file_activate() */
+
+
+
/** xconfig_preview_clicked() ****************************************
*
* Called when the user clicks on the "Preview" button of the
@@ -8286,6 +5939,200 @@ static void xconfig_preview_clicked(GtkWidget *widget, gpointer user_data)
+/** update_xconfig_save_buffer() ************************************
+ *
+ * Updates the "preview" buffer to hold the right contents based on
+ * how the user wants the X config file to be generated (and what is
+ * possible.)
+ *
+ * Also updates the state of the "Merge" checkbox in the case where
+ * the named file can/cannot be parsed as a valid X config file.
+ *
+ */
+static gboolean update_xconfig_save_buffer(CtkDisplayConfig *ctk_object)
+{
+ gchar *filename;
+ XConfigPtr config = NULL;
+ XConfigPtr mergeConfig = NULL;
+ XConfigError error;
+ gint result;
+
+ char *tmp_filename;
+ int tmp_fd;
+ struct stat st;
+ void *buf;
+ GtkTextIter buf_start, buf_end;
+
+ gboolean merge;
+ gboolean mergable = TRUE;
+
+ gchar *err_msg = NULL;
+
+
+ /* Get how the user wants to generate the X config file */
+ merge = gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(ctk_object->btn_xconfig_merge));
+
+ filename = (gchar *)gtk_entry_get_text
+ (GTK_ENTRY(ctk_object->txt_xconfig_file));
+
+
+ /* Find out if the file is mergable */
+ if (!filename) {
+ mergable = FALSE;
+ } else {
+ /* Must be able to open the file */
+ tmp_filename = (char *)xconfigOpenConfigFile(filename, NULL);
+ if (!tmp_filename || strcmp(tmp_filename, filename)) {
+ gchar *msg =
+ g_strdup_printf("Failed to open existing X config file '%s'!",
+ filename);
+ ctk_display_warning_msg
+ (ctk_get_parent_window(GTK_WIDGET(ctk_object)),
+ msg);
+ g_free(msg);
+
+ xconfigCloseConfigFile();
+ mergable = FALSE;
+
+ } else {
+
+ /* Must be able to parse the file as an X config file */
+ error = xconfigReadConfigFile(&mergeConfig);
+ if (error) {
+ /* If we failed to parse the config file, we should not
+ * allow a merge.
+ */
+ gchar *msg =
+ g_strdup_printf("Failed to parse existing X config file "
+ "'%s'!", filename);
+ ctk_display_warning_msg
+ (ctk_get_parent_window(GTK_WIDGET(ctk_object)),
+ msg);
+ g_free(msg);
+
+ xconfigCloseConfigFile();
+ mergeConfig = NULL;
+ mergable = FALSE;
+ }
+ }
+
+ /* If we're not actualy doing a merge, close the file */
+ if (!merge && mergeConfig) {
+ xconfigFreeConfig(mergeConfig);
+ xconfigCloseConfigFile();
+ mergeConfig = NULL;
+ }
+ }
+
+ merge = (merge && mergable);
+
+
+ /* Report merge problems */
+ g_signal_handlers_block_by_func
+ (G_OBJECT(ctk_object->btn_xconfig_merge),
+ G_CALLBACK(xconfig_merge_toggled), (gpointer) ctk_object);
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(ctk_object->btn_xconfig_merge), merge);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(ctk_object->btn_xconfig_merge),
+ G_CALLBACK(xconfig_merge_toggled), (gpointer) ctk_object);
+
+ gtk_widget_set_sensitive(ctk_object->btn_xconfig_merge, mergable);
+
+
+ /* Generate an X config structure from our layout */
+ result = generateXConfig(ctk_object, &config);
+ if ((result != XCONFIG_GEN_OK) || !config) {
+ err_msg = g_strdup("Failed to generate an X config file!");
+ goto fail;
+ }
+
+
+ /* Merge the two X config structures */
+ if (mergeConfig) {
+ result = xconfigMergeConfigs(mergeConfig, config);
+ xconfigFreeConfig(config);
+ xconfigCloseConfigFile();
+ config = mergeConfig;
+ if (!result) {
+ xconfigFreeConfig(mergeConfig);
+ err_msg = g_strdup_printf("Failed to merge current configuration "
+ "with existing X config file '%s'!",
+ filename);
+ goto fail;
+ }
+ }
+
+
+ /* Update the X config banner */
+ update_banner(config);
+
+
+ /* Setup the X config file preview buffer by writing to a temp file */
+ tmp_filename = g_strdup_printf("/tmp/.xconfig.tmp.XXXXXX");
+ tmp_fd = mkstemp(tmp_filename);
+ if (!tmp_fd) {
+ err_msg = g_strdup_printf("Failed to create temp X config file '%s' "
+ "for display.",
+ tmp_filename);
+ g_free(tmp_filename);
+ goto fail;
+ }
+ xconfigWriteConfigFile(tmp_filename, config);
+ xconfigFreeConfig(config);
+
+ lseek(tmp_fd, 0, SEEK_SET);
+ fstat(tmp_fd, &st);
+ buf = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0);
+
+ /* Clear the GTK buffer */
+ gtk_text_buffer_get_bounds
+ (GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save), &buf_start,
+ &buf_end);
+ gtk_text_buffer_delete
+ (GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save), &buf_start,
+ &buf_end);
+
+ /* Set the new GTK buffer contents */
+ gtk_text_buffer_set_text(GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save),
+ buf, st.st_size);
+ munmap(buf, st.st_size);
+ close(tmp_fd);
+ remove(tmp_filename);
+ g_free(tmp_filename);
+
+ return TRUE;
+
+ fail:
+ if (err_msg) {
+ ctk_display_error_msg(ctk_get_parent_window(GTK_WIDGET(ctk_object)),
+ err_msg);
+ g_free(err_msg);
+ }
+ return FALSE;
+
+} /* update_xconfig_save_buffer() */
+
+
+
+/** xconfig_merge_toggled() ******************************************
+ *
+ * Called when the user clicks on the "Merge" button of the X config
+ * save dialog.
+ *
+ **/
+
+static void xconfig_merge_toggled(GtkWidget *widget, gpointer user_data)
+{
+ update_xconfig_save_buffer((CtkDisplayConfig *)user_data);
+
+} /* xconfig_merge_toggled() */
+
+
+
/** makeXConfigModeline() ********************************************
*
* Returns a copy of an XF86Config-parser modeline structure.
@@ -8411,7 +6258,7 @@ static Bool add_monitor_to_xconfig(nvDisplayPtr display, XConfigPtr config,
tmp += 2;
}
- if (!read_float_range(tmp, &min, &max)) {
+ if (!parse_read_float_range(tmp, &min, &max)) {
nv_error_msg("Unable to determine valid horizontal sync ranges "
"for display device '%s' (GPU: %s)!",
display->name, display->gpu->name);
@@ -8422,7 +6269,8 @@ static Bool add_monitor_to_xconfig(nvDisplayPtr display, XConfigPtr config,
monitor->hsync[0].lo = min;
monitor->hsync[0].hi = max;
- parse_tokens(range_str, apply_monitor_token, (void *)(&h_source));
+ parse_token_value_pairs(range_str, apply_monitor_token,
+ (void *)(&h_source));
free(range_str);
range_str = NULL;
@@ -8447,7 +6295,7 @@ static Bool add_monitor_to_xconfig(nvDisplayPtr display, XConfigPtr config,
tmp += 2;
}
- if (!read_float_range(tmp, &min, &max)) {
+ if (!parse_read_float_range(tmp, &min, &max)) {
nv_error_msg("Unable to determine valid vertical refresh ranges "
"for display device '%s' (GPU: %s)!",
display->name, display->gpu->name);
@@ -8458,7 +6306,8 @@ static Bool add_monitor_to_xconfig(nvDisplayPtr display, XConfigPtr config,
monitor->vrefresh[0].lo = min;
monitor->vrefresh[0].hi = max;
- parse_tokens(range_str, apply_monitor_token, (void *)(&v_source));
+ parse_token_value_pairs(range_str, apply_monitor_token,
+ (void *)(&v_source));
free(range_str);
range_str = NULL;
@@ -8659,13 +6508,11 @@ static int add_screen_to_xconfig(CtkDisplayConfig *ctk_object,
add_modelines_to_monitor(display->conf_monitor, other->modes);
}
- /* Add the TwinView option for multi monitor setups */
- if (screen->num_displays > 1) {
- conf_screen->options =
- xconfigAddNewOption(conf_screen->options,
- xconfigStrdup("TwinView"),
- xconfigStrdup("1"));
- }
+ /* Set the TwinView option */
+ conf_screen->options = xconfigAddNewOption
+ (conf_screen->options,
+ xconfigStrdup("TwinView"),
+ xconfigStrdup( (screen->num_displays > 1) ? "1" : "0" ));
/* XXX Setup any other twinview options ... */
@@ -8679,7 +6526,7 @@ static int add_screen_to_xconfig(CtkDisplayConfig *ctk_object,
* whatever the currently selected metamode is
*/
if (!metamode_strs) {
- metamode_strs = get_screen_metamode_str(screen,
+ metamode_strs = screen_get_metamode_str(screen,
screen->cur_metamode_idx, 1);
}
@@ -9154,11 +7001,13 @@ static void update_banner(XConfigPtr config)
*
**/
-static int save_xconfig_file(gchar *filename, char *buf, mode_t mode)
+static int save_xconfig_file(CtkDisplayConfig *ctk_object,
+ gchar *filename, char *buf, mode_t mode)
{
gchar *backup_filename = NULL;
FILE *fp = NULL;
size_t size;
+ gchar *err_msg = NULL;
int ret = 0;
@@ -9179,16 +7028,20 @@ static int save_xconfig_file(gchar *filename, char *buf, mode_t mode)
if (access(backup_filename, F_OK) == 0) {
if (unlink(backup_filename) != 0) {
- nv_error_msg("Unable to create backup file '%s'.",
- backup_filename);
+ err_msg =
+ g_strdup_printf("Unable to remove old X config backup "
+ "file '%s'.",
+ backup_filename);
goto done;
}
}
/* Make the current x config file the backup */
if (rename(filename, backup_filename)) {
- nv_error_msg("Unable to create backup file '%s'.",
- backup_filename);
+ err_msg =
+ g_strdup_printf("Unable to create new X config backup "
+ "file '%s'.",
+ backup_filename);
goto done;
}
}
@@ -9196,8 +7049,9 @@ static int save_xconfig_file(gchar *filename, char *buf, mode_t mode)
/* Write out the X config file */
fp = fopen(filename, "w");
if (!fp) {
- nv_error_msg("Unable to open file '%s' for writing.",
- filename);
+ err_msg =
+ g_strdup_printf("Unable to open X config file '%s' for writing.",
+ filename);
goto done;
}
fprintf(fp, "%s", buf);
@@ -9205,6 +7059,12 @@ static int save_xconfig_file(gchar *filename, char *buf, mode_t mode)
ret = 1;
done:
+ /* Display any errors that might have occured */
+ if (err_msg) {
+ ctk_display_error_msg(ctk_get_parent_window(GTK_WIDGET(ctk_object)),
+ err_msg);
+ g_free(err_msg);
+ }
if (fp) fclose(fp);
g_free(backup_filename);
@@ -9224,13 +7084,10 @@ static void save_clicked(GtkWidget *widget, gpointer user_data)
{
CtkDisplayConfig *ctk_object = CTK_DISPLAY_CONFIG(user_data);
gint result;
+ gboolean created;
gchar *filename;
- XConfigPtr config = NULL;
- char *tmp_filename;
- int tmp_fd;
- struct stat st;
void *buf;
GtkTextIter buf_start, buf_end;
@@ -9256,40 +7113,12 @@ static void save_clicked(GtkWidget *widget, gpointer user_data)
ctk_object->layout->filename);
- /* Generate an X config file from the layout */
- result = generateXConfig(ctk_object, &config);
-
- if ((result != XCONFIG_GEN_OK) || !config) {
- if (result == XCONFIG_GEN_ERROR) {
- nv_error_msg("Failed to generate an X config file!");
- }
- return;
- }
-
- /* Update the X config banner */
- update_banner(config);
-
- /* Setup the X config file preview buffer by writing to a temp file */
- tmp_filename = g_strdup_printf("/tmp/.xconfig.tmp.XXXXXX");
- tmp_fd = mkstemp(tmp_filename);
- if (!tmp_fd) {
- nv_error_msg("Failed to create temp file for displaying X config!");
- g_free(tmp_filename);
+ /* Generate the X config file save buffer */
+ created = update_xconfig_save_buffer(ctk_object);
+ if (!created) {
return;
}
- xconfigWriteConfigFile(tmp_filename, config);
- xconfigFreeConfig(config);
- lseek(tmp_fd, 0, SEEK_SET);
- fstat(tmp_fd, &st);
- buf = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0);
- gtk_text_buffer_set_text(GTK_TEXT_BUFFER(ctk_object->buf_xconfig_save),
- buf, st.st_size);
- munmap(buf, st.st_size);
- close(tmp_fd);
- remove(tmp_filename);
- g_free(tmp_filename);
-
/* Confirm the save */
gtk_window_set_transient_for
@@ -9337,7 +7166,7 @@ static void save_clicked(GtkWidget *widget, gpointer user_data)
/* Save the X config file */
nv_info_msg("", "Writing X config file '%s'", filename);
- save_xconfig_file(filename, (char *)buf, 0644);
+ save_xconfig_file(ctk_object, filename, (char *)buf, 0644);
g_free(buf);
break;
@@ -9433,7 +7262,7 @@ static void probe_clicked(GtkWidget *widget, gpointer user_data)
if ((gpu->connected_displays & mask) &&
!(probed_displays & mask)) {
- display = get_display_from_gpu(gpu, mask);
+ display = gpu_get_display(gpu, mask);
if (!display) continue; /* XXX ack. */
/* The selected display is being removed */
@@ -9442,7 +7271,7 @@ static void probe_clicked(GtkWidget *widget, gpointer user_data)
}
/* Setup the remove display dialog */
- type = get_display_type_str(display->device_mask, 0);
+ type = display_get_type_str(display->device_mask, 0);
str = g_strdup_printf("The display device %s (%s) on GPU-%d "
"(%s) has been\nunplugged. Would you "
"like to remove this display from the "
@@ -9467,8 +7296,7 @@ static void probe_clicked(GtkWidget *widget, gpointer user_data)
if (do_query_remove_display(ctk_object, display)) {
/* Remove display from the GPU */
- remove_display_from_gpu(display);
- free_display(display);
+ gpu_remove_and_free_display(display);
/* Let display layout widget know about change */
ctk_display_layout_update_display_count
@@ -9482,12 +7310,12 @@ static void probe_clicked(GtkWidget *widget, gpointer user_data)
} else if (!(gpu->connected_displays & mask) &&
(probed_displays & mask)) {
gchar *err_str = NULL;
- display = add_display_to_gpu(gpu, mask, &err_str);
+ display = gpu_add_display_from_server(gpu, mask, &err_str);
if (err_str) {
nv_warning_msg(err_str);
g_free(err_str);
}
- add_screenless_modes_to_displays(gpu);
+ gpu_add_screenless_modes_to_displays(gpu);
ctk_display_layout_update_display_count
(CTK_DISPLAY_LAYOUT(ctk_object->obj_layout),
selected_display);
@@ -9544,7 +7372,7 @@ static void reset_clicked(GtkWidget *widget, gpointer user_data)
/* Load the current layout */
- layout = load_server_layout(ctk_object->handle, &err_str);
+ layout = layout_load_from_server(ctk_object->handle, &err_str);
/* Handle errors loading the new layout */
@@ -9556,10 +7384,7 @@ static void reset_clicked(GtkWidget *widget, gpointer user_data)
/* Free the existing layout */
- if (ctk_object->layout) {
- remove_gpus_from_layout(ctk_object->layout);
- free(ctk_object->layout);
- }
+ layout_free(ctk_object->layout);
/* Setup the new layout */
diff --git a/src/gtk+-2.x/ctkdisplayconfig.h b/src/gtk+-2.x/ctkdisplayconfig.h
index e6d3ec6..ed80e29 100644
--- a/src/gtk+-2.x/ctkdisplayconfig.h
+++ b/src/gtk+-2.x/ctkdisplayconfig.h
@@ -152,12 +152,13 @@ typedef struct _CtkDisplayConfig
guint display_confirm_timer;
int display_confirm_countdown; /* Timeout to reset display config */
- GtkWidget *dlg_xconfig_save; /* Save X config dialog */
- GtkWidget *scr_xconfig_save;
- GtkWidget *txt_xconfig_save; /* Text file... */
- GtkTextBuffer *buf_xconfig_save; /* Text file... */
- GtkWidget *btn_xconfig_preview; /* Show/Hide button */
- GtkWidget *box_xconfig_save; /* Show/Hide this box */
+ GtkWidget *dlg_xconfig_save; /* Save X config dialog */
+ GtkWidget *scr_xconfig_save; /* Scroll window */
+ GtkWidget *txt_xconfig_save; /* Text view of file contents */
+ GtkTextBuffer *buf_xconfig_save; /* Text buffer (Actual) file contents */
+ GtkWidget *btn_xconfig_merge; /* Merge with existing X config */
+ GtkWidget *btn_xconfig_preview; /* Show/Hide button */
+ GtkWidget *box_xconfig_save; /* Show/Hide this box */
GtkWidget *dlg_xconfig_file; /* File save dialog */
GtkWidget *btn_xconfig_file;
diff --git a/src/gtk+-2.x/ctkdisplaydevice-crt.c b/src/gtk+-2.x/ctkdisplaydevice-crt.c
index bb4170a..26dbd4b 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-crt.c
+++ b/src/gtk+-2.x/ctkdisplaydevice-crt.c
@@ -33,7 +33,7 @@
#include "ctkedid.h"
#include "ctkconfig.h"
#include "ctkhelp.h"
-
+#include <stdio.h>
static void ctk_display_device_crt_class_init(CtkDisplayDeviceCrtClass *);
static void ctk_display_device_crt_finalize(GObject *);
@@ -43,9 +43,17 @@ static void reset_button_clicked(GtkButton *button, gpointer user_data);
static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt
*ctk_display_device_crt);
+static void info_update_received(GtkObject *object, gpointer arg1,
+ gpointer user_data);
+
+static void crt_info_setup(CtkDisplayDeviceCrt *ctk_display_device_crt);
+
static void enabled_displays_received(GtkObject *object, gpointer arg1,
gpointer user_data);
+static const char * __refresh_rate_help = "The refresh rate displays the "
+"rate at which the screen is currently refreshing the image.";
+
GType ctk_display_device_crt_get_type(void)
{
static GType ctk_display_device_crt_type = 0;
@@ -101,8 +109,11 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle,
CtkDisplayDeviceCrt *ctk_display_device_crt;
GtkWidget *banner;
GtkWidget *hbox;
+ GtkWidget *tmpbox;
+ GtkWidget *tmphbox, *eventbox;
+ GtkWidget *frame;
GtkWidget *alignment;
-
+
object = g_object_new(CTK_TYPE_DISPLAY_DEVICE_CRT, NULL);
ctk_display_device_crt = CTK_DISPLAY_DEVICE_CRT(object);
@@ -111,7 +122,7 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle,
ctk_display_device_crt->ctk_event = ctk_event;
ctk_display_device_crt->display_device_mask = display_device_mask;
ctk_display_device_crt->name = g_strdup(name);
-
+ ctk_display_device_crt->txt_refresh_rate = gtk_label_new("");
gtk_box_set_spacing(GTK_BOX(object), 10);
/* banner */
@@ -152,7 +163,47 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle,
ctk_display_device_crt->image_sliders,
FALSE, FALSE, 0);
}
-
+ /* add the label Refresh Rate and its value */
+
+ frame = gtk_frame_new(NULL);
+ gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
+ tmphbox = gtk_hbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(tmphbox), 5);
+ gtk_container_add(GTK_CONTAINER(frame), tmphbox);
+
+ tmpbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(tmphbox), tmpbox);
+
+ /* pack the Refresh Rate Label */
+ {
+ typedef struct {
+ GtkWidget *label;
+ GtkWidget *txt;
+ const gchar *tooltip;
+ } TextLineInfo;
+
+ TextLineInfo line = {
+ gtk_label_new("Refresh Rate:"),
+ ctk_display_device_crt->txt_refresh_rate,
+ __refresh_rate_help,
+ };
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), line.label,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), line.txt,
+ FALSE, FALSE, 5);
+
+ /* Include tooltips */
+ if (!line.tooltip) {
+ gtk_box_pack_start(GTK_BOX(tmpbox), hbox, FALSE, FALSE, 0);
+ } else {
+ eventbox = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(eventbox), hbox);
+ ctk_config_set_tooltip(ctk_config, eventbox, line.tooltip);
+ gtk_box_pack_start(GTK_BOX(tmpbox), eventbox, FALSE, FALSE, 0);
+ }
+ }
/* pack the EDID button */
hbox = gtk_hbox_new(FALSE, 0);
@@ -174,6 +225,11 @@ GtkWidget* ctk_display_device_crt_new(NvCtrlAttributeHandle *handle,
G_CALLBACK(enabled_displays_received),
(gpointer) ctk_display_device_crt);
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE),
+ G_CALLBACK(info_update_received),
+ (gpointer) ctk_display_device_crt);
+
return GTK_WIDGET(object);
}
@@ -192,6 +248,9 @@ GtkTextBuffer *ctk_display_device_crt_create_help(GtkTextTagTable *table,
ctk_help_title(b, &i, "%s Help", ctk_display_device_crt->name);
+ ctk_help_heading(b, &i, "Refresh rate");
+ ctk_help_para(b, &i, __refresh_rate_help);
+
add_image_sliders_help
(CTK_IMAGE_SLIDERS(ctk_display_device_crt->image_sliders), b, &i);
@@ -249,7 +308,9 @@ static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt
(ret == NvCtrlSuccess &&
(enabled_displays & (ctk_display_device_crt->display_device_mask)));
-
+ /* Update CRT-specific settings */
+ crt_info_setup(ctk_display_device_crt);
+
/* Update the image sliders */
ctk_image_sliders_setup
@@ -259,16 +320,16 @@ static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt
/* update acquire EDID button */
if (ctk_display_device_crt->edid) {
- GList *list;
+ GList *list;
- list = gtk_container_get_children
+ list = gtk_container_get_children
(GTK_CONTAINER(ctk_display_device_crt->edid_box));
- if (list) {
- gtk_container_remove
- (GTK_CONTAINER(ctk_display_device_crt->edid_box),
- (GtkWidget *)(list->data));
- g_list_free(list);
- }
+ if (list) {
+ gtk_container_remove
+ (GTK_CONTAINER(ctk_display_device_crt->edid_box),
+ (GtkWidget *)(list->data));
+ g_list_free(list);
+ }
}
ctk_display_device_crt->edid =
@@ -291,8 +352,28 @@ static void ctk_display_device_crt_setup(CtkDisplayDeviceCrt
} /* ctk_display_device_crt_setup() */
-
-
+static void crt_info_setup(CtkDisplayDeviceCrt *ctk_display_device_crt)
+{
+ ReturnStatus ret;
+ gint val;
+
+ /* Refresh Rate */
+ ret = NvCtrlGetDisplayAttribute(ctk_display_device_crt->handle,
+ ctk_display_device_crt->display_device_mask,
+ NV_CTRL_REFRESH_RATE, &val);
+ if (ret == NvCtrlSuccess) {
+ char str[32];
+ float fvalue = ((float)(val)) / 100.0f;
+ snprintf(str, 32, "%.2f Hz", fvalue);
+ gtk_label_set_text
+ (GTK_LABEL(ctk_display_device_crt->txt_refresh_rate),
+ str);
+ } else {
+ gtk_label_set_text
+ (GTK_LABEL(ctk_display_device_crt->txt_refresh_rate),
+ "Unknown");
+ }
+}
/*
* When the list of enabled displays on the GPU changes,
* this page should disable/enable access based on whether
@@ -306,3 +387,22 @@ static void enabled_displays_received(GtkObject *object, gpointer arg1,
ctk_display_device_crt_setup(ctk_object);
} /* enabled_displays_received() */
+
+
+/*
+ * When resolution changes occur, we should update the GUI to reflect
+ * the current state.
+ */
+
+static void info_update_received(GtkObject *object, gpointer arg1,
+ gpointer user_data)
+{
+ CtkDisplayDeviceCrt *ctk_object = CTK_DISPLAY_DEVICE_CRT(user_data);
+ CtkEventStruct *event_struct = (CtkEventStruct *) arg1;
+
+ /* if the event is not for this display device, return */
+ if (!(event_struct->display_mask & ctk_object->display_device_mask)) {
+ return;
+ }
+ crt_info_setup(ctk_object);
+}
diff --git a/src/gtk+-2.x/ctkdisplaydevice-crt.h b/src/gtk+-2.x/ctkdisplaydevice-crt.h
index 56180d3..3b0745e 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-crt.h
+++ b/src/gtk+-2.x/ctkdisplaydevice-crt.h
@@ -63,6 +63,7 @@ struct _CtkDisplayDeviceCrt
CtkEvent *ctk_event;
GtkWidget *image_sliders;
GtkWidget *reset_button;
+ GtkWidget *txt_refresh_rate;
GtkWidget *edid_box;
GtkWidget *edid;
diff --git a/src/gtk+-2.x/ctkdisplaydevice-dfp.c b/src/gtk+-2.x/ctkdisplaydevice-dfp.c
index 01a3d7b..1ee106c 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-dfp.c
+++ b/src/gtk+-2.x/ctkdisplaydevice-dfp.c
@@ -34,7 +34,7 @@
#include "ctkconfig.h"
#include "ctkhelp.h"
#include "ctkutils.h"
-
+#include <stdio.h>
static void ctk_display_device_dfp_class_init(CtkDisplayDeviceDfpClass *);
static void ctk_display_device_dfp_finalize(GObject *);
@@ -46,17 +46,8 @@ static GtkWidget *make_scaling_radio_button(CtkDisplayDeviceDfp
char *label,
gint value);
-static GtkWidget *make_dithering_radio_button(CtkDisplayDeviceDfp
- *ctk_display_device_dfp,
- GtkWidget *vbox,
- GtkWidget *prev_radio,
- char *label,
- gint value);
-
static void dfp_scaling_changed(GtkWidget *widget, gpointer user_data);
-static void dfp_dithering_changed(GtkWidget *widget, gpointer user_data);
-
static void reset_button_clicked(GtkButton *button, gpointer user_data);
static void
@@ -64,10 +55,6 @@ dfp_scaling_update_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp,
gint value);
-static void
-dfp_dithering_update_radio_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp,
- gint value);
-
static void dfp_update_received(GtkObject *object, gpointer arg1,
gpointer user_data);
@@ -75,8 +62,6 @@ static void dfp_info_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp);
static void dfp_scaling_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp);
-static void dfp_dithering_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp);
-
static void ctk_display_device_dfp_setup(CtkDisplayDeviceDfp
*ctk_display_device_dfp);
@@ -90,7 +75,6 @@ static void info_update_received(GtkObject *object, gpointer arg1,
#define FRAME_PADDING 5
#define __SCALING (1<<0)
-#define __DITHERING (1<<1)
#define GET_SCALING_TARGET(V) ((V) >> 16)
@@ -106,11 +90,6 @@ static const char *__scaling_help =
"when GPU scaling is active (This occurs when the frontend and "
"backend resolutions of the current mode are different.)";
-static const char *__dithering_help =
-"Some GeForce2 GPUs required dithering to "
-"properly display on a flat panel; this option allows "
-"you to control the dithering behavior.";
-
static const char *__info_help =
"This section describes basic informations about the "
"DVI connection to the digital flat panel.";
@@ -129,6 +108,10 @@ static const char * __best_fit_res_help =
static const char * __frontend_res_help =
"The Frontend Resolution is the current resolution of the image in pixels.";
+static const char * __refresh_rate_help =
+"The refresh rate displays the rate at which the screen is currently "
+"refreshing the image.";
+
static const char * __backend_res_help =
"The Backend Resolution is the resolution that the GPU is driving to "
"the DFP. If the Backend Resolution is different than the Frontend "
@@ -252,7 +235,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
"The Reset Hardware Defaults button restores "
"the DFP settings to their default values.");
- /* create the hbox to store dfp info, scaling and dithering */
+ /* create the hbox to store dfp info, scaling */
hbox = gtk_hbox_new(FALSE, FRAME_PADDING);
gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, FRAME_PADDING);
@@ -279,6 +262,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
ctk_display_device_dfp->txt_best_fit_resolution = gtk_label_new("");
ctk_display_device_dfp->txt_frontend_resolution = gtk_label_new("");
ctk_display_device_dfp->txt_backend_resolution = gtk_label_new("");
+ ctk_display_device_dfp->txt_refresh_rate = gtk_label_new("");
/* Add information widget lines */
{
@@ -302,7 +286,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
{
gtk_label_new("Signal:"),
ctk_display_device_dfp->txt_signal,
- NULL,
+ NULL
},
{
gtk_label_new("Native Resolution:"),
@@ -324,6 +308,11 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
ctk_display_device_dfp->txt_backend_resolution,
__backend_res_help,
},
+ {
+ gtk_label_new("Refresh Rate:"),
+ ctk_display_device_dfp->txt_refresh_rate,
+ __refresh_rate_help,
+ },
{ NULL, NULL, NULL }
};
int i;
@@ -348,7 +337,7 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
GtkWidget *tmphbox;
/* Add separators */
- if (i == 3 || i == 5) {
+ if (i == 3 || i == 5 || i == 7) {
GtkWidget *separator = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(tmpbox), separator,
FALSE, FALSE, 0);
@@ -437,37 +426,6 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
G_CALLBACK(dfp_update_received),
(gpointer) ctk_display_device_dfp);
- /* Flat Panel Dithering */
-
- frame = gtk_frame_new("Flat Panel Dithering");
- eventbox = gtk_event_box_new();
- gtk_container_add(GTK_CONTAINER(eventbox), frame);
- gtk_box_pack_start(GTK_BOX(hbox), eventbox, TRUE, TRUE, 0);
- ctk_display_device_dfp->dithering_frame = frame;
-
- ctk_config_set_tooltip(ctk_config, eventbox, __dithering_help);
-
- vbox = gtk_vbox_new(FALSE, FRAME_PADDING);
- gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING);
- gtk_container_add(GTK_CONTAINER(frame), vbox);
-
- radio0 = make_dithering_radio_button
- (ctk_display_device_dfp, vbox, NULL, "Default",
- NV_CTRL_FLATPANEL_DITHERING_DEFAULT);
-
- radio1 = make_dithering_radio_button
- (ctk_display_device_dfp, vbox, radio0, "Enabled",
- NV_CTRL_FLATPANEL_DITHERING_ENABLED);
-
- radio2 = make_dithering_radio_button
- (ctk_display_device_dfp, vbox, radio1, "Disabled",
- NV_CTRL_FLATPANEL_DITHERING_DISABLED);
-
- g_signal_connect(G_OBJECT(ctk_event),
- CTK_EVENT_NAME(NV_CTRL_FLATPANEL_DITHERING),
- G_CALLBACK(dfp_update_received),
- (gpointer) ctk_display_device_dfp);
-
/* pack the image sliders */
ctk_display_device_dfp->image_sliders =
@@ -525,6 +483,10 @@ GtkWidget* ctk_display_device_dfp_new(NvCtrlAttributeHandle *handle,
CTK_EVENT_NAME(NV_CTRL_BACKEND_RESOLUTION),
G_CALLBACK(info_update_received),
(gpointer) ctk_display_device_dfp);
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE),
+ G_CALLBACK(info_update_received),
+ (gpointer) ctk_display_device_dfp);
return GTK_WIDGET(object);
@@ -571,44 +533,6 @@ static GtkWidget *make_scaling_radio_button(CtkDisplayDeviceDfp
/*
- * make_dithering_radio_button() - create a radio button and plug it
- * into the dithering radio group.
- */
-
-static GtkWidget *make_dithering_radio_button(CtkDisplayDeviceDfp
- *ctk_display_device_dfp,
- GtkWidget *vbox,
- GtkWidget *prev_radio,
- char *label,
- gint value)
-{
- GtkWidget *radio;
-
- if (prev_radio) {
- radio = gtk_radio_button_new_with_label_from_widget
- (GTK_RADIO_BUTTON(prev_radio), label);
- } else {
- radio = gtk_radio_button_new_with_label(NULL, label);
- }
-
- gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0);
-
- g_object_set_data(G_OBJECT(radio), "dithering_value",
- GINT_TO_POINTER(value));
-
- g_signal_connect(G_OBJECT(radio), "toggled",
- G_CALLBACK(dfp_dithering_changed),
- (gpointer) ctk_display_device_dfp);
-
- ctk_display_device_dfp->dithering_buttons[value] = radio;
-
- return radio;
-
-} /* make_dithering_radio_button() */
-
-
-
-/*
* post_dfp_scaling_update() - helper function for
* dfp_scaling_changed() and dfp_update_received(); this does whatever
* work is necessary after scaling has been updated -- currently, this
@@ -713,66 +637,6 @@ static void dfp_scaling_changed(GtkWidget *widget, gpointer user_data)
/*
- * post_dfp_dithering_update() - helper function for
- * dfp_dithering_changed() and dfp_update_received(); this does
- * whatever work is necessary after dithering has been updated --
- * currently, this just means posting a statusbar message.
- */
-
-static void
-post_dfp_dithering_update(CtkDisplayDeviceDfp *ctk_display_device_dfp,
- gint value)
-{
- static const char *dithering_string_table[] = {
- "Default", /* NV_CTRL_FLATPANEL_DITHERING_DEFAULT */
- "Enabled", /* NV_CTRL_FLATPANEL_DITHERING_ENABLED */
- "Disabled" /* NV_CTRL_FLATPANEL_DITHERING_DISABLED */
- };
-
- if (value > NV_CTRL_FLATPANEL_DITHERING_DISABLED) return;
-
- ctk_config_statusbar_message(ctk_display_device_dfp->ctk_config,
- "Set Flat Panel Dithering for %s to %s.",
- ctk_display_device_dfp->name,
- dithering_string_table[value]);
-
-} /* post_dfp_dithering_update() */
-
-
-
-/*
- * dfp_dithering_changed() - callback function for changes to the
- * dithering radio button group; if the specified radio button is
- * active, send updated state to the server
- */
-
-static void dfp_dithering_changed(GtkWidget *widget, gpointer user_data)
-{
- CtkDisplayDeviceDfp *ctk_display_device_dfp =
- CTK_DISPLAY_DEVICE_DFP(user_data);
-
- gboolean enabled;
- gint value;
-
- enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-
- if (enabled) {
-
- user_data = g_object_get_data(G_OBJECT(widget), "dithering_value");
- value = GPOINTER_TO_INT(user_data);
-
- NvCtrlSetDisplayAttribute(ctk_display_device_dfp->handle,
- ctk_display_device_dfp->display_device_mask,
- NV_CTRL_FLATPANEL_DITHERING, value);
-
- post_dfp_dithering_update(ctk_display_device_dfp, value);
- }
-
-} /* dfp_dithering_changed() */
-
-
-
-/*
* reset_button_clicked() - callback when the reset button is clicked
*/
@@ -804,22 +668,6 @@ static void reset_button_clicked(GtkButton *button, gpointer user_data)
dfp_scaling_update_buttons(ctk_display_device_dfp, value);
}
- /*
- * if dithering is active, send the default dithering value to the
- * server and update the radio button group
- */
-
- if (ctk_display_device_dfp->active_attributes & __DITHERING) {
-
- value = NV_CTRL_FLATPANEL_DITHERING_DEFAULT;
-
- NvCtrlSetDisplayAttribute(ctk_display_device_dfp->handle,
- ctk_display_device_dfp->display_device_mask,
- NV_CTRL_FLATPANEL_DITHERING, value);
-
- dfp_dithering_update_radio_buttons(ctk_display_device_dfp, value);
- }
-
/* Update the reset button */
gtk_widget_set_sensitive(ctk_display_device_dfp->reset_button, FALSE);
@@ -911,54 +759,6 @@ dfp_scaling_update_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp,
/*
- * dfp_dithering_update_radio_buttons() - update the dithering radio
- * button group, making the specified dithering value active.
- */
-
-static void
-dfp_dithering_update_radio_buttons(CtkDisplayDeviceDfp *ctk_display_device_dfp,
- gint value)
-{
- GtkWidget *b, *button = NULL;
- int i;
-
- if ((value < NV_CTRL_FLATPANEL_DITHERING_DEFAULT) ||
- (value > NV_CTRL_FLATPANEL_DITHERING_DISABLED)) return;
-
- button = ctk_display_device_dfp->dithering_buttons[value];
-
- if (!button) return;
-
- /* turn off signal handling for all the dithering buttons */
-
- for (i = 0; i < 3; i++) {
- b = ctk_display_device_dfp->dithering_buttons[i];
- if (!b) continue;
-
- g_signal_handlers_block_by_func
- (G_OBJECT(b), G_CALLBACK(dfp_dithering_changed),
- (gpointer) ctk_display_device_dfp);
- }
-
- /* set the appropriate button active */
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
-
- /* turn on signal handling for all the dithering buttons */
-
- for (i = 0; i < 3; i++) {
- b = ctk_display_device_dfp->dithering_buttons[i];
- if (!b) continue;
-
- g_signal_handlers_unblock_by_func
- (G_OBJECT(b), G_CALLBACK(dfp_dithering_changed),
- (gpointer) ctk_display_device_dfp);
- }
-} /* dfp_dithering_update_radio_buttons() */
-
-
-
-/*
* dfp_update_received() - callback function for changed DFP
* settings; this is called when we receive an event indicating that
* another NV-CONTROL client changed any of the settings that we care
@@ -986,11 +786,6 @@ static void dfp_update_received(GtkObject *object, gpointer arg1,
post_dfp_scaling_update(ctk_display_device_dfp, event_struct->value);
break;
- case NV_CTRL_FLATPANEL_DITHERING:
- dfp_dithering_update_radio_buttons(ctk_display_device_dfp,
- event_struct->value);
- post_dfp_dithering_update(ctk_display_device_dfp, event_struct->value);
- break;
default:
break;
}
@@ -1046,6 +841,9 @@ GtkTextBuffer *ctk_display_device_dfp_create_help(GtkTextTagTable *table,
ctk_help_term(b, &i, "Backend Resolution");
ctk_help_para(b, &i, __backend_res_help);
+
+ ctk_help_term(b, &i, "Refresh Rate");
+ ctk_help_para(b, &i, __refresh_rate_help);
ctk_help_heading(b, &i, "Flat Panel Scaling");
ctk_help_para(b, &i, __scaling_help);
@@ -1069,18 +867,6 @@ GtkTextBuffer *ctk_display_device_dfp_create_help(GtkTextTagTable *table,
ctk_help_para(b, &i, "The image will be scaled (retaining the original "
"aspect ratio) to expand and fit as much of the entire "
"flat panel as possible.");
-
- ctk_help_heading(b, &i, "Flat Panel Dithering");
- ctk_help_para(b, &i, __dithering_help);
-
- ctk_help_term(b, &i, "Default");
- ctk_help_para(b, &i, "The driver will choose when to dither.");
-
- ctk_help_term(b, &i, "Enabled");
- ctk_help_para(b, &i, "Force dithering on.");
-
- ctk_help_term(b, &i, "Disabled");
- ctk_help_para(b, &i, "Force dithering off.");
add_image_sliders_help
(CTK_IMAGE_SLIDERS(ctk_display_device_dfp->image_sliders), b, &i);
@@ -1228,6 +1014,25 @@ static void dfp_info_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp)
(GTK_LABEL(ctk_display_device_dfp->txt_backend_resolution),
"Unknown");
}
+ /* Refresh Rate */
+
+ ret =
+ NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle,
+ ctk_display_device_dfp->display_device_mask,
+ NV_CTRL_REFRESH_RATE, &val);
+ if (ret == NvCtrlSuccess) {
+ char str[32];
+ float fvalue = ((float)(val)) / 100.0f;
+ snprintf(str, 32, "%.2f Hz", fvalue);
+ gtk_label_set_text
+ (GTK_LABEL(ctk_display_device_dfp->txt_refresh_rate),
+ str);
+ } else {
+ gtk_label_set_text
+ (GTK_LABEL(ctk_display_device_dfp->txt_refresh_rate),
+ "Unknown");
+
+ }
/* GPU/DFP Scaling */
@@ -1295,38 +1100,6 @@ static void dfp_scaling_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp)
/*
- * dfp_dithering_setup() - Update GUI to reflect X server settings
- * of DFP Dithering.
- */
-static void dfp_dithering_setup(CtkDisplayDeviceDfp *ctk_display_device_dfp)
-{
- ReturnStatus ret;
- int val;
-
- ret =
- NvCtrlGetDisplayAttribute(ctk_display_device_dfp->handle,
- ctk_display_device_dfp->display_device_mask,
- NV_CTRL_FLATPANEL_DITHERING, &val);
- if (ret != NvCtrlSuccess) {
- gtk_widget_set_sensitive(ctk_display_device_dfp->dithering_frame,
- FALSE);
- gtk_widget_hide(ctk_display_device_dfp->dithering_frame);
- ctk_display_device_dfp->active_attributes &= ~__DITHERING;
- return;
- }
-
- gtk_widget_show(ctk_display_device_dfp->dithering_frame);
- ctk_display_device_dfp->active_attributes |= __DITHERING;
-
- gtk_widget_set_sensitive(ctk_display_device_dfp->dithering_frame, TRUE);
-
- dfp_dithering_update_radio_buttons(ctk_display_device_dfp, val);
-
-} /* dfp_dithering_setup() */
-
-
-
-/*
* Updates the display device page to reflect the current
* configuration of the display device.
*/
@@ -1354,8 +1127,6 @@ static void ctk_display_device_dfp_setup(CtkDisplayDeviceDfp
dfp_scaling_setup(ctk_display_device_dfp);
- dfp_dithering_setup(ctk_display_device_dfp);
-
/* Update the image sliders */
diff --git a/src/gtk+-2.x/ctkdisplaydevice-dfp.h b/src/gtk+-2.x/ctkdisplaydevice-dfp.h
index 98b7edf..03b2051 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-dfp.h
+++ b/src/gtk+-2.x/ctkdisplaydevice-dfp.h
@@ -74,13 +74,12 @@ struct _CtkDisplayDeviceDfp
GtkWidget *txt_best_fit_resolution;
GtkWidget *txt_backend_resolution;
+ GtkWidget *txt_refresh_rate;
GtkWidget *txt_scaling;
GtkWidget *scaling_frame;
GtkWidget *scaling_gpu_button;
GtkWidget *scaling_method_buttons[NV_CTRL_GPU_SCALING_METHOD_ASPECT_SCALED];
- GtkWidget *dithering_frame;
- GtkWidget *dithering_buttons[NV_CTRL_FLATPANEL_DITHERING_DISABLED+1];
unsigned int display_device_mask;
gboolean display_enabled;
diff --git a/src/gtk+-2.x/ctkdisplaydevice-tv.c b/src/gtk+-2.x/ctkdisplaydevice-tv.c
index 30d22b7..1fae539 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-tv.c
+++ b/src/gtk+-2.x/ctkdisplaydevice-tv.c
@@ -38,7 +38,7 @@
#include "ctkconfig.h"
#include "ctkhelp.h"
#include "ctkscale.h"
-
+#include <stdio.h>
#define FRAME_PADDING 5
@@ -60,6 +60,11 @@ static const char* __tv_contrast_help = "The TV Brightness slider adjusts "
static const char* __tv_saturation_help = "The TV Brightness slider adjusts "
"the saturation of the TV image.";
+static const char* __tv_refresh_rate_help = "The refresh rate displays the "
+"rate at which the screen is currently refreshing the image.";
+
+static const char* __tv_encoder_name_help = "The TV Encoder name displays "
+"the name of TV Encoder.";
/* local prototypes */
@@ -80,8 +85,12 @@ static void value_received(GtkObject *object, gpointer arg1,
static void ctk_display_device_tv_setup(CtkDisplayDeviceTv
*ctk_display_device_tv);
+static void tv_info_setup(CtkDisplayDeviceTv *ctk_display_device_tv);
+
static void enabled_displays_received(GtkObject *object, gpointer arg1,
gpointer user_data);
+static void info_update_received(GtkObject *object, gpointer arg1,
+ gpointer user_data);
GType ctk_display_device_tv_get_type(void)
@@ -140,8 +149,9 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle,
CtkDisplayDeviceTv *ctk_display_device_tv;
GtkWidget *banner;
GtkWidget *frame;
+ GtkWidget *eventbox;
+ GtkWidget *tmpbox;
GtkWidget *hbox;
- GtkWidget *label;
GtkWidget *alignment;
@@ -171,13 +181,89 @@ GtkWidget* ctk_display_device_tv_new(NvCtrlAttributeHandle *handle,
gtk_container_set_border_width(GTK_CONTAINER(hbox), FRAME_PADDING);
gtk_container_add(GTK_CONTAINER(frame), hbox);
- label = gtk_label_new("TV Encoder: ");
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
- label = gtk_label_new("");
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
- ctk_display_device_tv->txt_encoder_name = label;
+ tmpbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(hbox), tmpbox);
+
+ ctk_display_device_tv->txt_encoder_name = gtk_label_new("");
+ ctk_display_device_tv->txt_refresh_rate = gtk_label_new("");
+
+ /* pack the Refresh Rate Label */
+ {
+ typedef struct {
+ GtkWidget *label;
+ GtkWidget *txt;
+ const gchar *tooltip;
+ } TextLineInfo;
+
+ TextLineInfo lines[] = {
+ {
+ gtk_label_new("TV Encoder:"),
+ ctk_display_device_tv->txt_encoder_name,
+ __tv_encoder_name_help,
+ },
+ {
+ gtk_label_new("TV Refresh Rate:"),
+ ctk_display_device_tv->txt_refresh_rate,
+ __tv_refresh_rate_help,
+ },
+ { NULL, NULL, NULL }
+ };
+
+ int i;
+ GtkRequisition req;
+ int max_width;
+
+ /* Compute max width of lables and setup text alignments */
+ max_width = 0;
+ for (i = 0; lines[i].label; i++) {
+ gtk_misc_set_alignment(GTK_MISC(lines[i].label), 0.0f, 0.5f);
+ gtk_misc_set_alignment(GTK_MISC(lines[i].txt), 0.0f, 0.5f);
+ gtk_widget_size_request(lines[i].label, &req);
+
+ if (max_width < req.width) {
+ max_width = req.width;
+ }
+ }
+
+ /* Pack labels */
+ for (i = 0; lines[i].label; i++) {
+ GtkWidget *tmphbox;
+ /* Add separators */
+
+ if (i == 1) {
+ GtkWidget *separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(tmpbox), separator,
+ FALSE, FALSE, 0);
+ }
+ /* Set the label's width */
+ gtk_widget_set_size_request(lines[i].label, max_width, -1);
+ /* add the widgets for this line */
+ tmphbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(tmphbox), lines[i].label,
+ FALSE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(tmphbox), lines[i].txt,
+ FALSE, TRUE, 5);
+
+ /* Include tooltips */
+ if (!lines[i].tooltip) {
+ gtk_box_pack_start(GTK_BOX(tmpbox), tmphbox, FALSE, FALSE, 0);
+ } else {
+ eventbox = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(eventbox), tmphbox);
+ ctk_config_set_tooltip(ctk_config, eventbox, lines[i].tooltip);
+ gtk_box_pack_start(GTK_BOX(tmpbox), eventbox, FALSE, FALSE, 0);
+ }
+ }
+ }
+
+ /* NV_CTRL_REFRESH_RATE */
+
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE),
+ G_CALLBACK(info_update_received),
+ (gpointer) ctk_display_device_tv);
+
/* NV_CTRL_TV_OVERSCAN */
@@ -629,7 +715,13 @@ GtkTextBuffer *ctk_display_device_tv_create_help(GtkTextTagTable *table,
ctk_help_heading(b, &i, "TV Saturation");
ctk_help_para(b, &i, __tv_saturation_help);
-
+
+ ctk_help_heading(b, &i, "TV Encoder name");
+ ctk_help_para(b, &i, __tv_encoder_name_help);
+
+ ctk_help_heading(b, &i, "TV Refresh rate");
+ ctk_help_para(b, &i, __tv_refresh_rate_help);
+
add_image_sliders_help
(CTK_IMAGE_SLIDERS(ctk_display_device_tv->image_sliders), b, &i);
@@ -644,7 +736,6 @@ GtkTextBuffer *ctk_display_device_tv_create_help(GtkTextTagTable *table,
} /* ctk_display_device_tv_create_help() */
-
/* Update GUI state of the scale to reflect current settings
* on the X Driver.
*/
@@ -708,7 +799,6 @@ static void ctk_display_device_tv_setup(CtkDisplayDeviceTv
*ctk_display_device_tv)
{
ReturnStatus ret;
- char *str;
unsigned int enabled_displays;
@@ -723,24 +813,9 @@ static void ctk_display_device_tv_setup(CtkDisplayDeviceTv
(enabled_displays & (ctk_display_device_tv->display_device_mask)));
- /* Information Frame */
-
- /* NV_CTRL_STRING_TV_ENCODER_NAME */
-
- ret = NvCtrlGetStringDisplayAttribute
- (ctk_display_device_tv->handle,
- ctk_display_device_tv->display_device_mask,
- NV_CTRL_STRING_TV_ENCODER_NAME,
- &str);
- if (ret == NvCtrlSuccess) {
- gtk_label_set_text(GTK_LABEL(ctk_display_device_tv->txt_encoder_name),
- str);
- gtk_widget_show(ctk_display_device_tv->info_frame);
- XFree(str);
- } else {
- gtk_widget_hide(ctk_display_device_tv->info_frame);
- }
+ /* Update Information Frame */
+ tv_info_setup(ctk_display_device_tv);
/* Update sliders */
@@ -783,16 +858,15 @@ static void ctk_display_device_tv_setup(CtkDisplayDeviceTv
/* update acquire EDID button */
if (ctk_display_device_tv->edid) {
- GList *list;
-
- list = gtk_container_get_children
+ GList *list;
+ list = gtk_container_get_children
(GTK_CONTAINER(ctk_display_device_tv->edid_box));
- if (list) {
- gtk_container_remove
+ if (list) {
+ gtk_container_remove
(GTK_CONTAINER(ctk_display_device_tv->edid_box),
(GtkWidget *)(list->data));
- g_list_free(list);
- }
+ g_list_free(list);
+ }
}
ctk_display_device_tv->edid =
@@ -815,7 +889,45 @@ static void ctk_display_device_tv_setup(CtkDisplayDeviceTv
} /* ctk_display_device_tv_setup() */
-
+static void tv_info_setup(CtkDisplayDeviceTv *ctk_display_device_tv)
+{
+ ReturnStatus ret;
+ int val;
+ char *str;
+
+ /* NV_CTRL_STRING_TV_ENCODER_NAME */
+
+ ret = NvCtrlGetStringDisplayAttribute
+ (ctk_display_device_tv->handle,
+ ctk_display_device_tv->display_device_mask,
+ NV_CTRL_STRING_TV_ENCODER_NAME,
+ &str);
+ if (ret == NvCtrlSuccess) {
+ gtk_label_set_text(GTK_LABEL(ctk_display_device_tv->txt_encoder_name),
+ str);
+ gtk_widget_show(ctk_display_device_tv->info_frame);
+ } else {
+ gtk_widget_hide(ctk_display_device_tv->info_frame);
+ }
+
+ /* NV_CTRL_REFRESH_RATE */
+
+ ret = NvCtrlGetDisplayAttribute
+ (ctk_display_device_tv->handle,
+ ctk_display_device_tv->display_device_mask,
+ NV_CTRL_REFRESH_RATE,
+ &val);
+ if (ret == NvCtrlSuccess) {
+ float fvalue = ((float)(val)) / 100.0f;
+ snprintf(str, 32, "%.2f Hz", fvalue);
+ gtk_label_set_text(GTK_LABEL(ctk_display_device_tv->txt_refresh_rate),
+ str);
+ } else {
+ gtk_label_set_text
+ (GTK_LABEL(ctk_display_device_tv->txt_refresh_rate),
+ "Unknown");
+ }
+}
/*
* When the list of enabled displays on the GPU changes,
@@ -830,3 +942,22 @@ static void enabled_displays_received(GtkObject *object, gpointer arg1,
ctk_display_device_tv_setup(ctk_object);
} /* enabled_displays_received() */
+
+/*
+ * When GPU scaling activation and/or TV resolution changes occur,
+ * we should update the GUI to reflect the current state.
+ */
+static void info_update_received(GtkObject *object, gpointer arg1,
+ gpointer user_data)
+{
+ CtkDisplayDeviceTv *ctk_object = CTK_DISPLAY_DEVICE_TV(user_data);
+ CtkEventStruct *event_struct = (CtkEventStruct *) arg1;
+
+ /* if the event is not for this display device, return */
+
+ if (!(event_struct->display_mask & ctk_object->display_device_mask)) {
+ return;
+ }
+
+ tv_info_setup(ctk_object);
+}
diff --git a/src/gtk+-2.x/ctkdisplaydevice-tv.h b/src/gtk+-2.x/ctkdisplaydevice-tv.h
index d4597a8..319ab8c 100644
--- a/src/gtk+-2.x/ctkdisplaydevice-tv.h
+++ b/src/gtk+-2.x/ctkdisplaydevice-tv.h
@@ -75,7 +75,8 @@ struct _CtkDisplayDeviceTv
GtkWidget *hue;
GtkWidget *contrast;
GtkWidget *saturation;
-
+ GtkWidget *txt_refresh_rate;
+
GtkWidget *image_sliders;
GtkWidget *edid_box;
diff --git a/src/gtk+-2.x/ctkdisplaylayout.c b/src/gtk+-2.x/ctkdisplaylayout.c
index bbbd562..bb53122 100644
--- a/src/gtk+-2.x/ctkdisplaylayout.c
+++ b/src/gtk+-2.x/ctkdisplaylayout.c
@@ -3161,14 +3161,13 @@ void ctk_display_layout_set_display_position(CtkDisplayLayout *ctk_object,
clear_layout(ctk_object);
- /* XXX When transitioning from absolute to relative, make sure
+ /* XXX When configuring a relative position, make sure
* all displays that are relative to us become absolute.
* This is to avoid relationship loops. Eventually, we'll want
* to be able to handle weird loops since X does this.
*/
- if (display->cur_mode->position_type == CONF_ADJ_ABSOLUTE &&
- position_type != CONF_ADJ_ABSOLUTE) {
+ if (position_type != CONF_ADJ_ABSOLUTE) {
nvDisplayPtr other;
@@ -3380,14 +3379,13 @@ void ctk_display_layout_set_screen_position(CtkDisplayLayout *ctk_object,
}
- /* XXX When transitioning from absolute to relative, make sure
+ /* XXX When configuring a relative position, make sure
* all screens that are relative to us become absolute.
* This is to avoid relationship loops. Eventually, we'll want
* to be able to handle weird loops since X does this.
*/
- if (screen->position_type == CONF_ADJ_ABSOLUTE &&
- position_type != CONF_ADJ_ABSOLUTE) {
+ if (position_type != CONF_ADJ_ABSOLUTE) {
nvScreenPtr other;
diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c
index 75cfee5..d7772ac 100644
--- a/src/gtk+-2.x/ctkevent.c
+++ b/src/gtk+-2.x/ctkevent.c
@@ -123,8 +123,6 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class)
/* create signals for all the NV-CONTROL attributes */
- MAKE_SIGNAL(NV_CTRL_FLATPANEL_SCALING);
- MAKE_SIGNAL(NV_CTRL_FLATPANEL_DITHERING);
MAKE_SIGNAL(NV_CTRL_DIGITAL_VIBRANCE);
MAKE_SIGNAL(NV_CTRL_BUS_TYPE);
MAKE_SIGNAL(NV_CTRL_VIDEO_RAM);
@@ -242,6 +240,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class)
MAKE_SIGNAL(NV_CTRL_GPU_SCALING_ACTIVE);
MAKE_SIGNAL(NV_CTRL_DFP_SCALING_ACTIVE);
MAKE_SIGNAL(NV_CTRL_FSAA_APPLICATION_ENHANCED);
+ MAKE_SIGNAL(NV_CTRL_FRAMELOCK_SYNC_RATE_4);
#undef MAKE_SIGNAL
@@ -252,7 +251,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class)
* knows about.
*/
-#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_FSAA_APPLICATION_ENHANCED
+#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_FRAMELOCK_SYNC_RATE_4
#warning "There are attributes that do not emit signals!"
#endif
diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c
index 5d65fab..074a86f 100644
--- a/src/gtk+-2.x/ctkframelock.c
+++ b/src/gtk+-2.x/ctkframelock.c
@@ -82,14 +82,15 @@ enum
* that entry.
*/
-#define NUM_GPU_SIGNALS 4
+#define NUM_GPU_SIGNALS 5
const char *__GPUSignals[NUM_GPU_SIGNALS] =
{
CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_MASTER),
CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SLAVES),
CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SYNC),
- CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_TEST_SIGNAL)
+ CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_TEST_SIGNAL),
+ CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE)
};
/*
@@ -119,24 +120,29 @@ typedef struct _nvFrameLockDataRec nvFrameLockDataRec, *nvFrameLockDataPtr;
struct _nvListEntryRec {
- nvListTreePtr tree;
+ nvListTreePtr tree;
+
+ GtkWidget *vbox; /* Holds all entry widgets and children */
- GtkWidget *vbox; /* Holds all entry widgets and children */
+ GtkWidget *ebox; /* Event box for this entry's stuff */
+ GtkWidget *hbox; /* Box inside ebox */
- GtkWidget *vp; /* Viewport used to set selected color */
- GtkWidget *parent_hbox; /* Holds expander button and data */
- GtkWidget *button; /* Expander button */
+ GtkWidget *title_hbox; /* This entry's title data */
+ GtkWidget *padding_hbox; /* Padding to denote nested hierarchy */
+ GtkWidget *expander_hbox;
+ GtkWidget *expander_button_image; /* Expander button widgets */
+ GtkWidget *expander_button;
+ GtkWidget *expander_vbox; /* To align the button */
gboolean expanded;
- GtkWidget *button_image;
+ GtkWidget *label_hbox;
- GtkWidget *data_hbox; /* Holds entry data (after expander button) */
+ GtkWidget *data_hbox;
- GtkWidget *child_hbox; /* Holds padding and children */
- GtkWidget *child_vbox;
+ GtkWidget *child_vbox; /* Holds child entries */
- gpointer data; /* Data (used to render entry) */
+ gpointer data; /* Data (used to render entry) */
gint data_type;
- CtkEvent *ctk_event; /* For receiving events on the entry */
+ CtkEvent *ctk_event; /* For receiving events on the entry */
nvListEntryPtr parent;
nvListEntryPtr children;
@@ -1145,7 +1151,7 @@ static void list_entry_update_framelock_controls(CtkFramelock *ctk_framelock,
*
*/
static void list_entry_update_display_controls(CtkFramelock *ctk_framelock,
- nvListEntryPtr entry)
+ nvListEntryPtr entry)
{
nvDisplayDataPtr data = (nvDisplayDataPtr)(entry->data);
gboolean framelock_enabled = ctk_framelock->framelock_enabled;
@@ -1196,16 +1202,22 @@ static void list_entry_update_display_controls(CtkFramelock *ctk_framelock,
*/
sensitive = (!server_data || data->rate == server_data->rate);
gtk_widget_set_sensitive(data->rate_label, sensitive);
- gtk_widget_set_sensitive(data->rate_text, sensitive);
+ gtk_widget_set_sensitive(data->rate_text, sensitive);
+ gtk_widget_set_sensitive(data->label, sensitive);
+
+ ctk_config_set_tooltip(entry->tree->ctk_framelock->ctk_config, entry->ebox,
+ sensitive ? NULL : "This display device cannot be "
+ "included in the frame lock group since it has a "
+ "different refresh rate than that of the server.");
- /* Remove display device from clients list */
+ /* Remove display device from the GPU's 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;
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(data->client_checkbox),
+ FALSE);
+ ((nvGPUDataPtr)(entry->parent->data))->clients_mask &=
+ data->device_mask;
}
}
@@ -1240,6 +1252,34 @@ static void list_entry_update_controls(CtkFramelock *ctk_framelock,
+/** any_gpu_has_selection() ******************************************
+ *
+ * Returns TRUE if any of the gpus have a server/client selected
+ *
+ */
+static gboolean any_gpu_has_selection(nvListEntryPtr entry)
+{
+ if (!entry) return FALSE;
+
+ if (entry->data_type == ENTRY_DATA_GPU &&
+ (((nvGPUDataPtr)(entry->data))->server_mask ||
+ ((nvGPUDataPtr)(entry->data))->clients_mask)) {
+ return TRUE;
+ }
+
+ if (any_gpu_has_selection(entry->children)) {
+ return TRUE;
+ }
+
+ if (any_gpu_has_selection(entry->next_sibling)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
/** update_framelock_controls() **************************************
*
* Enable/disable access to various GUI controls on the frame lock
@@ -1252,6 +1292,7 @@ static void update_framelock_controls(CtkFramelock *ctk_framelock)
{
nvListTreePtr tree;
gboolean enabled;
+ gboolean something_selected;
tree = (nvListTreePtr)(ctk_framelock->tree);
@@ -1269,8 +1310,11 @@ static void update_framelock_controls(CtkFramelock *ctk_framelock)
G_CALLBACK(toggle_sync_enable),
(gpointer) ctk_framelock);
+ something_selected =
+ any_gpu_has_selection(((nvListTreePtr)ctk_framelock->tree)->entries);
+
gtk_widget_set_sensitive(ctk_framelock->sync_state_button,
- tree->nentries);
+ tree->nentries && something_selected);
gtk_container_remove
(GTK_CONTAINER(ctk_framelock->sync_state_button),
@@ -1458,6 +1502,7 @@ static void list_entry_set_select(nvListEntryPtr entry, gint selected)
/* Do the selection */
+
if (selected) {
state = GTK_STATE_SELECTED;
if (entry->tree->selected_entry) {
@@ -1471,9 +1516,10 @@ static void list_entry_set_select(nvListEntryPtr entry, gint selected)
entry->tree->selected_entry = NULL;
}
+
/* Update the state of the entry's widgets */
-
- SELECT_WIDGET(entry->vp, state);
+
+ SELECT_WIDGET(entry->ebox, state);
if (!entry->data) {
return;
@@ -1531,29 +1577,31 @@ static void expander_button_clicked(GtkWidget *widget, gpointer user_data)
if (entry->expanded) {
/* Collapse */
- gtk_container_remove(GTK_CONTAINER(entry->button),
- entry->button_image);
- entry->button_image =
+ gtk_container_remove(GTK_CONTAINER(entry->expander_button),
+ entry->expander_button_image);
+ entry->expander_button_image =
gtk_image_new_from_stock(GTK_STOCK_ADD,
GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_widget_set_size_request(entry->button, 20, 20);
+ gtk_widget_set_size_request(entry->expander_button, 20, 20);
- gtk_container_add(GTK_CONTAINER(entry->button), entry->button_image);
- gtk_widget_show_all(entry->button);
- gtk_widget_hide(entry->child_hbox);
+ gtk_container_add(GTK_CONTAINER(entry->expander_button),
+ entry->expander_button_image);
+ gtk_widget_show_all(entry->expander_button);
+ gtk_widget_hide(entry->child_vbox);
} else {
/* Expand */
- gtk_container_remove(GTK_CONTAINER(entry->button),
- entry->button_image);
- entry->button_image =
+ gtk_container_remove(GTK_CONTAINER(entry->expander_button),
+ entry->expander_button_image);
+ entry->expander_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_widget_set_size_request(entry->expander_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);
+ gtk_container_add(GTK_CONTAINER(entry->expander_button),
+ entry->expander_button_image);
+ gtk_widget_show_all(entry->expander_button);
+ gtk_widget_show(entry->child_vbox);
}
entry->expanded = !(entry->expanded);
@@ -1570,23 +1618,27 @@ static void expander_button_clicked(GtkWidget *widget, gpointer user_data)
*/
static void list_entry_add_expander_button(nvListEntryPtr entry)
{
- if (!entry || entry->button) {
+ if (!entry || entry->expander_button) {
return;
}
-
- entry->button = gtk_button_new();
- entry->button_image =
+
+ entry->expander_vbox = gtk_vbox_new(FALSE, 0);
+ entry->expander_button = gtk_button_new();
+ entry->expander_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_widget_set_size_request(entry->expander_button, 20, 20);
entry->expanded = True;
- g_signal_connect(G_OBJECT(entry->button), "clicked",
+ g_signal_connect(G_OBJECT(entry->expander_button), "clicked",
G_CALLBACK(expander_button_clicked),
(gpointer) entry);
-
- gtk_container_add(GTK_CONTAINER(entry->button), entry->button_image);
- gtk_box_pack_start(GTK_BOX(entry->parent_hbox), entry->button,
+
+ gtk_container_add(GTK_CONTAINER(entry->expander_button),
+ entry->expander_button_image);
+ gtk_box_pack_start(GTK_BOX(entry->expander_vbox), entry->expander_button,
+ TRUE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(entry->expander_hbox), entry->expander_vbox,
FALSE, FALSE, 0);
}
@@ -1603,12 +1655,13 @@ static void list_entry_add_expander_button(nvListEntryPtr entry)
*/
static void list_entry_remove_expander_button(nvListEntryPtr entry)
{
- if (!entry || !entry->button) {
+ if (!entry || !entry->expander_button) {
return;
}
- gtk_container_remove(GTK_CONTAINER(entry->parent_hbox), entry->button);
- entry->button = NULL;
+ gtk_container_remove(GTK_CONTAINER(entry->expander_hbox),
+ entry->expander_vbox);
+ entry->expander_button = NULL;
}
@@ -1628,27 +1681,37 @@ static nvListEntryPtr list_entry_new(void)
return NULL;
}
- /* Create the box that holds everything */
+ /* Create the vertical box that holds this entry and its children */
entry->vbox = gtk_vbox_new(FALSE, 0);
- /* Create the top row that holds the entry data */
+ /* Create the (top) row that holds this entry's data */
+ entry->ebox = gtk_event_box_new();
+ entry->hbox = gtk_hbox_new(FALSE, 15);
+ entry->title_hbox = gtk_hbox_new(FALSE, 0);
+ entry->padding_hbox = gtk_hbox_new(FALSE, 0);
+ entry->expander_hbox = gtk_hbox_new(FALSE, 0);
+ entry->label_hbox = gtk_hbox_new(FALSE, 0);
+ entry->data_hbox = gtk_hbox_new(FALSE, 0);
- entry->parent_hbox = gtk_hbox_new(FALSE, 0);
- entry->data_hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(entry->title_hbox), entry->padding_hbox,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(entry->title_hbox), entry->expander_hbox,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(entry->title_hbox), entry->label_hbox,
+ FALSE, 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_box_pack_start(GTK_BOX(entry->hbox), entry->title_hbox,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(entry->hbox), entry->data_hbox,
+ FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(entry->ebox), GTK_WIDGET(entry->hbox));
+ gtk_box_pack_start(GTK_BOX(entry->vbox), entry->ebox, TRUE, TRUE, 0);
- gtk_widget_set_events(entry->vp, GDK_BUTTON_PRESS_MASK);
- g_signal_connect(G_OBJECT(entry->vp), "button_press_event",
+ SELECT_WIDGET(entry->ebox, GTK_STATE_NORMAL);
+ gtk_widget_set_events(entry->ebox, GDK_BUTTON_PRESS_MASK);
+ g_signal_connect(G_OBJECT(entry->ebox), "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);
+ (gpointer)entry);
return entry;
}
@@ -1671,9 +1734,9 @@ static void list_entry_free(nvListEntryPtr entry)
/* XXX DON"T Need these?
gtk_widget_destroy(entry->vbox);
- gtk_widget_destroy(entry->parent_hbox);
+ gtk_widget_destroy(entry->title_hbox);
gtk_widget_destroy(entry->data_hbox);
- gtk_widget_destroy(entry->vp);
+ gtk_widget_destroy(entry->ebox);
*/
/* Remove signal callbacks */
@@ -1747,30 +1810,18 @@ static void list_entry_add_child(nvListEntryPtr parent, nvListEntryPtr child)
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);
+ parent->child_vbox = gtk_vbox_new(FALSE, 0);
+
gtk_box_pack_start(GTK_BOX(parent->vbox),
- parent->child_hbox, FALSE, FALSE, 0);
- gtk_widget_show(parent->child_hbox);
+ parent->child_vbox, FALSE, FALSE, 0);
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);
+ gtk_widget_show(parent->expander_button);
}
/* Pack the child into the parent's child box */
@@ -1879,8 +1930,7 @@ static void list_entry_unparent(nvListEntryPtr child)
parent->nchildren--;
if (parent->nchildren == 0) {
- gtk_container_remove(GTK_CONTAINER(parent->vbox), parent->child_hbox);
- parent->child_hbox = NULL;
+ gtk_container_remove(GTK_CONTAINER(parent->vbox), parent->child_vbox);
parent->child_vbox = NULL;
list_entry_remove_expander_button(parent);
}
@@ -1918,12 +1968,15 @@ static void list_entry_remove_children(nvListEntryPtr entry)
*/
static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data)
{
- nvListEntryPtr entry = list_entry_new();
+ nvListEntryPtr entry;
+
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *vseparator;
GtkWidget *padding;
+
+ entry = list_entry_new();
if (!entry) {
return NULL;
}
@@ -1932,21 +1985,20 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data)
/* Pack the data's widgets into the list entry data hbox */
- gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label,
+ gtk_box_pack_start(GTK_BOX(entry->label_hbox), data->label,
FALSE, FALSE, 5);
+ frame = gtk_frame_new(NULL);
hbox = gtk_hbox_new(FALSE, 5);
padding = gtk_hbox_new(FALSE, 0);
+
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
- 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_container_set_border_width(GTK_CONTAINER(hbox), 2);
gtk_container_add(GTK_CONTAINER(frame), hbox);
- 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);
+ gtk_box_pack_start(GTK_BOX(hbox), data->receiving_label, FALSE, FALSE, 0);
vseparator = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0);
@@ -1957,20 +2009,20 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data)
vseparator = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0);
- 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);
+ gtk_box_pack_start(GTK_BOX(hbox), data->house_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->port0_label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), data->port0_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), data->port0_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->port1_label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), data->port1_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), data->port1_label, FALSE, FALSE, 0);
/* Extra Info Section */
@@ -1994,6 +2046,8 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data)
gtk_box_pack_start(GTK_BOX(data->extra_info_hbox), data->revision_text,
FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(hbox), padding, FALSE, FALSE, 0);
+
return entry;
}
@@ -2006,8 +2060,14 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data)
*/
static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data)
{
- nvListEntryPtr entry = list_entry_new();
+ nvListEntryPtr entry;
+
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *padding;
+
+ entry = list_entry_new();
if (!entry) {
return NULL;
}
@@ -2016,23 +2076,22 @@ static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data)
/* Pack the data's widgets into the list entry data hbox */
- gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label,
+ gtk_box_pack_start(GTK_BOX(entry->label_hbox), data->label,
FALSE, FALSE, 5);
- {
- GtkWidget *frame;
- GtkWidget *hbox;
-
- hbox = gtk_hbox_new(FALSE, 5);
-
- frame = gtk_frame_new(NULL);
- gtk_box_pack_end(GTK_BOX(entry->data_hbox), frame, FALSE, FALSE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
- gtk_container_add(GTK_CONTAINER(frame), hbox);
-
- gtk_box_pack_start(GTK_BOX(hbox), data->timing_label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox), data->timing_hbox, FALSE, FALSE, 0);
- }
+ frame = gtk_frame_new(NULL);
+ hbox = gtk_hbox_new(FALSE, 5);
+ padding = gtk_hbox_new(FALSE, 0);
+
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
+
+ gtk_box_pack_end(GTK_BOX(entry->data_hbox), frame, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+
+ gtk_box_pack_start(GTK_BOX(hbox), data->timing_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), data->timing_label, FALSE, FALSE, 0);
+
+ gtk_box_pack_end(GTK_BOX(hbox), padding, FALSE, FALSE, 0);
return entry;
}
@@ -2046,8 +2105,15 @@ static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data)
*/
static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data)
{
- nvListEntryPtr entry = list_entry_new();
+ nvListEntryPtr entry;
+
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *vseparator;
+ GtkWidget *padding;
+
+ entry = list_entry_new();
if (!entry) {
return NULL;
}
@@ -2056,44 +2122,40 @@ static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data)
/* Pack the data's widgets into the list entry data hbox */
- gtk_box_pack_start(GTK_BOX(entry->data_hbox), data->label,
+ gtk_box_pack_start(GTK_BOX(entry->label_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);
+ frame = gtk_frame_new(NULL);
+ hbox = gtk_hbox_new(FALSE, 5);
+ padding = gtk_hbox_new(FALSE, 0);
- vseparator = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), vseparator, FALSE, FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
- 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);
- }
+ gtk_box_pack_end(GTK_BOX(entry->data_hbox), frame, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+
+ gtk_box_pack_start(GTK_BOX(hbox), data->stereo_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), data->stereo_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->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);
+
+ gtk_box_pack_end(GTK_BOX(hbox), padding, FALSE, FALSE, 0);
return entry;
}
@@ -2230,6 +2292,76 @@ static void list_tree_remove_entry(nvListTreePtr tree, nvListEntryPtr entry)
+/** list_entry_setup_title() *****************************************
+ *
+ * Returns the max width
+ *
+ */
+static int list_entry_setup_title(nvListEntryPtr entry, int depth)
+{
+ int max_width;
+ int width;
+ GtkRequisition req;
+
+ if (!entry) return FALSE;
+
+ /* Setup this entry's padding */
+ gtk_widget_set_size_request(entry->padding_hbox, depth * 25, -1);
+
+ /* Calculate this entry's width */
+ gtk_widget_size_request(entry->title_hbox, &req);
+ max_width = req.width;
+
+ width = list_entry_setup_title(entry->children, depth +1);
+ max_width = (width > max_width) ? width : max_width;
+
+ width = list_entry_setup_title(entry->next_sibling, depth);
+ max_width = (width > max_width) ? width : max_width;
+
+ return max_width;
+}
+
+
+
+/** list_entry_set_title() *******************************************
+ *
+ * Sets the width of the titles
+ *
+ */
+static void list_entry_set_title(nvListEntryPtr entry, int width)
+{
+ if (!entry) return;
+
+ /* Set this entry's title width */
+ gtk_widget_set_size_request(entry->title_hbox, width, -1);
+
+ list_entry_set_title(entry->children, width);
+ list_entry_set_title(entry->next_sibling, width);
+}
+
+
+
+/** list_tree_align_titles() *****************************************
+ *
+ * - Aligns the titles and sets up the padding of all the tree's
+ * entries.
+ *
+ */
+static void list_tree_align_titles(nvListTreePtr tree)
+{
+ int max_width;
+
+ /* Setup the left padding and calculate the max width
+ * of the tree entries
+ */
+ max_width = list_entry_setup_title(tree->entries, 0);
+
+ /* Make sure all entry titles are the same width */
+ list_entry_set_title(tree->entries, max_width);
+}
+
+
+
/** find_server_by_name() ********************************************
*
* - Looks in the list tree for a list entry with a handle to a
@@ -2385,8 +2517,8 @@ static void toggle_use_house_sync(GtkWidget *widget, gpointer user_data)
NvCtrlGetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, &enabled);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- "%s use of House Sync Signal.",
- enabled?"Enabled":"Disabled");
+ "%s use of house sync signal.",
+ (enabled ? "Enabled" : "Disabled"));
}
@@ -2411,8 +2543,8 @@ static void toggle_extra_info(GtkWidget *widget, gpointer data)
update_framelock_status(ctk_framelock);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- " extra information.",
- enabled?"Showing":"Hiding");
+ "%s extra information.",
+ (enabled ? "Showing" : "Hiding"));
}
@@ -2440,16 +2572,23 @@ static void toggle_server(GtkWidget *widget, gpointer data)
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 X server state, making sure FrameLock sync is disabled */
+ NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC,
+ NV_CTRL_FRAMELOCK_SYNC_DISABLE);
- /* Update server state */
NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_MASTER,
gpu_data->server_mask);
+ gpu_data->enabled = FALSE;
+ entry->tree->ctk_framelock->framelock_enabled =
+ any_gpu_enabled(entry->tree->entries);
+
+ /* Update GUI state */
+ update_framelock_controls(entry->tree->ctk_framelock);
+
ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config,
- " frame lock server device.",
- server_checked?"Selected":"Unselected");
+ "%s frame lock server device.",
+ (server_checked ? "Selected" : "Unselected"));
}
@@ -2480,16 +2619,23 @@ static void toggle_client(GtkWidget *widget, gpointer data)
gpu_data->clients_mask &= ~(display_data->device_mask);
}
- /* Update GUI state */
- update_framelock_controls(entry->tree->ctk_framelock);
+ /* Update X server state, make sure FrameLock Sync is disabled */
+ NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC,
+ NV_CTRL_FRAMELOCK_SYNC_DISABLE);
- /* Update server state */
NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SLAVES,
gpu_data->clients_mask);
+ gpu_data->enabled = FALSE;
+ entry->tree->ctk_framelock->framelock_enabled =
+ any_gpu_enabled(entry->tree->entries);
+
+ /* Update GUI state */
+ update_framelock_controls(entry->tree->ctk_framelock);
+
ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config,
- " frame lock client device.",
- client_checked?"Selected":"Unselected");
+ "%s frame lock client device.",
+ (client_checked ? "Selected" : "Unselected"));
}
@@ -2752,8 +2898,8 @@ static void toggle_sync_enable(GtkWidget *button, gpointer data)
update_framelock_status(ctk_framelock);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- "Frame lock %s.",
- enabled ? "enabled" : "disabled");
+ "Frame Lock %s.",
+ (enabled ? "enabled" : "disabled"));
}
@@ -2808,7 +2954,7 @@ static gint test_link_done(gpointer data)
(gpointer) ctk_framelock);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- "Test Link complete.");
+ "Test link complete.");
return FALSE;
}
@@ -2865,7 +3011,7 @@ static void toggle_test_link(GtkWidget *button, gpointer data)
NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- "Test Link started.");
+ "Test link started.");
/* register the "done" function */
@@ -3016,10 +3162,10 @@ static gboolean detect_video_mode_timer(gpointer user_data)
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]);
+ ctk_config_statusbar_message
+ (ctk_framelock->ctk_config,
+ "House sync format detected as %s.",
+ houseFormatStrings[ctk_framelock->current_detect_format]);
goto done;
}
@@ -3157,9 +3303,9 @@ void list_entry_update_framelock_status(CtkFramelock *ctk_framelock,
gboolean use_house_sync;
gboolean framelock_enabled;
gboolean is_server;
+ ReturnStatus ret;
- 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);
@@ -3189,8 +3335,15 @@ void list_entry_update_framelock_status(CtkFramelock *ctk_framelock,
/* 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
+
+ ret =
+ NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_RATE_4, &rate);
+ if (ret == NvCtrlSuccess) {
+ snprintf(str, 32, "%d.%.4d Hz", (rate / 10000), (rate % 10000));
+ } else {
+ NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &rate);
+ snprintf(str, 32, "%d.%.3d Hz", (rate / 1000), (rate % 1000));
+ }
gtk_label_set_text(GTK_LABEL(data->rate_text), str);
/* Sync Delay (Skew) */
@@ -3419,7 +3572,7 @@ static gboolean check_for_ethernet(gpointer user_data)
if (error_data) {
if (first_error) {
error_msg(ctk_framelock, "<span weight=\"bold\" "
- "size=\"larger\">Frame lock RJ45 error</span>\n\n"
+ "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 "
@@ -3590,6 +3743,13 @@ static void gpu_state_received(GtkObject *object,
* X Server we are unsetting it.
*/
if (display_entry->parent != gpu_entry) {
+ nvGPUDataPtr gpu_data =
+ (nvGPUDataPtr)(display_entry->parent->data);
+
+ NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC,
+ NV_CTRL_FRAMELOCK_SYNC_DISABLE);
+ gpu_data->enabled = FALSE;
+
NvCtrlSetAttribute(display_data->handle,
NV_CTRL_FRAMELOCK_MASTER, 0);
}
@@ -3602,7 +3762,7 @@ static void gpu_state_received(GtkObject *object,
if (display_entry) {
display_data = (nvDisplayDataPtr)(display_entry->data);
- /* Clear the server checkbox */
+ /* Set the server checkbox */
g_signal_handlers_block_by_func
(G_OBJECT(display_data->server_checkbox),
G_CALLBACK(toggle_server),
@@ -3621,6 +3781,10 @@ static void gpu_state_received(GtkObject *object,
gpu_data->server_mask = event->value;
+ /* See if anything was disabled */
+ ctk_framelock->framelock_enabled =
+ any_gpu_enabled(gpu_entry->tree->entries);
+
update_framelock_controls(gpu_entry->tree->ctk_framelock);
break;
@@ -3687,6 +3851,10 @@ static void gpu_state_received(GtkObject *object,
/* Save the client state */
gpu_data->clients_mask = event->value;
+ /* See if anything was disabled */
+ ctk_framelock->framelock_enabled =
+ any_gpu_enabled(gpu_entry->tree->entries);
+
update_framelock_controls(gpu_entry->tree->ctk_framelock);
break;
@@ -3753,9 +3921,30 @@ static void gpu_state_received(GtkObject *object,
(gpointer) ctk_framelock);
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- ctk_framelock->test_link_enabled ?
- "Test Link started." :
- "Test Link complete.");
+ (ctk_framelock->test_link_enabled ?
+ "Test link started." :
+ "Test link complete."));
+ break;
+
+
+ case NV_CTRL_REFRESH_RATE:
+ /* Update the display device's refresh rate */
+ display_entry = get_display_on_gpu(gpu_entry, event->display_mask);
+ if (display_entry && display_entry->data) {
+ float fvalue;
+ char str[32];
+
+ display_data =
+ (nvDisplayDataPtr)(display_entry->data);
+
+ display_data->rate = event->value;
+ fvalue = ((float)(display_data->rate)) / 100.0f;
+ snprintf(str, 32, "%.2f Hz", fvalue);
+ gtk_label_set_text(GTK_LABEL(display_data->rate_text), str);
+ }
+
+ /* Make sure the framelock controls are in a consistent state */
+ update_framelock_controls(ctk_framelock);
break;
@@ -4202,7 +4391,7 @@ GtkWidget* ctk_framelock_new(NvCtrlAttributeHandle *handle,
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 **/
+ /** XXX **/gtk_widget_set_size_request(sw, -1, 200);/** XXX **/
/* add the custom tree & buttons */
@@ -4427,7 +4616,7 @@ static void add_devices_response(GtkWidget *button, gint response,
/* Update status bar */
ctk_config_statusbar_message(ctk_framelock->ctk_config,
- "Added X Server '%s'", display_name);
+ "Added X server '%s'.", display_name);
}
@@ -4551,7 +4740,10 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock,
* as master, unset this entry and make it a slave. */
if (server_entry && master_mask) {
- /* XXXvm What if this GPU has Sync enabled? */
+ /* Ensure FrameLock sync is disabled before setting server/clients */
+ NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC,
+ NV_CTRL_FRAMELOCK_SYNC_DISABLE);
+ gpu_data->enabled = FALSE;
ret = NvCtrlSetAttribute(gpu_data->handle,
NV_CTRL_FRAMELOCK_MASTER, 0);
@@ -4623,7 +4815,7 @@ static unsigned int add_display_devices(CtkFramelock *ctk_framelock,
snprintf(str, 32, "%.2f Hz", fvalue);
display_data->rate_text = gtk_label_new(str);
- display_data->stereo_label = gtk_label_new("Stereo:");
+ display_data->stereo_label = gtk_label_new("Stereo");
display_data->stereo_hbox = gtk_hbox_new(FALSE, 0);
/* Create the display entry */
@@ -4762,7 +4954,7 @@ static unsigned int add_gpu_devices(CtkFramelock *ctk_framelock,
NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM);
gpu_data->label = gtk_label_new("");
- gpu_data->timing_label = gtk_label_new("Timing:");
+ gpu_data->timing_label = gtk_label_new("Timing");
gpu_data->timing_hbox = gtk_hbox_new(FALSE, 0);
/* Create the GPU list entry */
@@ -4782,11 +4974,10 @@ static unsigned int add_gpu_devices(CtkFramelock *ctk_framelock,
* 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));
- }
+ NvCtrlGetAttribute(gpu_data->handle,
+ NV_CTRL_FRAMELOCK_SYNC,
+ &(gpu_data->enabled));
+ ctk_framelock->framelock_enabled |= gpu_data->enabled;
entry->ctk_event = CTK_EVENT(ctk_event_new(gpu_data->handle));
@@ -4860,7 +5051,7 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock,
goto fail;
}
- /* Create the frame lock handle and label */
+ /* Create the frame lock handle */
framelock_data->handle =
NvCtrlAttributeInit(NvCtrlGetDisplayPtr(handle),
NV_CTRL_TARGET_TYPE_FRAMELOCK,
@@ -4868,7 +5059,6 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock,
NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM);
/* Get the framelock revision information */
-
ret = NvCtrlGetAttribute(framelock_data->handle,
NV_CTRL_FRAMELOCK_FPGA_REVISION,
&val);
@@ -4877,10 +5067,10 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock,
}
revision_str = g_strdup_printf("%d", val);
-
+ /* Create the frame lock widgets */
framelock_data->label = gtk_label_new("");
- framelock_data->receiving_label = gtk_label_new("Receiving:");
+ 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:");
@@ -4889,13 +5079,13 @@ static unsigned int add_framelock_devices(CtkFramelock *ctk_framelock,
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_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_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_label = gtk_label_new("Port 1");
framelock_data->port1_hbox = gtk_hbox_new(FALSE, 0);
framelock_data->revision_label = gtk_label_new("FPGA Revision:");
@@ -5080,6 +5270,11 @@ static gint add_devices(CtkFramelock *ctk_framelock,
goto done;
}
+
+ /* Align the list entry titles */
+ list_tree_align_titles((nvListTreePtr)(ctk_framelock->tree));
+
+
/* Fall through */
done:
if (server_name) {
@@ -5324,8 +5519,8 @@ GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table)
"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.");
+ "connector. This LED mirrors the status of the BNC 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 "
diff --git a/src/gtk+-2.x/ctkglx.c b/src/gtk+-2.x/ctkglx.c
index 63abd39..dfe7894 100644
--- a/src/gtk+-2.x/ctkglx.c
+++ b/src/gtk+-2.x/ctkglx.c
@@ -40,7 +40,7 @@
/* Number of FBConfigs attributes reported in gui */
-#define NUM_FBCONFIG_ATTRIBS 30
+#define NUM_FBCONFIG_ATTRIBS 31
/* FBConfig tooltips */
@@ -48,6 +48,11 @@ static const char * __fid_help =
"fid (Frame buffer ID) - Frame Buffer Configuration ID.";
static const char * __vid_help =
"vid (XVisual ID) - ID of the associated X Visual.";
+static const char * __vt_help =
+ "vt (XVisual Type) - Type of the associated X Visual. "
+ "Possible X visual types are 'tc', 'dc', 'pc', 'sc', 'gs', 'sg', '.' "
+ "which means TrueColor, DirectColor, PseudoColor, StaticColor, GrayScale, "
+ "StaticGray and None, respectively.";
static const char * __bfs_help =
"bfs (buffer size) - Number of bits per color in the color buffer.";
static const char * __lvl_help =
@@ -167,6 +172,12 @@ static void dummy_button_signal(GtkWidget *widget,
* signal is thrown. This will result in calling the
* ctk_glx_probe_info() function.
*/
+
+typedef struct WidgetSizeRec {
+ GtkWidget *widget;
+ int width;
+} WidgetSize;
+
GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
CtkConfig *ctk_config, CtkEvent *ctk_event)
{
@@ -175,20 +186,24 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
GtkWidget *label;
GtkWidget *banner;
GtkWidget *hseparator;
- GtkWidget *hbox;
+ GtkWidget *hbox, *hbox1;
GtkWidget *vbox, *vbox2;
- GtkWidget *table;
GtkWidget *scrollWin;
GtkWidget *event; /* For setting the background color to white */
-
+ GtkWidget *data_table, *header_table;
+ GtkWidget *data_viewport, *full_viewport;
+ GtkWidget *vscrollbar, *hscrollbar, *vpan;
+ GtkRequisition req;
ReturnStatus ret;
char * glx_info_str = NULL; /* Test if GLX supported */
GLXFBConfigAttr *fbconfig_attribs = NULL; /* FBConfig data */
int i; /* Iterator */
+ int num_fbconfigs = 0;
+ char *err_str = NULL;
gchar *fbconfig_titles[NUM_FBCONFIG_ATTRIBS] = {
- "fid", "vid", "bfs", "lvl",
+ "fid", "vid", "vt", "bfs", "lvl",
"bf", "db", "st",
"rs", "gs", "bs", "as",
"aux", "dpt", "stn",
@@ -199,8 +214,10 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
"trt", "trr", "trg", "trb", "tra", "tri"
};
+ WidgetSize fbconfig_header_sizes[NUM_FBCONFIG_ATTRIBS];
+
const char *fbconfig_tooltips[NUM_FBCONFIG_ATTRIBS] = {
- __fid_help, __vid_help, __bfs_help, __lvl_help,
+ __fid_help, __vid_help, __vt_help, __bfs_help, __lvl_help,
__bf_help, __db_help, __st_help,
__rs_help, __gs_help, __bs_help, __as_help,
__aux_help, __dpt_help, __stn_help,
@@ -236,7 +253,8 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
&glx_info_str);
free(glx_info_str);
if ( ret != NvCtrlSuccess ) {
- goto fail_glx_not_supported;
+ err_str = "Fail to query the GLX server vendor.";
+ goto fail;
}
@@ -247,7 +265,6 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
event = gtk_event_box_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollWin),
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
- gtk_box_pack_start(GTK_BOX(ctk_glx), scrollWin, TRUE, TRUE, 0);
gtk_widget_modify_fg(event, GTK_STATE_NORMAL, &(event->style->text[GTK_STATE_NORMAL]));
gtk_widget_modify_bg(event, GTK_STATE_NORMAL, &(event->style->base[GTK_STATE_NORMAL]));
gtk_container_add(GTK_CONTAINER(event), hbox);
@@ -255,7 +272,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);
+ gtk_widget_set_size_request(scrollWin, -1, 50);
/* GLX 1.3 supports frame buffer configurations */
@@ -265,60 +282,108 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
ret = NvCtrlGetVoidAttribute(handle, NV_CTRL_ATTR_GLX_FBCONFIG_ATTRIBS,
(void *)(&fbconfig_attribs));
if ( ret != NvCtrlSuccess ) {
- goto fail_glx_not_supported;
+ err_str = "Failed to query list of GLX frame buffer configurations.";
+ goto fail;
+ }
+
+ /* Count the number of fbconfigs */
+ if ( fbconfig_attribs ) {
+ for (num_fbconfigs = 0;
+ fbconfig_attribs[num_fbconfigs].fbconfig_id != 0;
+ num_fbconfigs++);
+ }
+ if ( ! num_fbconfigs ) {
+ err_str = "No frame buffer configurations found.";
+
+ goto fail;
}
+
/* Create clist in a scroll box */
- hbox = gtk_hbox_new(FALSE, 0);
+ hbox1 = gtk_hbox_new(FALSE, 0);
label = gtk_label_new("Frame Buffer Configurations");
hseparator = gtk_hseparator_new();
- gtk_box_pack_start(GTK_BOX(ctk_glx), hbox, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox), hseparator, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox1), hseparator, TRUE, TRUE, 5);
hbox = gtk_hbox_new(FALSE, 0);
vbox = gtk_vbox_new(FALSE, 10);
vbox2 = gtk_vbox_new(FALSE, 10);
- scrollWin = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrollWin),
- 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);
+ vpan = gtk_vpaned_new();
+ data_viewport = gtk_viewport_new(NULL, NULL);
+ gtk_widget_set_size_request(data_viewport, 400, 50);
+ vscrollbar = gtk_vscrollbar_new(gtk_viewport_get_vadjustment
+ (GTK_VIEWPORT(data_viewport)));
+
+ full_viewport = gtk_viewport_new(NULL, NULL);
+ gtk_widget_set_size_request(full_viewport, 400, 50);
+ hscrollbar = gtk_hscrollbar_new(gtk_viewport_get_hadjustment
+ (GTK_VIEWPORT(full_viewport)));
/*
* NODE: Because clists have a hard time displaying tooltips in their
* column labels/buttons, we make the fbconfig table using a
* table widget.
*/
- /* Count number of rows */
- i = 1;
- if ( fbconfig_attribs ) {
- while ( fbconfig_attribs[i].fbconfig_id != 0 ) { i++; }
- }
-
- table = gtk_table_new(i, NUM_FBCONFIG_ATTRIBS, FALSE);
- event = gtk_event_box_new();
+ /* Create the header table */
- gtk_widget_modify_fg(table, GTK_STATE_NORMAL, &(table->style->text[GTK_STATE_NORMAL]));
- gtk_widget_modify_bg(table, GTK_STATE_NORMAL, &(table->style->base[GTK_STATE_NORMAL]));
- gtk_container_add (GTK_CONTAINER(event), table);
- gtk_widget_modify_fg(event, GTK_STATE_NORMAL, &(event->style->text[GTK_STATE_NORMAL]));
- gtk_widget_modify_bg(event, GTK_STATE_NORMAL, &(event->style->base[GTK_STATE_NORMAL]));
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollWin),
- event);
+ header_table = gtk_table_new(num_fbconfigs, NUM_FBCONFIG_ATTRIBS, FALSE);
- /* Generate table headings */
for ( i = 0; i < NUM_FBCONFIG_ATTRIBS; i++ ) {
GtkWidget * btn = gtk_button_new_with_label(fbconfig_titles[i]);
g_signal_connect(G_OBJECT(btn), "clicked",
G_CALLBACK(dummy_button_signal),
(gpointer) ctk_glx);
ctk_config_set_tooltip(ctk_config, btn, fbconfig_tooltips[i]);
- gtk_table_attach(GTK_TABLE(table), btn, i, i+1, 0, 1,
+ gtk_table_attach(GTK_TABLE(header_table), btn, i, i+1, 0, 1,
GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
+
+ fbconfig_header_sizes[i].widget = btn;
+ gtk_widget_size_request(btn, &req);
+ fbconfig_header_sizes[i].width = req.width;
}
+
+ /* Create the data table */
+
+ data_table = gtk_table_new(num_fbconfigs, NUM_FBCONFIG_ATTRIBS, FALSE);
+ event = gtk_event_box_new();
+
+ gtk_widget_modify_fg(data_table, GTK_STATE_NORMAL,
+ &(data_table->style->text[GTK_STATE_NORMAL]));
+ gtk_widget_modify_bg(data_table, GTK_STATE_NORMAL,
+ &(data_table->style->base[GTK_STATE_NORMAL]));
+ gtk_container_add (GTK_CONTAINER(event), data_table);
+ gtk_widget_modify_fg(event, GTK_STATE_NORMAL,
+ &(event->style->text[GTK_STATE_NORMAL]));
+ gtk_widget_modify_bg(event, GTK_STATE_NORMAL,
+ &(event->style->base[GTK_STATE_NORMAL]));
+ gtk_container_add(GTK_CONTAINER(data_viewport), event);
+
+ /* Pack the fbconfig header and data tables */
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), header_table, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), data_viewport, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER(full_viewport), vbox);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), full_viewport, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), hscrollbar, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
+
+ gtk_paned_pack1 (GTK_PANED (vpan), scrollWin, TRUE, FALSE);
+ gtk_paned_pack2 (GTK_PANED (vpan), vbox, TRUE, FALSE);
+ gtk_box_pack_start(GTK_BOX(ctk_glx), vpan, TRUE, TRUE, 0);
+
+ /* Fill the data table */
if ( fbconfig_attribs ) {
@@ -341,6 +406,8 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
} else {
sprintf((char *) (&(str[cell++])),".");
}
+ snprintf((char *) (&(str[cell++])), 16, "%s",
+ x_visual_type_abbrev(fbconfig_attribs[i].x_visual_type));
snprintf((char *) (&(str[cell++])), 16, "%3d",
fbconfig_attribs[i].buffer_size);
snprintf((char *) (&(str[cell++])), 16, "%2d",
@@ -402,10 +469,27 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
/* Populate row cells */
for ( cell = 0; cell < NUM_FBCONFIG_ATTRIBS ; cell++) {
GtkWidget * label = gtk_label_new( str[cell] );
- gtk_table_attach(GTK_TABLE(table), label,
+ gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+ gtk_table_attach(GTK_TABLE(data_table), label,
cell, cell+1,
i+1, i+2,
- GTK_EXPAND, GTK_EXPAND, 3, 2);
+ GTK_EXPAND, GTK_EXPAND, 0, 0);
+
+ /* Make sure the table headers are the same width
+ * as their table data column
+ */
+ gtk_widget_size_request(label, &req);
+
+ if ( fbconfig_header_sizes[cell].width > req.width ) {
+ gtk_widget_set_size_request(label,
+ fbconfig_header_sizes[cell].width,
+ -1);
+ } else if ( fbconfig_header_sizes[cell].width < req.width ) {
+ fbconfig_header_sizes[cell].width = req.width + 6;
+ gtk_widget_set_size_request(fbconfig_header_sizes[cell].widget,
+ fbconfig_header_sizes[cell].width,
+ -1);
+ }
}
i++;
@@ -425,18 +509,17 @@ GtkWidget* ctk_glx_new(NvCtrlAttributeHandle *handle,
/* Failure (no GLX) */
- fail_glx_not_supported:
- label =
- gtk_label_new("GLX not available: either the GLX extension is not\n"
- "available on this X server, or there was a problem\n"
- "retrieving GLX information from the X server.");
- gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+ fail:
+ if (err_str) {
+ label = gtk_label_new(err_str);
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
- gtk_container_add(GTK_CONTAINER(ctk_glx), label);
+ gtk_container_add(GTK_CONTAINER(ctk_glx), label);
+ }
/* Free memory that may have been allocated */
free(fbconfig_attribs);
-
+
gtk_widget_show_all(GTK_WIDGET(object));
return GTK_WIDGET(object);
@@ -776,6 +859,7 @@ GtkTextBuffer *ctk_glx_create_help(GtkTextTagTable *table,
"\t%s\n\n"
"\t%s\n\n"
"\t%s\n\n"
+ "\t%s\n\n"
"\t%s\n\n"
"\t%s\n\n"
@@ -801,6 +885,7 @@ GtkTextBuffer *ctk_glx_create_help(GtkTextTagTable *table,
__fid_help,
__vid_help,
+ __vt_help,
__bfs_help,
__lvl_help,
__bf_help,
diff --git a/src/gtk+-2.x/ctkgvo.c b/src/gtk+-2.x/ctkgvo.c
index 0c36ce7..da79328 100644
--- a/src/gtk+-2.x/ctkgvo.c
+++ b/src/gtk+-2.x/ctkgvo.c
@@ -96,8 +96,15 @@ static void update_input_video_format_text_entry(CtkGvo *ctk_gvo);
static void init_input_video_format_text_entry(CtkGvo *ctk_gvo);
+static void init_composite_termination(CtkGvo *ctk_gvo);
+
static int max_input_video_format_text_entry_length(void);
+static void post_toggle_composite_termination(CtkGvo *gvo, gboolean enabled);
+
+static void toggle_composite_termination(GtkWidget *button,
+ CtkGvo *ctk_gvo);
+
static void detect_input(GtkToggleButton *togglebutton, CtkGvo *ctk_gvo);
static gint detect_input_done(gpointer data);
@@ -316,7 +323,7 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
GtkWidget *hbox, *alignment, *button, *label;
ReturnStatus ret;
gchar scratch[64], *firmware, *string;
- gint val, i, width, height, n;
+ gint val, i, width, height, n, caps;
GtkWidget *frame, *table, *menu;
@@ -331,6 +338,11 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
/* GVO not available */
return NULL;
}
+
+ /* Get this GVO device's capabilities */
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_CAPABILITIES, &caps);
+ if (ret != NvCtrlSuccess) return NULL;
/* create the CtkGvo object */
@@ -509,6 +521,29 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
g_signal_connect(G_OBJECT(button), "toggled",
G_CALLBACK(detect_input), ctk_gvo);
+ /* Composite Termination */
+
+ if (caps & NV_CTRL_GVO_CAPABILITIES_COMPOSITE_TERMINATION) {
+
+ button =
+ gtk_check_button_new_with_label("Enable Composite Termination");
+
+ alignment = gtk_alignment_new(1, 1, 0, 0);
+
+ gtk_container_add(GTK_CONTAINER(alignment), button);
+ gtk_table_attach(GTK_TABLE(table), alignment,
+ 1, 2, 4, 5, GTK_FILL | GTK_EXPAND, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
+
+ ctk_gvo->composite_termination_button = button;
+
+ init_composite_termination(ctk_gvo);
+
+ g_signal_connect(G_OBJECT(button), "toggled",
+ G_CALLBACK(toggle_composite_termination), ctk_gvo);
+ } else {
+ ctk_gvo->composite_termination_button = NULL;
+ }
/*
* Output options
@@ -1817,7 +1852,7 @@ static void toggle_sdi_output_button(GtkWidget *button, gpointer user_data)
return;
}
- post_toggle_sdi_output_button(ctk_gvo, enabled);
+ post_toggle_sdi_output_button(ctk_gvo, enabled);
} /* toggle_sdi_output_button() */
@@ -1977,6 +2012,31 @@ static void init_input_video_format_text_entry(CtkGvo *ctk_gvo)
/*
+ * init_composite_termination() -
+ */
+
+static void init_composite_termination(CtkGvo *ctk_gvo)
+{
+ ReturnStatus ret;
+ gint val;
+
+ if (!ctk_gvo->composite_termination_button) return;
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_COMPOSITE_TERMINATION, &val);
+ if (ret != NvCtrlSuccess) {
+ val = NV_CTRL_GVO_COMPOSITE_TERMINATION_DISABLE;
+ }
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(ctk_gvo->composite_termination_button),
+ (val == NV_CTRL_GVO_COMPOSITE_TERMINATION_ENABLE));
+
+} /* init_composite_termination() */
+
+
+
+/*
* max_input_video_format_text_entry_length()
*/
@@ -1996,6 +2056,47 @@ static int max_input_video_format_text_entry_length(void)
/*
+ * post_toggle_composite_termination() - Call this function after
+ * the composite termination attribute has changed.
+ */
+
+static void post_toggle_composite_termination(CtkGvo *ctk_gvo,
+ gboolean enabled)
+{
+ /* update the statusbar */
+
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Composite Termination %s.",
+ enabled ? "Enabled" : "Disabled");
+
+} /* post_toggle_composite_termination() */
+
+
+
+/*
+ * toggle_composite_termination() - Called when the user clicks
+ * on the "Enable Composite Termination" check button.
+ */
+
+static void toggle_composite_termination(GtkWidget *button,
+ CtkGvo *ctk_gvo)
+{
+ gboolean enabled;
+
+ enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
+
+ NvCtrlSetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_COMPOSITE_TERMINATION,
+ enabled ? NV_CTRL_GVO_COMPOSITE_TERMINATION_ENABLE :
+ NV_CTRL_GVO_COMPOSITE_TERMINATION_DISABLE);
+
+ post_toggle_composite_termination(ctk_gvo, enabled);
+
+} /* toggle_composite_termination() */
+
+
+
+/*
* detect_input() - if the Detect button is enabled, then enable
* INPUT_VIDEO_FORMAT_REACQUIRE, make everything else insensitive,
* switch to the wait cursor, and queue detect_input_done() to be
@@ -2524,6 +2625,11 @@ static void register_for_gvo_events(CtkGvo *ctk_gvo)
CTK_EVENT_NAME(NV_CTRL_GVO_DISPLAY_X_SCREEN),
G_CALLBACK(gvo_event_received),
(gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_COMPOSITE_TERMINATION),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
}
@@ -2683,6 +2789,26 @@ static void gvo_event_received(GtkObject *object,
}
break;
+ case NV_CTRL_GVO_COMPOSITE_TERMINATION:
+ widget = ctk_gvo->composite_termination_button;
+
+ if (widget) {
+ g_signal_handlers_block_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(toggle_composite_termination),
+ ctk_gvo);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), value);
+
+ post_toggle_composite_termination(ctk_gvo, value);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(toggle_composite_termination),
+ ctk_gvo);
+ }
+ break;
+
}
}
diff --git a/src/gtk+-2.x/ctkgvo.h b/src/gtk+-2.x/ctkgvo.h
index 85d4211..30d1367 100644
--- a/src/gtk+-2.x/ctkgvo.h
+++ b/src/gtk+-2.x/ctkgvo.h
@@ -86,6 +86,8 @@ struct _CtkGvo
GtkWidget *output_video_format_menu;
GtkWidget *output_data_format_menu;
+ GtkWidget *composite_termination_button;
+
GtkWidget *enable_sdi_output_label;
GtkWidget *disable_sdi_output_label;
GtkWidget *toggle_sdi_output_button;
diff --git a/src/gtk+-2.x/ctkutils.c b/src/gtk+-2.x/ctkutils.c
index 28a8f85..c25e0f9 100644
--- a/src/gtk+-2.x/ctkutils.c
+++ b/src/gtk+-2.x/ctkutils.c
@@ -24,7 +24,9 @@
#include <gtk/gtk.h>
#include "ctkutils.h"
-#include <stdlib.h>
+#include "msg.h"
+
+
GtkWidget *add_table_row(GtkWidget *table,
@@ -55,4 +57,87 @@ GtkWidget *add_table_row(GtkWidget *table,
return label;
}
+
+
+
+/** ctk_get_parent_window() ******************************************
+ *
+ * Returns the parent window of a widget, if one exists
+ *
+ **/
+GtkWidget * ctk_get_parent_window(GtkWidget *child)
+{
+ GtkWidget *parent = gtk_widget_get_parent(child);
+
+ while (parent && !GTK_IS_WINDOW(parent)) {
+ GtkWidget *last = parent;
+
+ parent = gtk_widget_get_parent(last);
+ if (!parent || parent == last) {
+ /* GTK Error, can't find parent window! */
+ parent = NULL;
+ break;
+ }
+ }
+
+ return parent;
+
+} /* ctk_get_parent_window() */
+
+
+
+
+/** ctk_display_error_msg() ******************************************
+ *
+ * Displays an error message.
+ *
+ **/
+void ctk_display_error_msg(GtkWidget *parent, gchar * msg)
+{
+ GtkWidget *dlg;
+
+ if (msg) {
+ nv_error_msg(msg);
+
+ if (parent) {
+ dlg = gtk_message_dialog_new
+ (GTK_WINDOW(parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ msg);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+ }
+ }
+
+} /* ctk_display_error_msg() */
+
+
+
+/** ctk_display_warning_msg() ****************************************
+ *
+ * Displays a warning message.
+ *
+ **/
+void ctk_display_warning_msg(GtkWidget *parent, gchar * msg)
+{
+ GtkWidget *dlg;
+
+ if (msg) {
+ nv_warning_msg(msg);
+
+ if (parent) {
+ dlg = gtk_message_dialog_new
+ (GTK_WINDOW(parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ msg);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+ }
+ }
+
+} /* ctk_display_warning_msg() */
diff --git a/src/gtk+-2.x/ctkutils.h b/src/gtk+-2.x/ctkutils.h
index 0cc28cf..bc387d6 100644
--- a/src/gtk+-2.x/ctkutils.h
+++ b/src/gtk+-2.x/ctkutils.h
@@ -21,7 +21,7 @@
* Boston, MA 02111-1307, USA
*
*/
-
+
#ifndef __CTK_UTILS_H__
#define __CTK_UTILS_H__
@@ -33,7 +33,13 @@ G_BEGIN_DECLS
GtkWidget *add_table_row(GtkWidget *, const gint,
const gfloat, const gfloat, const gchar *,
const gfloat, const gfloat, const gchar *);
-
+
+GtkWidget * ctk_get_parent_window(GtkWidget *child);
+
+void ctk_display_error_msg(GtkWidget *parent, gchar *msg);
+
+void ctk_display_warning_msg(GtkWidget *parent, gchar *msg);
+
G_END_DECLS
#endif /* __CTK_UTILS_H__ */
diff --git a/src/gtk+-2.x/ctkxvideo.c b/src/gtk+-2.x/ctkxvideo.c
index 85085ba..53063a6 100644
--- a/src/gtk+-2.x/ctkxvideo.c
+++ b/src/gtk+-2.x/ctkxvideo.c
@@ -74,7 +74,6 @@ static const char *__reset_button_help =
static void xv_sync_to_display_changed(GtkWidget *widget, gpointer user_data);
static GtkWidget *xv_sync_to_display_radio_button_add(CtkXVideo *ctk_xvideo,
- GtkWidget *vbox,
GtkWidget *prev_radio,
char *label,
gint value,
@@ -112,6 +111,13 @@ static GtkWidget *create_check_button(CtkXVideo *ctk_xvideo,
static void check_button_toggled(GtkWidget *widget, gpointer user_data);
+
+static void post_check_button_toggled(CtkXVideo *ctk_xvideo,
+ gchar *str,
+ gboolean enabled);
+
+static void sensitize_radio_buttons(CtkXVideo *ctk_xvideo);
+
static void reset_check_button(CtkXVideo *ctk_xvideo,
GtkWidget *check_button,
gint attribute);
@@ -120,6 +126,15 @@ static void set_button_sensitive(GtkButton *button);
static void reset_defaults(GtkButton *button, gpointer user_data);
+static void post_xv_sync_to_display_changed(CtkXVideo *ctk_xvideo,
+ gboolean enabled,
+ gchar *label);
+static void nv_ctrl_enabled_displays(GtkObject *object, gpointer arg1,
+ gpointer user_data);
+static void xv_sync_to_display_radio_button_remove(CtkXVideo *ctk_xvideo,
+ gint value);
+static void xv_sync_to_display_radio_button_enabled_add(CtkXVideo *ctk_xvideo,
+ gint add_device_mask);
#define FRAME_PADDING 5
@@ -166,7 +181,6 @@ GType ctk_xvideo_get_type(
*/
static GtkWidget *xv_sync_to_display_radio_button_add(CtkXVideo *ctk_xvideo,
- GtkWidget *vbox,
GtkWidget *prev_radio,
char *label,
gint value,
@@ -181,8 +195,9 @@ static GtkWidget *xv_sync_to_display_radio_button_add(CtkXVideo *ctk_xvideo,
radio = gtk_radio_button_new_with_label(NULL, label);
}
- gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0);
-
+ gtk_box_pack_start(GTK_BOX(ctk_xvideo->xv_sync_to_display_button_box),
+ radio, FALSE, FALSE, 0);
+
g_object_set_data(G_OBJECT(radio), "xv_sync_to_display",
GINT_TO_POINTER(value));
@@ -261,14 +276,135 @@ static void xv_sync_to_display_changed(GtkWidget *widget, gpointer user_data)
NV_CTRL_XV_SYNC_TO_DISPLAY, value);
gtk_label_get(GTK_LABEL(GTK_BIN(widget)->child), &label);
-
- ctk_config_statusbar_message(ctk_xvideo->ctk_config,
+
+ post_xv_sync_to_display_changed(ctk_xvideo, enabled, label);
+ }
+}/* xv_sync_to_display_changed() */
+
+
+static void post_xv_sync_to_display_changed(CtkXVideo *ctk_xvideo,
+ gboolean enabled,
+ gchar *label)
+{
+ ctk_config_statusbar_message(ctk_xvideo->ctk_config,
"XVideo application syncing to %s.",
label);
+}
+
+/*
+ * xv_sync_to_display_radio_button_remove()
+ */
+static void xv_sync_to_display_radio_button_remove(CtkXVideo *ctk_xvideo,
+ gint value)
+{
+ int j;
+ GtkWidget *b;
+ gpointer user_data;
+ for (j = 0; j < 24; j++) {
+ b = ctk_xvideo->xv_sync_to_display_buttons[j];
+ if (b != NULL) {
+ user_data = g_object_get_data(G_OBJECT(b), "xv_sync_to_display");
+ if (GPOINTER_TO_INT(user_data) == value) {
+ g_object_set_data(G_OBJECT(b), "xv_sync_to_display",
+ GINT_TO_POINTER(0));
+ gtk_container_remove(GTK_CONTAINER(ctk_xvideo->xv_sync_to_display_button_box), b);
+ ctk_xvideo->xv_sync_to_display_buttons[j] = NULL;
+ break;
+ }
+ }
+ }
+} /* xv_sync_to_display_radio_button_remove() */
+
+/*
+ * nv_ctrl_enabled_displays()
+ */
+static void nv_ctrl_enabled_displays(GtkObject *object, gpointer arg1,
+ gpointer user_data)
+{
+ CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data);
+ CtkEventStruct *event_struct = (CtkEventStruct *) arg1;
+ int i, enabled, prev_enabled = 0;
+ int remove_devices_mask, add_devices_mask;
+ unsigned int mask;
+ gpointer udata;
+ GtkWidget *b;
+
+ enabled = event_struct->value;
+ /* Extract the previous value. */
+ for ( i = 0; i < 24; i++) {
+ b = ctk_xvideo->xv_sync_to_display_buttons[i];
+ if (b == NULL) continue;
+ udata = g_object_get_data(G_OBJECT(b),
+ "xv_sync_to_display");
+
+ prev_enabled |= GPOINTER_TO_INT(udata);
+ }
+
+ /* Remove devices that were previously enabled but are no
+ * longer enabled. */
+ remove_devices_mask = (prev_enabled & (~enabled));
+
+ /* Add devices that were not previously enabled */
+ add_devices_mask = (enabled & (~prev_enabled));
+ prev_enabled = enabled;
+ for (mask = 1; mask; mask <<= 1) {
+ if (mask & add_devices_mask)
+ xv_sync_to_display_radio_button_enabled_add(ctk_xvideo, mask);
+
+ if (mask & remove_devices_mask)
+ xv_sync_to_display_radio_button_remove(ctk_xvideo, mask);
+ }
+ sensitize_radio_buttons(ctk_xvideo);
+ gtk_widget_show_all(ctk_xvideo->xv_sync_to_display_button_box);
+} /* nv_ctrl_enabled_displays() */
+
+/*
+ * xv_sync_to_display_radio_button_enabled_add()
+ */
+static void xv_sync_to_display_radio_button_enabled_add(CtkXVideo *ctk_xvideo,
+ gint add_device_mask)
+{
+ GtkWidget *radio[24], *prev_radio = NULL, *b1, *b2;
+ int n;
+ ReturnStatus ret;
+ char *name, *type;
+ gchar *name_str;
+
+ /* Get the previous radio button. */
+ for (n = 0; n < 24; n++) {
+ b1 = ctk_xvideo->xv_sync_to_display_buttons[n];
+ if (b1 != NULL) {
+ prev_radio = b1;
+ break;
+ }
+ }
+ /* Get the next index where to add button. */
+ for (n = 0; n < 24; n++) {
+ b2 = ctk_xvideo->xv_sync_to_display_buttons[n];
+ if (b2 == NULL) break;
+ }
+ ret = NvCtrlGetStringDisplayAttribute(ctk_xvideo->handle, add_device_mask,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &name);
+
+ if ((ret != NvCtrlSuccess) || (!name)) {
+ name = g_strdup("Unknown");
}
+ /* get the display device type */
+ type = display_device_mask_to_display_device_name(add_device_mask);
+ name_str = g_strdup_printf("%s (%s)", name, type);
+ XFree(name);
+ free(type);
-} /* xv_sync_to_display_changed() */
+ radio[n] = xv_sync_to_display_radio_button_add(ctk_xvideo,
+ prev_radio, name_str,
+ add_device_mask, n);
+ g_free(name_str);
+ ctk_config_set_tooltip(ctk_xvideo->ctk_config, radio[n],
+ __xv_sync_to_display_help);
+
+} /* xv_sync_to_display_radio_button_enabled_add() */
/*
* xv_sync_to_display_update_received() - callback function for changed sync
@@ -277,8 +413,9 @@ static void xv_sync_to_display_changed(GtkWidget *widget, gpointer user_data)
* about.
*/
-static void xv_sync_to_display_update_received(GtkObject *object, gpointer arg1,
- gpointer user_data)
+static void xv_sync_to_display_update_received(GtkObject *object,
+ gpointer arg1,
+ gpointer user_data)
{
CtkEventStruct *event_struct = (CtkEventStruct *) arg1;
CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data);
@@ -323,10 +460,8 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle,
GtkWidget *label;
GtkWidget *vbox;
GtkWidget *button;
-
+ int sync_mask;
int xv_overlay_present, xv_texture_present, xv_blitter_present;
- int sync_mask;
-
ReturnStatus ret;
/*
@@ -434,7 +569,7 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle,
gtk_container_add(GTK_CONTAINER(frame), vbox);
ctk_xvideo->texture_sync_to_blank =
- create_check_button(ctk_xvideo, vbox, button, "Sync To VBlank",
+ create_check_button(ctk_xvideo, vbox, button, "Sync to VBlank",
__xv_texture_sync_to_vblank_help,
NV_CTRL_ATTR_XV_TEXTURE_SYNC_TO_VBLANK,
__XV_TEXTURE_SYNC_TO_VBLANK);
@@ -444,101 +579,103 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle,
if (xv_blitter_present) {
-
- frame = gtk_frame_new("Video Blitter Adaptor");
+ frame = gtk_frame_new("Video Blitter Adaptor Settings");
gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
vbox = gtk_vbox_new(FALSE, 5);
+ ctk_xvideo->xv_sync_to_display_button_box = vbox;
gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
ctk_xvideo->blitter_sync_to_blank =
- create_check_button(ctk_xvideo, vbox, button, "Sync To VBlank",
+ create_check_button(ctk_xvideo,
+ ctk_xvideo->xv_sync_to_display_button_box,
+ button,
+ "Sync to VBlank on display device",
__xv_blitter_sync_to_vblank_help,
NV_CTRL_ATTR_XV_BLITTER_SYNC_TO_VBLANK,
__XV_BLITTER_SYNC_TO_VBLANK);
- }
-
- /* Sync to display selection */
-
- ret = NvCtrlGetAttribute(handle,
- NV_CTRL_XV_SYNC_TO_DISPLAY,
- &sync_mask);
-
- if (ret == NvCtrlSuccess) {
- int enabled;
-
- ret = NvCtrlGetAttribute(handle, NV_CTRL_ENABLED_DISPLAYS, &enabled);
+
+ /* Sync to display selection */
+ ret = NvCtrlGetAttribute(handle,
+ NV_CTRL_XV_SYNC_TO_DISPLAY,
+ &sync_mask);
if (ret == NvCtrlSuccess) {
- GtkWidget *radio[24], *prev_radio;
- int i, n, current = -1, mask;
- char *name;
- char *type;
- gchar *name_str;
-
- frame = gtk_frame_new("Sync to this display device");
- gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
-
- vbox = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(vbox), FRAME_PADDING);
- gtk_container_add(GTK_CONTAINER(frame), vbox);
-
- ctk_xvideo->active_attributes |= __XV_SYNC_TO_DISPLAY;
+ int enabled;
+ ret = NvCtrlGetAttribute(handle,
+ NV_CTRL_ENABLED_DISPLAYS,
+ &enabled);
+ if (ret == NvCtrlSuccess) {
+
+ GtkWidget *radio[24], *prev_radio;
+ int i, n, current = -1, mask;
+ char *name, *type;
+ gchar *name_str;
- for (n=0, i = 0; i < 24; i++) {
+
+ for (n=0, i = 0; i < 24; i++) {
- mask = 1 << i;
- if (!(enabled & mask)) continue;
+ mask = 1 << i;
+ if (!(enabled & mask)) continue;
- /* get the name of the display device */
+ /* get the name of the display device */
- ret = NvCtrlGetStringDisplayAttribute(handle, mask,
- NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
- &name);
+ ret = NvCtrlGetStringDisplayAttribute(handle, mask,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &name);
- if ((ret != NvCtrlSuccess) || (!name)) {
- name = g_strdup("Unknown");
- }
+ if ((ret != NvCtrlSuccess) || (!name)) {
+ name = g_strdup("Unknown");
+ }
- /* get the display device type */
+ /* get the display device type */
- type = display_device_mask_to_display_device_name(mask);
+ type = display_device_mask_to_display_device_name(mask);
- name_str = g_strdup_printf("%s (%s)", name, type);
- XFree(name);
- free(type);
+ name_str = g_strdup_printf("%s (%s)", name, type);
+ XFree(name);
+ free(type);
- if (n==0) {
- prev_radio = NULL;
- } else {
- prev_radio = radio[n-1];
- }
- radio[n] = xv_sync_to_display_radio_button_add(ctk_xvideo, vbox,
- prev_radio, name_str, mask, n);
- g_free(name_str);
-
- ctk_config_set_tooltip(ctk_config, radio[n],
- __xv_sync_to_display_help);
+ if (n==0) {
+ prev_radio = NULL;
+ } else {
+ prev_radio = radio[n-1];
+ }
+ radio[n] = xv_sync_to_display_radio_button_add(ctk_xvideo,
+ prev_radio, name_str,
+ mask, n);
+ g_free(name_str);
+ ctk_config_set_tooltip(ctk_config, radio[n],
+ __xv_sync_to_display_help);
- if (mask == sync_mask) {
- current = n;
- }
+ if (mask == sync_mask) {
+ current = n;
+ }
- n++;
- }
-
- g_signal_connect(G_OBJECT(ctk_event),
- CTK_EVENT_NAME(NV_CTRL_XV_SYNC_TO_DISPLAY),
- G_CALLBACK(xv_sync_to_display_update_received),
- (gpointer) ctk_xvideo);
+ n++;
+ ctk_xvideo->active_attributes |= __XV_SYNC_TO_DISPLAY;
+ }
+
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_XV_SYNC_TO_DISPLAY),
+ G_CALLBACK(xv_sync_to_display_update_received),
+ (gpointer) ctk_xvideo);
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_ENABLED_DISPLAYS),
+ G_CALLBACK(nv_ctrl_enabled_displays),
+ (gpointer) ctk_xvideo);
+ sensitize_radio_buttons(ctk_xvideo);
- if (current != -1)
- xv_sync_to_display_update_radio_buttons(ctk_xvideo, current);
+ if (current != -1)
+ xv_sync_to_display_update_radio_buttons(ctk_xvideo, current);
+
+ }
}
}
/* Reset button */
+ sensitize_radio_buttons(ctk_xvideo);
alignment = gtk_alignment_new(1, 1, 0, 0);
gtk_container_add(GTK_CONTAINER(alignment), button);
gtk_box_pack_start(GTK_BOX(object), alignment, TRUE, TRUE, 0);
@@ -721,7 +858,7 @@ static GtkWidget *create_check_button(CtkXVideo *ctk_xvideo,
g_object_set_data(G_OBJECT(check_button), "xvideo_attribute",
GINT_TO_POINTER(attribute));
-
+
ctk_config_set_tooltip(ctk_xvideo->ctk_config, check_button, name);
gtk_box_pack_start(GTK_BOX(vbox), check_button, FALSE, FALSE, 0);
@@ -756,16 +893,46 @@ static void check_button_toggled(GtkWidget *widget, gpointer user_data)
switch (attribute) {
case NV_CTRL_ATTR_XV_TEXTURE_SYNC_TO_VBLANK:
str = "Texture Sync To VBlank"; break;
- case NV_CTRL_ATTR_XV_BLITTER_SYNC_TO_VBLANK:
- str = "Blitter Sync To VBlank"; break;
+ case NV_CTRL_ATTR_XV_BLITTER_SYNC_TO_VBLANK: {
+ str = "Blitter Sync To VBlank";
+ sensitize_radio_buttons(ctk_xvideo);
+ break;
+ }
default:
return;
}
-
+ post_check_button_toggled(ctk_xvideo, str, enabled);
+} /* check_button_toggled() */
+
+/*
+ * post_check_button_toggled()
+ */
+
+static void post_check_button_toggled(CtkXVideo *ctk_xvideo, gchar *str, gboolean enabled)
+{
ctk_config_statusbar_message(ctk_xvideo->ctk_config, "%s XVideo %s.",
enabled ? "Enabled" : "Disabled", str);
-} /* check_button_toggled() */
+} /* post_check_button_toggled() */
+
+/*
+ * sensitize_radio_buttons()
+ */
+static void sensitize_radio_buttons(CtkXVideo *ctk_xvideo)
+{
+ int i;
+ gboolean enabled;
+ if (!ctk_xvideo->blitter_sync_to_blank) return;
+
+ enabled = gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(ctk_xvideo->blitter_sync_to_blank));
+
+ for (i = 0; i < 24; i++) {
+ GtkWidget *b = ctk_xvideo->xv_sync_to_display_buttons[i];
+ if (!b) continue;
+ gtk_widget_set_sensitive(b, enabled);
+ }
+} /* sensitize_radio_buttons() */
/*
@@ -791,6 +958,7 @@ static void reset_check_button(CtkXVideo *ctk_xvideo,
g_signal_handlers_unblock_matched
(G_OBJECT(check_button), G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
G_CALLBACK(check_button_toggled), NULL);
+ sensitize_radio_buttons(ctk_xvideo);
} /* reset_check_button() */
diff --git a/src/gtk+-2.x/ctkxvideo.h b/src/gtk+-2.x/ctkxvideo.h
index 6c6e5b7..88a9e47 100644
--- a/src/gtk+-2.x/ctkxvideo.h
+++ b/src/gtk+-2.x/ctkxvideo.h
@@ -66,8 +66,8 @@ struct _CtkXVideo
GtkWidget *texture_sync_to_blank;
GtkWidget *blitter_sync_to_blank;
GtkWidget *xv_sync_to_display_buttons[24];
-
- unsigned int active_attributes;
+ GtkWidget *xv_sync_to_display_button_box;
+ unsigned int active_attributes;
};
struct _CtkXVideoClass
diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h
index 58fd564..803e8f8 100644
--- a/src/libXNVCtrl/NVCtrl.h
+++ b/src/libXNVCtrl/NVCtrl.h
@@ -119,6 +119,8 @@
* 0: default (the driver will decide when to dither)
* 1: enabled (the driver will always dither when possible)
* 2: disabled (the driver will never dither)
+ *
+ * USAGE NOTE: This attribute had been deprecated.
*/
#define NV_CTRL_FLATPANEL_DITHERING 3 /* RWDG */
@@ -1223,6 +1225,11 @@
* unless NV_CTRL_GPU_OVERCLOCKING_STATE is set to _MANUAL. Since
* the target clocks may be rejected, the requester should read this
* attribute after the set to determine success or failure.
+ *
+ * NV_CTRL_GPU_{2,3}D_CLOCK_FREQS are "packed" integer attributes; the
+ * GPU clock is stored in the upper 16 bits of the integer, and the
+ * memory clock is stored in the lower 16 bits of the integer. All
+ * clock values are in MHz.
*/
#define NV_CTRL_GPU_2D_CLOCK_FREQS 89 /* RW-G */
@@ -1232,6 +1239,11 @@
/*
* NV_CTRL_GPU_DEFAULT_{2,3}D_CLOCK_FREQS - query the default memory
* and GPU core clocks of the device driving the X screen.
+ *
+ * NV_CTRL_GPU_DEFAULT_{2,3}D_CLOCK_FREQS are "packed" integer
+ * attributes; the GPU clock is stored in the upper 16 bits of the
+ * integer, and the memory clock is stored in the lower 16 bits of the
+ * integer. All clock values are in MHz.
*/
#define NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS 91 /* R--G */
@@ -1241,6 +1253,11 @@
/*
* NV_CTRL_GPU_CURRENT_CLOCK_FREQS - query the current GPU and memory
* clocks of the graphics device driving the X screen.
+ *
+ * NV_CTRL_GPU_CURRENT_CLOCK_FREQS is a "packed" integer attribute;
+ * the GPU clock is stored in the upper 16 bits of the integer, and
+ * the memory clock is stored in the lower 16 bits of the integer.
+ * All clock values are in MHz. All clock values are in MHz.
*/
#define NV_CTRL_GPU_CURRENT_CLOCK_FREQS 93 /* R--G */
@@ -2663,11 +2680,16 @@
* 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.
+ *
+ * COMPOSITE_TERMINATION - whether the 75 ohm termination of the
+ * SDI composite input signal can be programmed through the
+ * NV_CTRL_GVO_COMPOSITE_TERMINATION attribute.
*/
#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
+#define NV_CTRL_GVO_CAPABILITIES_COMPOSITE_TERMINATION 0x4
/*
@@ -2980,7 +3002,19 @@
#define NV_CTRL_FSAA_APPLICATION_ENHANCED_ENABLED 1
#define NV_CTRL_FSAA_APPLICATION_ENHANCED_DISABLED 0
-#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_FSAA_APPLICATION_ENHANCED
+
+/*
+ * NV_CTRL_FRAMELOCK_SYNC_RATE_4 - This is the refresh rate that the
+ * frame lock board is sending to the GPU with 4 digits of precision.
+ *
+ * This attribute may be queried through XNVCTRLQueryTargetAttribute()
+ * using a NV_CTRL_TARGET_TYPE_FRAMELOCK.
+ */
+
+#define NV_CTRL_FRAMELOCK_SYNC_RATE_4 256 /* R--F */
+
+
+#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_FRAMELOCK_SYNC_RATE_4
/**************************************************************************/
@@ -3269,7 +3303,6 @@
#define NV_CTRL_STRING_MOVE_METAMODE 23 /* -W-- */
-
/*
* NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES - returns the valid
* horizontal sync ranges used to perform mode validation for the
@@ -3361,7 +3394,8 @@
#define NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER 27 /* RW-- */
-#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER
+#define NV_CTRL_STRING_LAST_ATTRIBUTE \
+ NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER
/**************************************************************************/
@@ -3546,8 +3580,59 @@
#define NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT 6 /* R-DG */
+/*
+ * NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU - Returns the list of
+ * Framelock devices currently connected to the given GPU.
+ *
+ * The format of the returned data is:
+ *
+ * 4 CARD32 number of Framelocks
+ * 4 * n CARD32 Framelock 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_FRAMELOCKS_USED_BY_GPU 7 /* R-DG */
+
+
+/*
+ * NV_CTRL_BINARY_DATA_GPUS_USING_VCSC - Returns the list of
+ * GPU devices connected to the given VCSC.
+ *
+ * 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_VCSC target. This attribute cannot be
+ * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN and cannot be queried using
+ * a NV_CTRL_TARGET_TYPE_X_GPU
+ */
+
+#define NV_CTRL_BINARY_DATA_GPUS_USING_VCSC 8 /* R-DV */
+
+
+/*
+ * NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU - Returns the VCSC device
+ * that is controlling the given GPU.
+ *
+ * The format of the returned data is:
+ *
+ * 4 CARD32 number of VCSCs (always 1)
+ * 4 * n CARD32 VCSC 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_VCSCS_USED_BY_GPU 9 /* R-DG */
+
#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE \
- NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT
+ NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU
/**************************************************************************/
@@ -3675,7 +3760,7 @@
#define NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE \
- NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL
+ NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL
diff --git a/src/libXNVCtrl/libXNVCtrl.a b/src/libXNVCtrl/libXNVCtrl.a
index 1aae24f..2c0a0e0 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 012f397..e655961 100644
--- a/src/libXNVCtrl/nv_control.h
+++ b/src/libXNVCtrl/nv_control.h
@@ -6,7 +6,7 @@
#define NV_CONTROL_NAME "NV-CONTROL"
#define NV_CONTROL_MAJOR 1
-#define NV_CONTROL_MINOR 12
+#define NV_CONTROL_MINOR 13
#define X_nvCtrlQueryExtension 0
#define X_nvCtrlIsNv 1
diff --git a/src/nvidia-settings.c b/src/nvidia-settings.c
index 7a9d2e9..d82e355 100644
--- a/src/nvidia-settings.c
+++ b/src/nvidia-settings.c
@@ -75,6 +75,23 @@ int main(int argc, char **argv)
init_config_properties(&conf);
+ /*
+ * Rewrite the X server settings to configuration file
+ * and exit, without starting a Graphical User Interface.
+ */
+
+ if (op->rewrite) {
+ nv_parsed_attribute_clean(p);
+ h = nv_alloc_ctrl_handles(op->ctrl_display);
+ if(!h || !h->dpy) return 1;
+ ret = nv_write_config_file(op->config, h, p, &conf);
+ nv_free_ctrl_handles(h);
+ nv_parsed_attribute_free(p);
+ free(op);
+ op = NULL;
+ return ret ? 0 : 1;
+ }
+
/* upload the data from the config file */
if (!op->no_load) {
diff --git a/src/parse.c b/src/parse.c
index 92358ec..608fd80 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -133,6 +133,7 @@ AttributeTableEntry attributeTable[] = {
{ "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 },
+ { "FrameLockSyncRate4", NV_CTRL_FRAMELOCK_SYNC_RATE_4, N|F|G },
{ "FrameLockTiming", NV_CTRL_FRAMELOCK_TIMING, N|F|G },
{ "FrameLockMasterable", NV_CTRL_FRAMELOCK_MASTERABLE, N|F|G },
{ "FrameLockFPGARevision", NV_CTRL_FRAMELOCK_FPGA_REVISION, N|F|G },
@@ -195,7 +196,7 @@ AttributeTableEntry attributeTable[] = {
* about.
*/
-#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_FSAA_APPLICATION_ENHANCED
+#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_FRAMELOCK_SYNC_RATE_4
#warning "Have you forgotten to add a new integer attribute to attributeTable?"
#endif
@@ -1228,3 +1229,242 @@ static char *nv_strndup(char *s, int n)
return (m);
} /* nv_strndup() */
+
+
+
+/** parse_skip_whitespace() ******************************************
+ *
+ * Returns a pointer to the start of non-whitespace chars in string 'str'
+ *
+ **/
+const char *parse_skip_whitespace(const char *str)
+{
+ while (*str &&
+ (*str == ' ' || *str == '\t' ||
+ *str == '\n' || *str == '\r')) {
+ str++;
+ }
+ return str;
+
+} /* parse_skip_whitespace() */
+
+
+
+/** parse_chop_whitespace() ******************************************
+ *
+ * Removes all trailing whitespace chars from the given string 'str'
+ *
+ ***/
+void parse_chop_whitespace(char *str)
+{
+ char *tmp = str + strlen(str) -1;
+
+ while (tmp >= str &&
+ (*tmp == ' ' || *tmp == '\t' ||
+ *tmp == '\n' || *tmp == '\r')) {
+ *tmp = '\0';
+ tmp--;
+ }
+
+} /* parse_chop_whitespace() */
+
+
+
+/** parse_skip_integer() *********************************************
+ *
+ * Returns a pointer to the location just after any integer in string 'str'
+ *
+ **/
+const char *parse_skip_integer(const char *str)
+{
+ if (*str == '-' || *str == '+') {
+ str++;
+ }
+ while (*str && *str >= '0' && *str <= '9') {
+ str++;
+ }
+ return str;
+
+} /* parse_skip_integer() */
+
+
+
+/** parse_read_integer() *********************************************
+ *
+ * Reads an integer from string str and returns a pointer
+ *
+ **/
+const char *parse_read_integer(const char *str, int *num)
+{
+ str = parse_skip_whitespace(str);
+ *num = atoi(str);
+ str = parse_skip_integer(str);
+ return parse_skip_whitespace(str);
+
+} /* parse_read_integer() */
+
+
+
+/** parse_read_integer_pair() ****************************************
+ *
+ * Reads two integers separated by 'separator' and returns a pointer
+ * to the location in 'str' where parsing finished. (After the two
+ * integers). NULL is returned on failure.
+ *
+ **/
+const char *parse_read_integer_pair(const char *str,
+ char separator, int *a, int *b)
+ {
+ str = parse_read_integer(str, a);
+ if (!str) return NULL;
+
+ if (separator) {
+ if (*str != separator) return NULL;
+ str++;
+ }
+ return parse_read_integer(str, b);
+
+} /* parse_read_integer_pair() */
+
+
+
+/** parse_read_name() ************************************************
+ *
+ * Skips whitespace and copies characters up to and excluding the
+ * terminating character 'term'. The location where parsing stopped
+ * is returned, or NULL on failure.
+ *
+ **/
+const char *parse_read_name(const char *str, char **name, char term)
+{
+ const char *tmp;
+
+ str = parse_skip_whitespace(str);
+ tmp = str;
+ while (*str && *str != term) {
+ str++;
+ }
+ *name = (char *)calloc(1, str -tmp +1);
+ if (!(*name)) {
+ return NULL;
+ }
+ strncpy(*name, tmp, str -tmp);
+ if (*str == term) {
+ str++;
+ }
+ return parse_skip_whitespace(str);
+
+} /* parse_read_name() */
+
+
+
+/** parse_read_display_name() ****************************************
+ *
+ * Convert a 'CRT-1' style display device name into a device_mask
+ * '0x00000002' bitmask. The location where parsing stopped is returned
+ * or NULL if an error occured.
+ *
+ **/
+const char *parse_read_display_name(const char *str, unsigned int *mask)
+{
+ if (!str || !mask) {
+ return NULL;
+ }
+
+ str = parse_skip_whitespace(str);
+ if (!strncmp(str, "CRT-", 4)) {
+ *mask = 1 << (atoi(str+4));
+
+ } else if (!strncmp(str, "TV-", 3)) {
+ *mask = (1 << (atoi(str+3))) << 8;
+
+ } else if (!strncmp(str, "DFP-", 4)) {
+ *mask = (1 << (atoi(str+4))) << 16;
+
+ } else {
+ return NULL;
+ }
+
+ while (*str && *str != ':') {
+ str++;
+ }
+ if (*str == ':') {
+ str++;
+ }
+
+ return parse_skip_whitespace(str);
+
+} /* parse_read_display_name() */
+
+
+
+/** parse_read_float_range() *****************************************
+ *
+ * Reads the maximun/minimum information from a string in the
+ * following format:
+ * "MIN-MAX"
+ * or
+ * "MIN"
+ *
+ **/
+int parse_read_float_range(char *str, float *min, float *max)
+{
+ if (!str) return 0;
+
+ str = (char *)parse_skip_whitespace(str);
+ *min = atof(str);
+ str = strstr(str, "-");
+ if (!str) {
+ *max = *min;
+ return 1;
+ }
+ str++;
+ *max = atof(str);
+
+ return 1;
+
+} /* parse_read_float_range() */
+
+
+
+/** parse_token_value_pairs() ****************************************
+ *
+ * Parses the given string for "token=value, token=value, ..." pairs
+ * and dispatches the handeling of tokens to the given function with
+ * the given data as an extra argument.
+ *
+ **/
+int parse_token_value_pairs(const char *str, apply_token_func func,
+ void *data)
+{
+ char *token;
+ char *value;
+
+
+ if (str) {
+
+ /* Parse each token */
+ while (*str) {
+
+ /* Read the token */
+ str = parse_read_name(str, &token, '=');
+ if (!str) return 0;
+
+ /* Read the value */
+ str = parse_read_name(str, &value, ',');
+ if (!str) return 0;
+
+ /* Remove trailing whitespace */
+ parse_chop_whitespace(token);
+ parse_chop_whitespace(value);
+
+ func(token, value, data);
+
+ free(token);
+ free(value);
+ }
+ }
+
+ return 1;
+
+} /* parse_token_value_pairs() */
diff --git a/src/parse.h b/src/parse.h
index 99b420c..dc1f3f9 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -284,4 +284,28 @@ char *nv_get_attribute_name(const int attr);
char *nv_standardize_screen_name(const char *display_name, int screen);
+
+
+/* General parsing functions */
+
+const char *parse_skip_whitespace(const char *str);
+void parse_chop_whitespace(char *str);
+const char *parse_skip_integer(const char *str);
+const char *parse_read_integer(const char *str, int *num);
+const char *parse_read_integer_pair(const char *str,
+ const char separator, int *a, int *b);
+const char *parse_read_name(const char *str, char **name, char term);
+const char *parse_read_display_name(const char *str, unsigned int *mask);
+int parse_read_float_range(char *str, float *min, float *max);
+
+
+/* Token parsing functions */
+
+typedef void (* apply_token_func)(char *token, char *value, void *data);
+
+int parse_token_value_pairs(const char *str, apply_token_func func,
+ void *data);
+
+
+
#endif /* __PARSE_H__ */
diff --git a/src/query-assign.c b/src/query-assign.c
index 93d9748..2b30e25 100644
--- a/src/query-assign.c
+++ b/src/query-assign.c
@@ -37,6 +37,8 @@
#include "msg.h"
#include "query-assign.h"
+extern int __verbosity;
+
/* local prototypes */
static int process_attribute_queries(int, char**, const char *);
@@ -92,7 +94,7 @@ CtrlHandles *nv_alloc_ctrl_handles(const char *display)
ReturnStatus status;
CtrlHandles *h, *pQueryHandle = NULL;
NvCtrlAttributeHandle *handle;
- int target, i, j, val, d, len;
+ int target, i, j, val, d, c, len;
char *tmp;
/* allocate the CtrlHandles struct */
@@ -234,11 +236,23 @@ CtrlHandles *nv_alloc_ctrl_handles(const char *display)
NvCtrlAttributesStrError(status));
d = 0;
}
+
+ status = NvCtrlGetAttribute(handle,
+ NV_CTRL_CONNECTED_DISPLAYS, &c);
+
+ if (status != NvCtrlSuccess) {
+ nv_error_msg("Error querying connected displays on "
+ "%s %d (%s).", targetTypeTable[j].name, i,
+ NvCtrlAttributesStrError(status));
+ c = 0;
+ }
} else {
d = 0;
+ c = 0;
}
h->targets[target].t[i].d = d;
+ h->targets[target].t[i].c = c;
/*
* store this handle so that we can use it to query other
@@ -341,7 +355,8 @@ static int process_attribute_queries(int num, char **queries,
/* special case the target type queries */
- if (nv_strcasecmp(queries[query], "screens")) {
+ if (nv_strcasecmp(queries[query], "screens") ||
+ nv_strcasecmp(queries[query], "xscreens")) {
query_all_targets(display_name, X_SCREEN_TARGET);
continue;
}
@@ -882,6 +897,192 @@ static int query_all(const char *display_name)
/*
+ * print_target_display_connections() - Print a list of all the
+ * display devices connected to the given target (GPU/X Screen)
+ */
+
+static int print_target_display_connections(CtrlHandleTarget *t)
+{
+ unsigned int bit;
+ char *tmp_d_str, *name;
+ ReturnStatus status;
+ int plural;
+
+ if (t->c == 0) {
+ nv_msg(" ", "Is not connected to any display devices.");
+ nv_msg(NULL, "");
+ return NV_TRUE;
+ }
+
+ plural = (t->c & (t->c - 1)); /* Is more than one bit set? */
+
+ nv_msg(" ", "Is connected to the following display device%s:",
+ plural ? "s" : "");
+
+ for (bit = 1; bit; bit <<= 1) {
+ if (!(bit & t->c)) continue;
+
+ status =
+ NvCtrlGetStringDisplayAttribute(t->h, bit,
+ NV_CTRL_STRING_DISPLAY_DEVICE_NAME,
+ &name);
+ if (status != NvCtrlSuccess) name = strdup("Unknown");
+
+ tmp_d_str = display_device_mask_to_display_device_name(bit);
+ nv_msg(" ", "%s (%s: 0x%0.8X)", name, tmp_d_str, bit);
+
+ free(name);
+ free(tmp_d_str);
+ }
+ nv_msg(NULL, "");
+
+ return NV_TRUE;
+
+} /* print_target_display_connections() */
+
+
+
+/*
+ * get_vcsc_name() Returns the VCSC product name of the given
+ * VCSC target.
+ */
+
+static char * get_vcsc_name(NvCtrlAttributeHandle *h)
+{
+ char *product_name;
+ ReturnStatus status;
+
+ status = NvCtrlGetStringAttribute(h, NV_CTRL_STRING_VCSC_PRODUCT_NAME,
+ &product_name);
+
+ if (status != NvCtrlSuccess) return strdup("Unknown");
+
+ return product_name;
+
+} /* get_vcsc_name() */
+
+
+
+/*
+ * get_gpu_name() Returns the GPU product name of the given
+ * GPU target.
+ */
+
+static char * get_gpu_name(NvCtrlAttributeHandle *h)
+{
+ char *product_name;
+ ReturnStatus status;
+
+ status = NvCtrlGetStringAttribute(h, NV_CTRL_STRING_PRODUCT_NAME,
+ &product_name);
+
+ if (status != NvCtrlSuccess) return strdup("Unknown");
+
+ return product_name;
+
+} /* get_gpu_name() */
+
+
+
+/*
+ * print_target_connections() Prints a list of all targets connected
+ * to a given target using print_func if the connected targets require
+ * special handling.
+ */
+
+static int print_target_connections(CtrlHandles *h,
+ CtrlHandleTarget *t,
+ unsigned int attrib,
+ unsigned int target_index)
+{
+ int *pData;
+ int len, i;
+ ReturnStatus status;
+ char *product_name;
+ char *target_name;
+
+
+ /* Query the connected targets */
+
+ status =
+ NvCtrlGetBinaryAttribute(t->h, 0, attrib,
+ (unsigned char **) &pData,
+ &len);
+ if (status != NvCtrlSuccess) return NV_FALSE;
+
+ if (pData[0] == 0) {
+ nv_msg(" ", "Is not connected to any %s.",
+ targetTypeTable[target_index].name);
+ nv_msg(NULL, "");
+
+ XFree(pData);
+ return NV_TRUE;
+ }
+
+ nv_msg(" ", "Is connected to the following %s%s:",
+ targetTypeTable[target_index].name,
+ ((pData[0] > 1) ? "s" : ""));
+
+
+ /* List the connected targets */
+
+ for (i = 1; i <= pData[0]; i++) {
+
+ if (pData[i] >= 0 &&
+ pData[i] < h->targets[target_index].n) {
+
+ target_name = h->targets[target_index].t[ pData[i] ].name;
+
+ switch (target_index) {
+ case GPU_TARGET:
+ product_name =
+ get_gpu_name(h->targets[target_index].t[ pData[i] ].h);
+ break;
+
+ case VCSC_TARGET:
+ product_name =
+ get_vcsc_name(h->targets[target_index].t[ pData[i] ].h);
+ break;
+
+ case FRAMELOCK_TARGET:
+ case X_SCREEN_TARGET:
+ default:
+ product_name = NULL;
+ break;
+ }
+
+ } else {
+ target_name = NULL;
+ product_name = NULL;
+ }
+
+ if (!target_name) {
+ nv_msg(" ", "[?] Unknown %s",
+ targetTypeTable[target_index].name);
+
+ } else if (product_name) {
+ nv_msg(" ", "[%d] %s (%s)",
+ pData[i], target_name, product_name);
+
+ } else {
+ nv_msg(" ", "[%d] %s (%s %d)",
+ pData[i], target_name,
+ targetTypeTable[target_index].name,
+ pData[i]);
+ }
+
+ free(product_name);
+ }
+ nv_msg(NULL, "");
+
+ XFree(pData);
+ return NV_TRUE;
+
+} /* print_target_connections() */
+
+
+
+/*
* query_all_targets() - print a list of all the targets (of the
* specified type) accessible via the Display connection.
*/
@@ -987,6 +1188,48 @@ static int query_all_targets(const char *display_name, const int target_index)
nv_msg(NULL, "");
free(product_name);
+
+ /* Print connectivity information */
+ if (__verbosity >= VERBOSITY_ALL) {
+ if (targetTypeTable[table_index].uses_display_devices) {
+ print_target_display_connections(t);
+ }
+
+ switch (target_index) {
+ case GPU_TARGET:
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU,
+ X_SCREEN_TARGET);
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU,
+ FRAMELOCK_TARGET);
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU,
+ VCSC_TARGET);
+ break;
+
+ case X_SCREEN_TARGET:
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN,
+ GPU_TARGET);
+ break;
+
+ case FRAMELOCK_TARGET:
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK,
+ GPU_TARGET);
+ break;
+
+ case VCSC_TARGET:
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_GPUS_USING_VCSC,
+ GPU_TARGET);
+ break;
+
+ default:
+ break;
+ }
+ }
}
nv_free_ctrl_handles(h);
@@ -1443,10 +1686,10 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h,
continue;
}
} else 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);
+ nv_warning_msg("The attribute '%s' specified %s cannot be "
+ "assigned; frame lock sync is currently "
+ "enabled on %s.",
+ a->name, whence, t->name);
continue;
}
}
diff --git a/src/query-assign.h b/src/query-assign.h
index 38ee72f..be359dc 100644
--- a/src/query-assign.h
+++ b/src/query-assign.h
@@ -47,6 +47,7 @@
typedef struct {
NvCtrlAttributeHandle *h; /* handle for this target */
uint32 d; /* display device mask for this target */
+ uint32 c; /* Connected display device mask for target */
char *name; /* name for this target */
} CtrlHandleTarget;