diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:59 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:28:59 -0800 |
commit | bb33b26f8d104cb8c0acbff21d1f2b4638d81f20 (patch) | |
tree | 46d6c65cc2f2f2fc28cec5d20c89b7d2e3590f2c | |
parent | 818140c39f7818755070e3b853956b818c842f2e (diff) |
100.14.03100.14.03
41 files changed, 5434 insertions, 3205 deletions
@@ -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 Binary files differindex 1aae24f..2c0a0e0 100644 --- a/src/libXNVCtrl/libXNVCtrl.a +++ b/src/libXNVCtrl/libXNVCtrl.a diff --git a/src/libXNVCtrl/nv_control.h b/src/libXNVCtrl/nv_control.h index 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; |