diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2013-10-04 08:47:45 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2013-10-04 08:47:45 -0700 |
commit | db3b5f655464386838d0c5859cddaf6c4f812979 (patch) | |
tree | d0b3a4e3f065eea69098c1f9e931914cdecdaf67 | |
parent | 2e80e4fdc20e051090289e4b32d713a7c4f7e14c (diff) |
331.13331.13
49 files changed, 3123 insertions, 2410 deletions
diff --git a/doc/version.mk b/doc/version.mk index 8a89afe..2abb57a 100644 --- a/doc/version.mk +++ b/doc/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 325.15 +NVIDIA_VERSION = 331.13 diff --git a/samples/nv-control-dpy.c b/samples/nv-control-dpy.c index 4371270..437cea1 100644 --- a/samples/nv-control-dpy.c +++ b/samples/nv-control-dpy.c @@ -45,7 +45,6 @@ static char *display_device_name(int mask); static unsigned int display_device_mask(char *str); static char *remove_whitespace(char *str); -static int count_bits(unsigned int mask); static void parse_mode_string(char *modeString, char **modeName, unsigned int *mask); static char *find_modeline(char *modeString, char *pModeLines, @@ -1096,158 +1095,6 @@ int main(int argc, char *argv[]) } } } - - - /* - * demonstrate how to programmatically transition into TwinView - * using NV-CONTROL and XRandR; the process is roughly: - * - * - probe for new display devices - * - * - if we found any new display devices, create a mode pool for - * the new display devices - * - * - associate any new display devices to the X screen, so that - * they are available for MetaMode assignment. - * - * - add a new MetaMode - * - * We have skipped error checking, and checking for things like if - * we are already using multiple display devices, but this gives - * the general idea. - */ - - else if (strcmp(argv[1], "--dynamic-twinview") == 0) { - - char *pOut; - int id; - - /* - * first, probe for new display devices; while - * NV_CTRL_CONNECTED_DISPLAYS reports what the NVIDIA X driver - * believes is currently connected to the GPU, - * NV_CTRL_PROBE_DISPLAYS forces the driver to redetect what - * is connected. - */ - - XNVCTRLQueryAttribute(dpy, - screen, - 0, - NV_CTRL_PROBE_DISPLAYS, - &display_devices); - - /* - * if we don't have atleast two display devices, there is - * nothing to do - */ - - printf("probed display device mask: 0x%08x\n\n", display_devices); - - if (count_bits(display_devices) < 2) { - printf("only one display device found; cannot enable " - "TwinView.\n\n"); - return 1; - } - - - /* - * next, make sure all display devices have a modepool; a more - * sophisticated client could use - * NV_CTRL_BINARY_DATA_MODELINES to query if a pool of - * modelines already exist on each display device we care - * about. - */ - - for (mask = 1; mask < (1 << 24); mask <<= 1) { - - if (!(display_devices & mask)) continue; - - XNVCTRLStringOperation(dpy, - NV_CTRL_TARGET_TYPE_X_SCREEN, - screen, - mask, - NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL, - NULL, - NULL); - } - - printf("all display devices should now have a mode pool.\n\n"); - - - /* - * associate all the probed display devices to the X screen; - * this makes the display devices available for MetaMode - * assignment - */ - - ret = - XNVCTRLSetAttributeAndGetStatus(dpy, - screen, - 0, - NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, - display_devices); - - if (!ret) { - printf("unable to assign the associated display devices to " - "0x%08x.\n\n", display_devices); - return 1; - } - - printf("associated display devices 0x%08x.\n\n", display_devices); - - - /* - * next, we add a new MetaMode; a more sophisticated client - * would actually select a modeline from - * NV_CTRL_BINARY_DATA_MODELINES on each display device, but - * for demonstration purposes, we assume that - * "nvidia-auto-select" is a valid mode on each display - * device. - */ - - pOut = NULL; - - ret = XNVCTRLStringOperation(dpy, - NV_CTRL_TARGET_TYPE_X_SCREEN, - screen, - 0, - NV_CTRL_STRING_OPERATION_ADD_METAMODE, - "nvidia-auto-select, nvidia-auto-select", - &pOut); - - if (!ret || !pOut) { - printf("failed to add MetaMode; this may be because the MetaMode " - "already exists for this X screen.\n\n"); - return 1; - } - - /* - * retrieve the id of the added MetaMode from the return - * string; a more sophisticated client should do actual - * parsing of the returned string, which is defined to be a - * comma-separated list of "token=value" pairs as output. - * Currently, the only output token is "id", which indicates - * the id that was assigned to the MetaMode. - */ - - sscanf(pOut, "id=%d", &id); - - XFree(pOut); - - - /* - * we have added a new MetaMode for this X screen, and we know - * its id. The last step is to use the XRandR extension to - * switch to this mode; see the Xrandr(3) manpage for details. - * - * For demonstration purposes, just use the xrandr commandline - * utility to switch to the mode with the refreshrate that - * matches the id. - */ - - printf("The id of the new MetaMode is %d; use xrandr to " - "switch to it.\n\n", id); - } /* Display all names each display device goes by @@ -1382,9 +1229,6 @@ int main(int argc, char *argv[]) printf(" --print-used-modelines: print the modeline for each display " "device for each MetaMode on the X screen.\n\n"); - printf(" --dynamic-twinview: demonstrates the process of " - "dynamically transitioning into TwinView.\n\n"); - printf(" --print-display-names: print all the names associated with " "each display device on the server\n\n"); } @@ -1511,25 +1355,6 @@ static char *remove_whitespace(char *str) /* - * count the number of bits set in the specified mask - */ - -static int count_bits(unsigned int mask) -{ - int n = 0; - - while (mask) { - n++; - mask &= (mask - 1) ; - } - - return n; - -} /* count_bits() */ - - - -/* * parse_mode_string() - extract the modeName and the display device * mask for the per-display device MetaMode string in 'modeString' */ diff --git a/samples/nv-control-events.c b/samples/nv-control-events.c index 1b34b44..b9711a0 100644 --- a/samples/nv-control-events.c +++ b/samples/nv-control-events.c @@ -606,13 +606,6 @@ static AttrEntry attr_table[] = { MAKE_ENTRY(NV_CTRL_MAX_DISPLAYS), MAKE_ENTRY(NV_CTRL_DYNAMIC_TWINVIEW), MAKE_ENTRY(NV_CTRL_MULTIGPU_DISPLAY_OWNER), - MAKE_ENTRY(NV_CTRL_GPU_SCALING), - MAKE_ENTRY(NV_CTRL_FRONTEND_RESOLUTION), - MAKE_ENTRY(NV_CTRL_BACKEND_RESOLUTION), - MAKE_ENTRY(NV_CTRL_FLATPANEL_NATIVE_RESOLUTION), - MAKE_ENTRY(NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION), - MAKE_ENTRY(NV_CTRL_GPU_SCALING_ACTIVE), - MAKE_ENTRY(NV_CTRL_DFP_SCALING_ACTIVE), MAKE_ENTRY(NV_CTRL_FSAA_APPLICATION_ENHANCED), MAKE_ENTRY(NV_CTRL_FRAMELOCK_SYNC_RATE_4), MAKE_ENTRY(NV_CTRL_GVO_LOCK_OWNER), @@ -731,5 +724,23 @@ static AttrEntry attr_table[] = { MAKE_ENTRY(NV_CTRL_GVO_ANC_PARITY_COMPUTATION), MAKE_ENTRY(NV_CTRL_3D_VISION_PRO_GLASSES_PAIR_EVENT), MAKE_ENTRY(NV_CTRL_3D_VISION_PRO_GLASSES_UNPAIR_EVENT), + MAKE_ENTRY(NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH), + MAKE_ENTRY(NV_CTRL_GPU_PCIE_CURRENT_LINK_SPEED), + MAKE_ENTRY(NV_CTRL_GVO_AUDIO_BLANKING), + MAKE_ENTRY(NV_CTRL_CURRENT_METAMODE_ID), + MAKE_ENTRY(NV_CTRL_DISPLAY_ENABLED), + MAKE_ENTRY(NV_CTRL_FRAMELOCK_INCOMING_HOUSE_SYNC_RATE), + MAKE_ENTRY(NV_CTRL_FXAA), + MAKE_ENTRY(NV_CTRL_DISPLAY_RANDR_OUTPUT_ID), + MAKE_ENTRY(NV_CTRL_FRAMELOCK_DISPLAY_CONFIG), + MAKE_ENTRY(NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY), + MAKE_ENTRY(NV_CTRL_USED_DEDICATED_GPU_MEMORY), + MAKE_ENTRY(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE), + MAKE_ENTRY(NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT), + MAKE_ENTRY(NV_CTRL_DPY_HDMI_3D), + MAKE_ENTRY(NV_CTRL_BASE_MOSAIC), + MAKE_ENTRY(NV_CTRL_MULTIGPU_MASTER_POSSIBLE), + MAKE_ENTRY(NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE), + MAKE_ENTRY(NV_CTRL_XV_SYNC_TO_DISPLAY_ID), { -1, NULL, NULL } }; diff --git a/samples/nv-control-info.c b/samples/nv-control-info.c index 913c246..ae92d18 100644 --- a/samples/nv-control-info.c +++ b/samples/nv-control-info.c @@ -189,13 +189,6 @@ static AttrEntry attr_int_table[] = { MAKE_ENTRY(NV_CTRL_MAX_DISPLAYS), MAKE_ENTRY(NV_CTRL_DYNAMIC_TWINVIEW), MAKE_ENTRY(NV_CTRL_MULTIGPU_DISPLAY_OWNER), - MAKE_ENTRY(NV_CTRL_GPU_SCALING), - MAKE_ENTRY(NV_CTRL_FRONTEND_RESOLUTION), - MAKE_ENTRY(NV_CTRL_BACKEND_RESOLUTION), - MAKE_ENTRY(NV_CTRL_FLATPANEL_NATIVE_RESOLUTION), - MAKE_ENTRY(NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION), - MAKE_ENTRY(NV_CTRL_GPU_SCALING_ACTIVE), - MAKE_ENTRY(NV_CTRL_DFP_SCALING_ACTIVE), MAKE_ENTRY(NV_CTRL_FSAA_APPLICATION_ENHANCED), MAKE_ENTRY(NV_CTRL_FRAMELOCK_SYNC_RATE_4), MAKE_ENTRY(NV_CTRL_GVO_LOCK_OWNER), diff --git a/samples/nv-control-targets.c b/samples/nv-control-targets.c index 3d24fb4..9d3bc6a 100644 --- a/samples/nv-control-targets.c +++ b/samples/nv-control-targets.c @@ -41,44 +41,18 @@ -/* - * display_device_name() - return the display device name corresponding - * to the display device mask. - */ - -static char *display_device_name(int mask) +static void print_display_device_target_indices(const int *pData) { - switch (mask) { - case (1 << 0): return "CRT-0"; break; - case (1 << 1): return "CRT-1"; break; - case (1 << 2): return "CRT-2"; break; - case (1 << 3): return "CRT-3"; break; - case (1 << 4): return "CRT-4"; break; - case (1 << 5): return "CRT-5"; break; - case (1 << 6): return "CRT-6"; break; - case (1 << 7): return "CRT-7"; break; - - case (1 << 8): return "TV-0"; break; - case (1 << 9): return "TV-1"; break; - case (1 << 10): return "TV-2"; break; - case (1 << 11): return "TV-3"; break; - case (1 << 12): return "TV-4"; break; - case (1 << 13): return "TV-5"; break; - case (1 << 14): return "TV-6"; break; - case (1 << 15): return "TV-7"; break; - - case (1 << 16): return "DFP-0"; break; - case (1 << 17): return "DFP-1"; break; - case (1 << 18): return "DFP-2"; break; - case (1 << 19): return "DFP-3"; break; - case (1 << 20): return "DFP-4"; break; - case (1 << 21): return "DFP-5"; break; - case (1 << 22): return "DFP-6"; break; - case (1 << 23): return "DFP-7"; break; - default: return "Unknown"; - } -} /* display_device_name() */ + int i, first = 1; + for (i = 1; i <= pData[0]; i++) { + if (!first) { + printf(", "); + } + first = 0; + printf("DPY-%d", pData[i]); + } +} int main(int argc, char *argv[]) @@ -94,7 +68,6 @@ int main(int argc, char *argv[]) int num_coolers; int num_thermal_sensors; int gpu, screen; - int display_devices, mask; int *pData; int len, j; char *str; @@ -156,6 +129,26 @@ int main(int argc, char *argv[]) printf(" number of X Screens: %d\n", num_screens); + /* Get the number of display devices in the system */ + + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_GPU, + 0, // target_id + 0, // display_mask + NV_CTRL_BINARY_DATA_DISPLAY_TARGETS, + (unsigned char **) &pData, + &len); + if (!ret) { + fprintf(stderr, "Failed to query number of display devices\n"); + return 1; + } + printf(" number of display devices: %d (", pData[0]); + print_display_device_target_indices(pData); + printf(")\n"); + XFree(pData); + + /* Get the number of Frame Lock devices in the system */ ret = XNVCTRLQueryTargetCount(dpy, NV_CTRL_TARGET_TYPE_FRAMELOCK, @@ -221,6 +214,8 @@ int main(int argc, char *argv[]) for (gpu = 0; gpu < num_gpus; gpu++) { + int *pDisplayData; + printf("\n\n"); printf("GPU %d information:\n", gpu); @@ -256,35 +251,22 @@ int main(int argc, char *argv[]) /* Connected Display Devices on GPU */ - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_CONNECTED_DISPLAYS, - &display_devices); + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_GPU, + gpu, // target_id + 0, // display_mask + NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, + (unsigned char **) &pDisplayData, + &len); if (!ret) { fprintf(stderr, "Failed to query connected displays\n"); return 1; } - printf(" Display Device Mask (Connected) : 0x%08x\n", - display_devices); - - - /* Enabled Display Devices on GPU */ - - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_GPU, - gpu, // target_id - 0, // display_mask - NV_CTRL_ENABLED_DISPLAYS, - &display_devices); - if (!ret) { - fprintf(stderr, "Failed to query enabled displays\n"); - return 1; - } - printf(" Display Device Mask (Enabled) : 0x%08x\n", - display_devices); - + printf(" Connected Display Devices : "); + print_display_device_target_indices(pDisplayData); + XFree(pDisplayData); + printf("\n"); /* X Screens driven by this GPU */ @@ -307,64 +289,47 @@ int main(int argc, char *argv[]) for (j = 1; j <= pData[0]; j++) { screen = pData[j]; - + printf("\n"); printf(" X Screen %d information:\n", screen); + /* Assigned Display Devices on X Screen */ - /* Connected Display Devices on X Screen */ - - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_X_SCREEN, - screen, // target_id - 0, // display_mask - NV_CTRL_CONNECTED_DISPLAYS, - &display_devices); + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, // target_id + 0, // display_mask + NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN, + (unsigned char **) &pDisplayData, + &len); if (!ret) { - fprintf(stderr, "Failed to query connected displays\n"); - XFree(pData); + fprintf(stderr, "Failed to query assigned displays\n"); return 1; } - printf(" Display Device Mask (Connected) : 0x%08x\n", - display_devices); - + printf(" Assigned Display Devices : "); + print_display_device_target_indices(pDisplayData); + XFree(pDisplayData); + printf("\n"); /* Enabled Display Devices on X Screen */ - ret = XNVCTRLQueryTargetAttribute(dpy, - NV_CTRL_TARGET_TYPE_X_SCREEN, - screen, // target_id - 0, // display_mask - NV_CTRL_ENABLED_DISPLAYS, - &display_devices); + ret = XNVCTRLQueryTargetBinaryData + (dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, // target_id + 0, // display_mask + NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN, + (unsigned char **) &pDisplayData, + &len); if (!ret) { - fprintf(stderr, "Failed to query enabled displays\n"); - XFree(pData); + fprintf(stderr, "Failed to query assigned displays\n"); return 1; } - printf(" Display Device Mask (Enabled) : 0x%08x\n", - display_devices); - - - /* List all display devices on this X Screen */ - - for (mask = 1; mask < (1 << 24); mask <<= 1) { - if (!(display_devices & mask)) { - continue; - } - - ret = XNVCTRLQueryTargetStringAttribute - (dpy, - NV_CTRL_TARGET_TYPE_X_SCREEN, - screen, // target_id - mask, // display_mask - NV_CTRL_STRING_DISPLAY_DEVICE_NAME, - &str); - printf(" Display Device (0x%08x) : %s - '%s'\n", - mask, - display_device_name(mask), - str); - } + printf(" Enabled Display Devices : "); + print_display_device_target_indices(pDisplayData); + XFree(pDisplayData); + printf("\n"); } XFree(pData); } diff --git a/samples/nv-control-warpblend.h b/samples/nv-control-warpblend.h index 36d36dc..4550e06 100644 --- a/samples/nv-control-warpblend.h +++ b/samples/nv-control-warpblend.h @@ -78,7 +78,7 @@ * XNVCTRLSetScanoutWarping * * xDpy: valid X display connection - * screenId: X protocol screen number; typically 0 in "TwinView" or "Mosaic" + * screenId: X protocol screen number * nvDpyId: NV-CONTROL display target index; can be enumerated with the * NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN request. * warpDatatype: NV_CTRL_WARP_DATA_TYPE_MESH_TRIANGLESTRIP_XYUVRQ or @@ -107,7 +107,7 @@ XNVCTRLSetScanoutWarping( * XNVCTRLSetScanout[Intensity/Offset] * * xDpy: valid X display connection - * screenId: X protocol screen number; typically 0 in "TwinView" or "Mosaic" + * screenId: X protocol screen number * nvDpyId: NV-CONTROL display target index; can be enumerated with the * NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN request. * pixmap: XID naming a valid Pixmap to be used as Intensity/Offset data. diff --git a/samples/version.mk b/samples/version.mk index 8a89afe..2abb57a 100644 --- a/samples/version.mk +++ b/samples/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 325.15 +NVIDIA_VERSION = 331.13 diff --git a/src/XF86Config-parser/Flags.c b/src/XF86Config-parser/Flags.c index 6eadae2..55720e0 100644 --- a/src/XF86Config-parser/Flags.c +++ b/src/XF86Config-parser/Flags.c @@ -59,6 +59,7 @@ #include "xf86tokens.h" #include "Configint.h" #include <math.h> +#include "common-utils.h" extern LexRec val; @@ -504,3 +505,87 @@ xconfigPrintOptionList(FILE *fp, XConfigOptionPtr list, int tabs) list = list->next; } } + +/* + * Determines if the Composite extension should be disabled or not. + * + * - If the extension can be enabled, this function returns NULL. + * + * - If the extension should be disabled, this function returns a + * string that lists the conflicting options that are enabled. + */ + +const char *xconfigValidateComposite(XConfigPtr config, + GenerateOptions *gop, + int composite_specified, + int xinerama_enabled, + int depth, + int overlay_enabled, + int cioverlay_enabled, + int ubb_enabled, + int stereo_enabled) +{ + int i, n, disable_composite; + static char err_str[256]; + int size = 256; + char *s; + + const struct { + const char *name; + int value; + + } composite_incompatible_options[] = { + { "Xinerama", xinerama_enabled }, + { "Overlay", overlay_enabled }, + { "CIOverlay", cioverlay_enabled }, + { "UBB", ubb_enabled }, + { "Stereo", stereo_enabled }, + }; + + /* + * We need to be careful to only set the option value if the X + * server is going to recognize the Extension section and the + * composite option. We guess whether the server will recognize + * the option: if get_xserver_in_use() thinks the X server + * supports the "Composite" extension, or the current config + * already has an extension section, or the user specified the + * composite option. + */ + if (!gop->supports_extension_section && + !config->extensions && + !composite_specified) { + /* Composite can't be set in X config, so bail */ + return NULL; + } + + disable_composite = FALSE; + s = err_str; + n = 0; + err_str[0] = '\0'; + + for (i = 0; i < ARRAY_LEN(composite_incompatible_options); i++) { + int value = composite_incompatible_options[i].value; + const char *name = composite_incompatible_options[i].name; + int wrote; + + if (value) { + disable_composite = TRUE; + n++; + + wrote = snprintf(s, size, "%s%s", (n > 1) ? " or " : "", name); + if (wrote <= 0) { + break; + } + size -= wrote; + s += wrote; + } + } + + /* Special case checking for depth 8 */ + + if (depth <= 8) { + snprintf(s, size, "%sdepth=8", (n > 1) ? " or " : ""); + } + + return disable_composite ? err_str : NULL; +} diff --git a/src/XF86Config-parser/xf86Parser.h b/src/XF86Config-parser/xf86Parser.h index 09fccad..1135ffd 100644 --- a/src/XF86Config-parser/xf86Parser.h +++ b/src/XF86Config-parser/xf86Parser.h @@ -762,6 +762,15 @@ void xconfigGenerateLoadDefaultOptions(GenerateOptions *gop); void xconfigGetXServerInUse(GenerateOptions *gop); +const char *xconfigValidateComposite(XConfigPtr config, + GenerateOptions *gop, + int composite_enabled, + int xinerama_enabled, + int depth, + int overlay_enabled, + int cioverlay_enabled, + int ubb_enabled, + int stereo); /* * check (and update, if necessary) the inputs in the specified layout diff --git a/src/app-profiles.c b/src/app-profiles.c index b6f98cc..a56bcbc 100644 --- a/src/app-profiles.c +++ b/src/app-profiles.c @@ -866,10 +866,19 @@ static int file_in_search_path(AppProfileConfig *config, const char *filename) return FALSE; } +// Print an error message and optionally capture the error string for later use +// Note: this assumes fmt is a string literal! +#define LOG_ERROR(error_str, fmt, ...) do { \ + if (error_str) { \ + nv_append_sprintf(error_str, fmt "\n", __VA_ARGS__); \ + } \ + nv_error_msg(fmt, __VA_ARGS__); \ +} while (0) + /* * Creates parent directories as needed, similarly to "mkdir -p" */ -static int nv_mkdirp(const char *dirname) +static int nv_mkdirp(const char *dirname, char **error_str) { int ret = 0; char *parent_name; @@ -881,8 +890,10 @@ static int nv_mkdirp(const char *dirname) parent_name = nvstrndup(dirname, next - dirname); ret = mkdir(parent_name, 0777); if ((ret < 0) && (errno != EEXIST)) { - nv_error_msg("Could not create parent directory \"%s\" for full path \"%s\" (%s)", - parent_name, dirname, strerror(errno)); + LOG_ERROR(error_str, + "Could not create parent directory \"%s\" " + "for full path \"%s\" (%s)", + parent_name, dirname, strerror(errno)); free(parent_name); return ret; } @@ -893,15 +904,15 @@ static int nv_mkdirp(const char *dirname) ret = mkdir(dirname, 0777); if (ret < 0) { if (errno != EEXIST) { - nv_error_msg("Could not create directory \"%s\" (%s)", - dirname, strerror(errno)); + LOG_ERROR(error_str, "Could not create directory \"%s\" (%s)", + dirname, strerror(errno)); } else { ret = stat(dirname, &stat_buf); if (ret == 0) { if (!S_ISDIR(stat_buf.st_mode)) { - nv_error_msg("Could not create directory \"%s\" (file " - "exists, but not as a directory)", - dirname); + LOG_ERROR(error_str, "Could not create directory \"%s\" " + "(file exists, but not as a directory)", + dirname); ret = -1; } } @@ -941,16 +952,17 @@ char *nv_app_profile_config_get_backup_filename(AppProfileConfig *config, const } static int app_profile_config_backup_file(AppProfileConfig *config, - const char *filename) + const char *filename, + char **error_str) { int ret; char *backup_name = nv_app_profile_config_get_backup_filename(config, filename); char *backup_dirname = nv_dirname(backup_name); - ret = nv_mkdirp(backup_dirname); + ret = nv_mkdirp(backup_dirname, error_str); if (ret < 0) { - nv_error_msg("Could not create backup directory \"%s\" (%s)", - backup_name, strerror(errno)); + LOG_ERROR(error_str, "Could not create backup directory \"%s\" (%s)", + backup_name, strerror(errno)); goto done; } @@ -960,8 +972,8 @@ static int app_profile_config_backup_file(AppProfileConfig *config, // Clear the error; the file does not exist ret = 0; } else { - nv_error_msg("Could not rename file \"%s\" to \"%s\" for backup (%s)", - filename, backup_name, strerror(errno)); + LOG_ERROR(error_str, "Could not rename file \"%s\" to \"%s\" for backup (%s)", + filename, backup_name, strerror(errno)); } } @@ -973,10 +985,12 @@ done: return ret; } + static int app_profile_config_save_updates_to_file(AppProfileConfig *config, const char *filename, const char *update_text, - int backup) + int backup, + char **error_str) { int file_is_new = FALSE; struct stat stat_buf; @@ -987,7 +1001,8 @@ static int app_profile_config_save_updates_to_file(AppProfileConfig *config, ret = stat(filename, &stat_buf); if ((ret < 0) && (errno != ENOENT)) { - nv_error_msg("Could not stat file \"%s\" (%s)", filename, strerror(errno)); + LOG_ERROR(error_str, "Could not stat file \"%s\" (%s)", + filename, strerror(errno)); goto done; } else if ((ret < 0) && (errno == ENOENT)) { file_is_new = TRUE; @@ -998,11 +1013,12 @@ static int app_profile_config_save_updates_to_file(AppProfileConfig *config, // This file is in a directory in the search path ret = stat(dirname, &stat_buf); if ((ret < 0) && (errno != ENOENT)) { - nv_error_msg("Could not stat file \"%s\" (%s)", dirname, strerror(errno)); + LOG_ERROR(error_str, "Could not stat file \"%s\" (%s)", + dirname, strerror(errno)); goto done; } else if ((ret < 0) && errno == ENOENT) { // Attempt to create the directory in the search path - ret = nv_mkdirp(dirname); + ret = nv_mkdirp(dirname, error_str); if (ret < 0) { goto done; } @@ -1010,24 +1026,27 @@ static int app_profile_config_save_updates_to_file(AppProfileConfig *config, // If the search path entry is currently a regular file, // unlink it and create a directory instead if (backup) { - ret = app_profile_config_backup_file(config, dirname); + ret = app_profile_config_backup_file(config, dirname, + error_str); if (ret < 0) { goto done; } } ret = unlink(dirname); if (ret < 0) { - nv_error_msg("Could not remove the file \"%s\" (%s)", dirname, strerror(errno)); + LOG_ERROR(error_str, + "Could not remove the file \"%s\" (%s)", + dirname, strerror(errno)); goto done; } - ret = nv_mkdirp(dirname); + ret = nv_mkdirp(dirname, error_str); if (ret < 0) { goto done; } } } else { // Attempt to create parent directories for this file - ret = nv_mkdirp(dirname); + ret = nv_mkdirp(dirname, error_str); if (ret < 0) { goto done; } @@ -1037,18 +1056,23 @@ static int app_profile_config_save_updates_to_file(AppProfileConfig *config, // but that seems a little dangerous. Instead, complain and bail out // here. ret = -1; - nv_error_msg("Refusing to write to file \"%s\" since it is not a regular file", filename); + LOG_ERROR(error_str, + "Refusing to write to file \"%s\" " + "since it is not a regular file", filename); + goto done; } if (!file_is_new && backup) { - ret = app_profile_config_backup_file(config, filename); + ret = app_profile_config_backup_file(config, filename, + error_str); if (ret < 0) { goto done; } } ret = open_and_stat(filename, "w", &fp, &stat_buf); if (ret < 0) { - nv_error_msg("Could not write to the file \"%s\" (%s)", filename, strerror(errno)); + LOG_ERROR(error_str, "Could not write to the file \"%s\" (%s)", + filename, strerror(errno)); goto done; } nv_info_msg("", "Writing to configuration file \"%s\"\n", filename); @@ -1060,24 +1084,44 @@ done: return ret; } -int nv_app_profile_config_save_updates(AppProfileConfig *config, json_t *updates, int backup) +int nv_app_profile_config_save_updates(AppProfileConfig *config, + json_t *updates, + int backup, + char **error_str) { json_t *update; const char *filename; const char *update_text; size_t i, size; int ret = 0; + int all_ret = 0; + + if (error_str) { + *error_str = NULL; + } - for (i = 0, size = json_array_size(updates); (ret == 0) && (i < size); i++) { + for (i = 0, size = json_array_size(updates); i < size; i++) { update = json_array_get(updates, i); filename = json_string_value(json_object_get(update, "filename")); update_text = json_string_value(json_object_get(update, "text")); - ret = app_profile_config_save_updates_to_file(config, filename, update_text, backup); + ret = app_profile_config_save_updates_to_file(config, + filename, + update_text, + backup, + error_str); + if (ret < 0) { + all_ret = -1; + } } - assert(ret <= 0); + assert(all_ret <= 0); - return ret; + // This asserts an error string is set iff we are returning an error + assert(!error_str || + (!(*error_str) && (all_ret == 0)) || + ((*error_str) && (all_ret < 0))); + + return all_ret; } AppProfileConfig *nv_app_profile_config_dup(AppProfileConfig *config) diff --git a/src/app-profiles.h b/src/app-profiles.h index fa74e58..6aa9de3 100644 --- a/src/app-profiles.h +++ b/src/app-profiles.h @@ -122,8 +122,12 @@ typedef struct AppProfileConfigRec { * backup indicates whether this should also make backups of the original files * before saving. * Returns 0 if successful, or a negative integer if an error was encountered. + * If error_str is non-NULL, *error_str is set to NULL on success, or a + * dynamically-allocated string if an error occurred. */ -int nv_app_profile_config_save_updates(AppProfileConfig *config, json_t *updates, int backup); +int nv_app_profile_config_save_updates(AppProfileConfig *config, + json_t *updates, int backup, + char **error_str); /* * Load an application profile configuration from disk, using a list of files specified by search_path. diff --git a/src/command-line.c b/src/command-line.c index 5638965..d884617 100644 --- a/src/command-line.c +++ b/src/command-line.c @@ -49,6 +49,7 @@ int __verbosity = VERBOSITY_DEFAULT; int __terse = NV_FALSE; int __display_device_string = NV_FALSE; int __verbosity_level_changed = NV_FALSE; +int __list_targets = NV_FALSE; /* * print_version() - print version information @@ -101,31 +102,45 @@ static void print_attribute_help(char *attr) if (show_desc) { nv_msg(NULL, "Attribute '%s':", entry->name); - if (entry->flags & NV_PARSER_TYPE_FRAMELOCK) + if (entry->flags & NV_PARSER_TYPE_FRAMELOCK) { nv_msg(NULL, " - Is Frame Lock attribute."); - if (entry->flags & NV_PARSER_TYPE_NO_CONFIG_WRITE) + } + if (entry->flags & NV_PARSER_TYPE_NO_CONFIG_WRITE) { nv_msg(NULL, " - Attribute is not written to the rc file."); - if (entry->flags & NV_PARSER_TYPE_GUI_ATTRIBUTE) + } + if (entry->flags & NV_PARSER_TYPE_GUI_ATTRIBUTE) { nv_msg(NULL, " - Is GUI attribute."); - if (entry->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) + } + if (entry->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { nv_msg(NULL, " - Attribute value is packed integer."); - if (entry->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY) + } + if (entry->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY) { nv_msg(NULL, " - Attribute value is a display mask."); - if (entry->flags & NV_PARSER_TYPE_NO_QUERY_ALL) + } + if (entry->flags & NV_PARSER_TYPE_NO_QUERY_ALL) { nv_msg(NULL, " - Attribute not queried in 'query all'."); - if (entry->flags & NV_PARSER_TYPE_NO_ZERO_VALUE) + } + if (entry->flags & NV_PARSER_TYPE_NO_ZERO_VALUE) { nv_msg(NULL, " - Attribute cannot be zero."); - if (entry->flags & NV_PARSER_TYPE_100Hz) + } + if (entry->flags & NV_PARSER_TYPE_100Hz) { nv_msg(NULL, " - Attribute value is in units of Centihertz (1/100Hz)."); - if (entry->flags & NV_PARSER_TYPE_1000Hz) + } + if (entry->flags & NV_PARSER_TYPE_1000Hz) { nv_msg(NULL, " - Attribute value is in units of Milihertz (1/1000 Hz)."); - if (entry->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) + } + if (entry->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { nv_msg(NULL, " - Attribute value is string."); - if (entry->flags & NV_PARSER_TYPE_SDI) + } + if (entry->flags & NV_PARSER_TYPE_SDI) { nv_msg(NULL, " - Is SDI attribute."); - if (entry->flags & NV_PARSER_TYPE_VALUE_IS_SWITCH_DISPLAY) + } + if (entry->flags & NV_PARSER_TYPE_VALUE_IS_SWITCH_DISPLAY) { nv_msg(NULL, " - Attribute value is switch display."); - + } + if (entry->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID) { + nv_msg(NULL, " - Attribute value is a display id."); + } nv_msg(TAB, "%s", entry->desc); nv_msg(NULL, ""); } else { @@ -253,6 +268,7 @@ Options *parse_command_line(int argc, char *argv[], char *dpy, case 't': __terse = NV_TRUE; break; case 'd': __display_device_string = NV_TRUE; break; case 'e': print_attribute_help(strval); exit(0); break; + case 'L': __list_targets = NV_TRUE; break; default: nv_error_msg("Invalid commandline, please run `%s --help` " "for usage information.\n", argv[0]); diff --git a/src/common-utils/common-utils.c b/src/common-utils/common-utils.c index b2958a7..9bd349e 100644 --- a/src/common-utils/common-utils.c +++ b/src/common-utils/common-utils.c @@ -235,6 +235,28 @@ char *nvasprintf(const char *fmt, ...) } /* nvasprintf() */ +/* + * nv_append_sprintf() - similar to glib's g_string_append_printf(), except + * instead of operating on a GString it operates on a (char **). Appends a + * formatted string to the end of the dynamically-allocated string pointed to by + * *buf (or the empty string if *buf is NULL), potentially reallocating the + * string in the process. This function only returns on succcess. + */ +void nv_append_sprintf(char **buf, const char *fmt, ...) +{ + char *prefix, *suffix; + + prefix = *buf; + NV_VSNPRINTF(suffix, fmt); + + if (!prefix) { + *buf = suffix; + } else { + *buf = nvstrcat(prefix, suffix, NULL); + free(prefix); + free(suffix); + } +} /* @@ -413,7 +435,7 @@ TextRows *nv_format_text_rows(const char *prefix, } } - /* look for any newline inbetween a and b, and move b to it */ + /* look for any newline between a and b, and move b to it */ for (c = a; c < b; c++) if (*c == '\n') { b = c; break; } diff --git a/src/common-utils/common-utils.h b/src/common-utils/common-utils.h index 92c57dd..3bc934f 100644 --- a/src/common-utils/common-utils.h +++ b/src/common-utils/common-utils.h @@ -72,6 +72,7 @@ char *nvstrtolower(char *s); char *nvstrtoupper(char *s); char *nvstrchrnul(char *s, int c); char *nvasprintf(const char *fmt, ...) NV_ATTRIBUTE_PRINTF(1, 2); +void nv_append_sprintf(char **buf, const char *fmt, ...) NV_ATTRIBUTE_PRINTF(2, 3); void nvfree(void *s); char *tilde_expansion(const char *str); @@ -184,4 +185,20 @@ static NV_INLINE uint64_t nv_encode_version(unsigned int major, #define NV_VERSION4(major, minor, micro, nano) \ nv_encode_version(major, minor, micro, nano) +/* + * Helper enum that can be used for boolean values that might or might not be + * set. Care should be taken to avoid simple boolean testing, as a value of + * NV_OPTIONAL_BOOL_DEFAULT would evaluate as true. + * + * The user is responsible for unconditionally initializing the default value of + * any such booleans to NV_OPTIONAL_BOOL_DEFAULT, before any code path that + * might optionally set their values is executed. + */ + +typedef enum { + NV_OPTIONAL_BOOL_DEFAULT = -1, + NV_OPTIONAL_BOOL_FALSE = FALSE, + NV_OPTIONAL_BOOL_TRUE = TRUE +} NVOptionalBool; + #endif /* __COMMON_UTILS_H__ */ diff --git a/src/common-utils/gen-manpage-opts-helper.c b/src/common-utils/gen-manpage-opts-helper.c index d2abb1c..532015d 100644 --- a/src/common-utils/gen-manpage-opts-helper.c +++ b/src/common-utils/gen-manpage-opts-helper.c @@ -89,7 +89,7 @@ static void print_option(const NVGetoptOption *o) * '^' : toggles bold on and off * '-' : is backslashified: "\-" * - * Whitespace is omited when italics or bold is on + * Whitespace is omitted when italics or bold is on */ italics = 0; diff --git a/src/common-utils/nvgetopt.h b/src/common-utils/nvgetopt.h index 5847546..fc735ee 100644 --- a/src/common-utils/nvgetopt.h +++ b/src/common-utils/nvgetopt.h @@ -34,8 +34,8 @@ /* * indicates that the option is a boolean value; the presence of the - * option will be interpretted as a TRUE value; if the option is - * prepended with '--no-', the option will be interpretted as a FALSE + * option will be interpreted as a TRUE value; if the option is + * prepended with '--no-', the option will be interpreted as a FALSE * value. On success, nvgetopt will return the parsed boolean value * through 'boolval'. */ diff --git a/src/config-file.c b/src/config-file.c index bb0b691..9478467 100644 --- a/src/config-file.c +++ b/src/config-file.c @@ -217,14 +217,14 @@ int nv_read_config_file(const char *file, const char *display_name, int nv_write_config_file(const char *filename, CtrlHandles *h, ParsedAttribute *p, ConfigProperties *conf) { - int screen, ret, entry, bit, val, display, randr_gamma_available; + int screen, ret, entry, val, display, randr_gamma_available; FILE *stream; time_t now; ReturnStatus status; + NVCTRLAttributePermissionsRec perms; NVCTRLAttributeValidValuesRec valid; - uint32 mask; CtrlHandleTarget *t; - char *tmp_d_str, *prefix, scratch[4]; + char *prefix, scratch[4]; const char *tmp; char *locale = "C"; @@ -337,59 +337,43 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, get_color_value(a->attr, c, b, g)); continue; } - - for (bit = 0; bit < 24; bit++) { - - mask = 1 << bit; - - /* - * if this bit is not present in the screen's enabled - * display device mask (and the X screen has enabled - * display devices), skip to the next bit - */ - - if (((t->d & mask) == 0x0) && (t->d)) continue; - status = NvCtrlGetValidDisplayAttributeValues - (t->h, mask, a->attr, &valid); + /* Ignore display attributes, they are written later on */ - if (status != NvCtrlSuccess) goto exit_bit_loop; - - if ((valid.permissions & ATTRIBUTE_TYPE_WRITE) == 0x0) - goto exit_bit_loop; - - status = NvCtrlGetDisplayAttribute(t->h, mask, a->attr, &val); - - if (status != NvCtrlSuccess) goto exit_bit_loop; - - if (valid.permissions & ATTRIBUTE_TYPE_DISPLAY) { + ret = nv_get_attribute_perms(h, a->attr, a->flags, &perms); + if (!ret || (perms.permissions & ATTRIBUTE_TYPE_DISPLAY)) { + continue; + } - tmp_d_str = - display_device_mask_to_display_device_name(mask); + /* Only write attributes that can be written */ - fprintf(stream, "%s%c%s[%s]=%d\n", prefix, - DISPLAY_NAME_SEPARATOR, a->name, tmp_d_str, val); - - free(tmp_d_str); - - continue; - - } else { + status = NvCtrlGetValidAttributeValues(t->h, a->attr, &valid); + if (status != NvCtrlSuccess || + !(valid.permissions & ATTRIBUTE_TYPE_WRITE) || + (valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) {; + continue; + } - fprintf(stream, "%s%c%s=%d\n", prefix, - DISPLAY_NAME_SEPARATOR, a->name, val); + status = NvCtrlGetAttribute(t->h, a->attr, &val); + if (status != NvCtrlSuccess) { + continue; + } - /* fall through to exit_bit_loop */ + if (a->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID) { + const char *name = + nv_get_display_target_config_name(h, val); + if (name) { + fprintf(stream, "%s%c%s=%s\n", prefix, + DISPLAY_NAME_SEPARATOR, a->name, name); } - - exit_bit_loop: + continue; + } + + fprintf(stream, "%s%c%s=%d\n", prefix, + DISPLAY_NAME_SEPARATOR, a->name, val); - bit = 25; /* XXX force us out of the display device loop */ - - } /* bit */ - } /* entry */ - + } /* screen */ /* @@ -447,7 +431,28 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, fprintf(stream, "%s%c%s=%f\n", prefix, DISPLAY_NAME_SEPARATOR, a->name, get_color_value(a->attr, c, b, g)); - } + continue; + } + + /* Make sure this is a display attribute */ + + ret = nv_get_attribute_perms(h, a->attr, a->flags, &perms); + if (!ret || !(perms.permissions & ATTRIBUTE_TYPE_DISPLAY)) { + continue; + } + + status = NvCtrlGetValidAttributeValues(t->h, a->attr, &valid); + if (status != NvCtrlSuccess || + !(valid.permissions & ATTRIBUTE_TYPE_WRITE) || + !(valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) { + continue; + } + + status = NvCtrlGetAttribute(t->h, a->attr, &val); + if (status == NvCtrlSuccess) { + fprintf(stream, "%s%c%s=%d\n", prefix, + DISPLAY_NAME_SEPARATOR, a->name, val); + } } free(prefix); @@ -499,22 +504,16 @@ int nv_write_config_file(const char *filename, CtrlHandles *h, } } - if (p->display_device_mask) { - - tmp_d_str = display_device_mask_to_display_device_name - (p->display_device_mask); - - fprintf(stream, "%s%s%c%s[%s]=%d\n", p->display, target_str, - DISPLAY_NAME_SEPARATOR, tmp, tmp_d_str, p->val.i); - - free(tmp_d_str); - + if (p->flags & NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE) { + fprintf(stream, "%s%s%c%s[0x%08x]=%d\n", p->display, target_str, + DISPLAY_NAME_SEPARATOR, tmp, p->display_device_mask, + p->val.i); } else { - fprintf(stream, "%s%s%c%s=%d\n", p->display, target_str, DISPLAY_NAME_SEPARATOR, tmp, p->val.i); } + p = p->next; } diff --git a/src/gtk+-2.x/ctkappprofile.c b/src/gtk+-2.x/ctkappprofile.c index 65e84d9..939634b 100644 --- a/src/gtk+-2.x/ctkappprofile.c +++ b/src/gtk+-2.x/ctkappprofile.c @@ -3583,13 +3583,15 @@ static void save_app_profile_changes_dialog_save_changes(GtkWidget *widget, gpoi GtkWidget *error_dialog; SaveAppProfileChangesDialog *dialog = (SaveAppProfileChangesDialog *)user_data; CtkAppProfile *ctk_app_profile = CTK_APP_PROFILE(dialog->parent); + char *write_errors = NULL; static const char config_files_changed_string[] = "nvidia-settings has detected that configuration files have changed " "since the configuration was last loaded. Saving the configuration " "may cause these changes to be permanently lost. Continue anyway?\n"; - static const char write_errors_occurred_string[] = - "nvidia-settings encountered errors when writing to the configuration. " - "Some changes may not have been saved. Reload the configuration anyway?\n"; + static const char write_errors_occurred_prefix[] = + "nvidia-settings encountered errors when writing to the configuration:\n"; + static const char write_errors_occurred_suffix[] = + "\nSome changes may not have been saved. Reload the configuration anyway?\n"; // First check for possible conflicts if (nv_app_profile_config_check_backing_files(ctk_app_profile->cur_config)) { @@ -3608,14 +3610,23 @@ static void save_app_profile_changes_dialog_save_changes(GtkWidget *widget, gpoi do_backup = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->backup_check_button)); if (do_save) { - ret = nv_app_profile_config_save_updates(ctk_app_profile->cur_config, dialog->updates, - do_backup); + ret = nv_app_profile_config_save_updates(ctk_app_profile->cur_config, + dialog->updates, + do_backup, &write_errors); if (ret < 0) { - error_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog->top_window), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", write_errors_occurred_string); + if (!write_errors) { + write_errors = strdup("Unknown error."); + } + error_dialog = + gtk_message_dialog_new(GTK_WINDOW(dialog->top_window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + "%s%s%s", + write_errors_occurred_prefix, + write_errors, + write_errors_occurred_suffix); result = gtk_dialog_run(GTK_DIALOG(error_dialog)); if (result != GTK_RESPONSE_YES) { do_reload = FALSE; @@ -3623,6 +3634,8 @@ static void save_app_profile_changes_dialog_save_changes(GtkWidget *widget, gpoi gtk_widget_destroy(error_dialog); } + free(write_errors); + if (do_reload) { app_profile_reload(CTK_APP_PROFILE(dialog->parent)); } diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.c b/src/gtk+-2.x/ctkdisplayconfig-utils.c index 050dc03..d3a7107 100644 --- a/src/gtk+-2.x/ctkdisplayconfig-utils.c +++ b/src/gtk+-2.x/ctkdisplayconfig-utils.c @@ -1976,12 +1976,39 @@ gchar *screen_get_metamode_str(nvScreenPtr screen, int metamode_idx, } } + if (!metamode_str) { + metamode_str = strdup("NULL"); + } + return metamode_str; } /* screen_get_metamode_str() */ +/** cleanup_metamode() *********************************************** + * + * Frees any internal memory used by the metamode. + * + **/ + +void cleanup_metamode(nvMetaModePtr metamode) +{ + if (metamode->cpl_str) { + free(metamode->cpl_str); + metamode->cpl_str = NULL; + } + + if (metamode->x_str) { + XFree(metamode->x_str); + metamode->x_str = NULL; + } + + metamode->x_str_entry = NULL; +} + + + /** screen_remove_metamodes() **************************************** * * Removes all metamodes currently referenced by this screen, also @@ -2006,7 +2033,7 @@ static void screen_remove_metamodes(nvScreenPtr screen) while (screen->metamodes) { metamode = screen->metamodes; screen->metamodes = metamode->next; - free(metamode->string); + cleanup_metamode(metamode); free(metamode); } screen->num_metamodes = 0; @@ -2070,7 +2097,6 @@ static Bool screen_add_metamode(nvScreenPtr screen, const char *metamode_str, char *mode_str_itr; const char *tokens_end; const char *metamode_modes; - char *metamode_copy = NULL; nvMetaModePtr metamode = NULL; int mode_count = 0; @@ -2105,82 +2131,82 @@ static Bool screen_add_metamode(nvScreenPtr screen, const char *metamode_str, } } - /* Process each mode in the metamode string */ - metamode_copy = strdup(metamode_modes); - if (!metamode_copy) goto fail; + metamode_modes = parse_skip_whitespace(metamode_modes); - for (mode_str_itr = mode_strtok(metamode_copy); - mode_str_itr; - mode_str_itr = mode_strtok(NULL)) { + if (strcmp(metamode_modes, "NULL")) { + /* Process each mode in the metamode string */ + char *metamode_copy = strdup(metamode_modes); + if (!metamode_copy) goto fail; - nvModePtr mode; - nvDisplayPtr display; - unsigned int display_id; - const char *orig_mode_str = parse_skip_whitespace(mode_str_itr); - const char *mode_str; + for (mode_str_itr = mode_strtok(metamode_copy); + mode_str_itr; + mode_str_itr = mode_strtok(NULL)) { - /* Parse the display device (NV-CONTROL target) id from the name */ - mode_str = parse_read_display_id(mode_str_itr, &display_id); - if (!mode_str) { - nv_warning_msg("Failed to read a display device name on screen %d " - "while parsing metamode:\n\n'%s'", - screen->scrnum, + nvModePtr mode; + nvDisplayPtr display; + unsigned int display_id; + const char *orig_mode_str = parse_skip_whitespace(mode_str_itr); + const char *mode_str; - orig_mode_str); - continue; - } - - /* Match device id to an existing display */ - display = layout_get_display(screen->layout, display_id); - if (!display) { - nv_warning_msg("Failed to find display device %d on screen %d " - "while parsing metamode:\n\n'%s'", - display_id, - screen->scrnum, + /* Parse the display device (NV-CONTROL target) id from the name */ + mode_str = parse_read_display_id(mode_str_itr, &display_id); + if (!mode_str) { + nv_warning_msg("Failed to read a display device name on screen " + "%d while parsing metamode:\n\n'%s'", + screen->scrnum, orig_mode_str); + continue; + } - orig_mode_str); - continue; - } + /* Match device id to an existing display */ + display = layout_get_display(screen->layout, display_id); + if (!display) { + nv_warning_msg("Failed to find display device %d on screen %d " + "while parsing metamode:\n\n'%s'", + display_id, + screen->scrnum, + orig_mode_str); + continue; + } - /* Parse the mode */ - mode = mode_parse(display, mode_str); - if (!mode) { - nv_warning_msg("Failed to parse mode '%s'\non screen %d\n" - "from metamode:\n\n'%s'", - mode_str, - screen->scrnum, - orig_mode_str); - continue; - } + /* Parse the mode */ + mode = mode_parse(display, mode_str); + if (!mode) { + nv_warning_msg("Failed to parse mode '%s'\non screen %d\n" + "from metamode:\n\n'%s'", + mode_str, + screen->scrnum, + orig_mode_str); + continue; + } - /* Make the mode part of the metamode */ - mode->metamode = metamode; + /* Make the mode part of the metamode */ + mode->metamode = metamode; - /* On older X driver NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN - * attribute is Not Available so we are unable to link displays to - * the screen implicitly. - * To avoid display->cur_mode = NULL link displays explicitly. - */ - screen_link_display(screen, display); - /* Make sure each display has the right number of (NULL) modes */ - screen_check_metamodes(screen); + /* On older X driver NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN + * attribute is Not Available so we are unable to link displays to + * the screen implicitly. + * To avoid display->cur_mode = NULL link displays explicitly. + */ + screen_link_display(screen, display); + /* Make sure each display has the right number of (NULL) modes */ + screen_check_metamodes(screen); - /* Add the mode at the end of the display's mode list */ - xconfigAddListItem((GenericListPtr *)(&display->modes), - (GenericListPtr)mode); - display->num_modes++; - mode_count++; - } + /* Add the mode at the end of the display's mode list */ + xconfigAddListItem((GenericListPtr *)(&display->modes), + (GenericListPtr)mode); + display->num_modes++; + mode_count++; + } - free(metamode_copy); - metamode_copy = NULL; + free(metamode_copy); - /* Make sure something was added */ - if (mode_count == 0) { - nv_warning_msg("Failed to find any display on screen %d\n" - "while parsing metamode:\n\n'%s'", - screen->scrnum, metamode_str); - goto fail; + /* Make sure something was added */ + if (mode_count == 0) { + nv_warning_msg("Failed to find any display on screen %d\n" + "while parsing metamode:\n\n'%s'", + screen->scrnum, metamode_str); + goto fail; + } } /* Add the metamode to the end of the screen's metamode list */ @@ -2195,9 +2221,6 @@ static Bool screen_add_metamode(nvScreenPtr screen, const char *metamode_str, if (metamode) { free(metamode); } - if (metamode_copy) { - free(metamode_copy); - } return FALSE; @@ -3197,7 +3220,7 @@ static Bool layout_add_gpu_from_server(nvLayoutPtr layout, unsigned int gpu_id, gpu->uuid = NULL; } - get_bus_id_str(gpu->handle, &(gpu->pci_bus_id)); + gpu->pci_bus_id = get_bus_id_str(gpu->handle); ret = NvCtrlGetAttribute(gpu->handle, NV_CTRL_MAX_SCREEN_WIDTH, (int *)&(gpu->max_width)); @@ -3507,13 +3530,6 @@ static Bool layout_add_screen_from_server(nvLayoutPtr layout, if (ret == NvCtrlSuccess) { screen->stereo_supported = TRUE; screen->stereo = val; - - /* XXX For now, if stereo is off, don't show configuration options - * until we work out interactions with composite. - */ - if (val == NV_CTRL_STEREO_OFF) { - screen->stereo_supported = FALSE; - } } else { screen->stereo_supported = FALSE; } @@ -3526,17 +3542,20 @@ static Bool layout_add_screen_from_server(nvLayoutPtr layout, screen->overlay = NV_CTRL_OVERLAY_OFF; } - /* See if the screen supports dynamic twinview */ - ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_DYNAMIC_TWINVIEW, &val); - if (ret != NvCtrlSuccess) { - *err_str = g_strdup_printf("Failed to query Dynamic TwinView for " - "screen %d.", - screen_id); - nv_warning_msg("%s", *err_str); - goto fail; + ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_HWOVERLAY, &val); + if (ret == NvCtrlSuccess) { + screen->hw_overlay = val; + } else { + screen->hw_overlay = NV_CTRL_HWOVERLAY_FALSE; } - screen->dynamic_twinview = !!val; + /* Query the current UBB state */ + ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_UBB, &val); + if (ret == NvCtrlSuccess) { + screen->ubb = val; + } else { + screen->ubb = NV_CTRL_UBB_OFF; + } /* See if the screen is set to not scanout */ ret = NvCtrlGetAttribute(screen->handle, NV_CTRL_NO_SCANOUT, &val); @@ -3557,18 +3576,6 @@ static Bool layout_add_screen_from_server(nvLayoutPtr layout, screen->no_scanout = (val == NV_CTRL_NO_SCANOUT_ENABLED); - /* XXX Currently there is no support for screens that are scanning - * out but have TwinView disabled. - */ - if (!screen->dynamic_twinview && !screen->no_scanout) { - *err_str = g_strdup_printf("nvidia-settings currently does not " - "support scanout screens (%d) that have " - "dynamic twinview disabled.", - screen_id); - nv_warning_msg("%s", *err_str); - goto fail; - } - /* Link screen to the GPUs driving it */ if (!link_screen_to_gpus(layout, screen)) { *err_str = g_strdup_printf("Failed to find GPU that drives screen %d.", diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.h b/src/gtk+-2.x/ctkdisplayconfig-utils.h index e903377..0e74a62 100644 --- a/src/gtk+-2.x/ctkdisplayconfig-utils.h +++ b/src/gtk+-2.x/ctkdisplayconfig-utils.h @@ -87,6 +87,8 @@ Bool display_set_modes_rotation(nvDisplayPtr display, Rotation rotation); /* Metamode functions */ +void cleanup_metamode(nvMetaModePtr metamode); + /* Screen functions */ diff --git a/src/gtk+-2.x/ctkdisplayconfig.c b/src/gtk+-2.x/ctkdisplayconfig.c index 8cb0638..ee2e25e 100644 --- a/src/gtk+-2.x/ctkdisplayconfig.c +++ b/src/gtk+-2.x/ctkdisplayconfig.c @@ -2171,7 +2171,11 @@ GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *table, { GtkTextIter i; GtkTextBuffer *b; + nvGpuPtr gpu = NULL; + if (ctk_object->layout) { + gpu = ctk_object->layout->gpus; + } b = gtk_text_buffer_new(table); @@ -2196,6 +2200,26 @@ GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *table, "be moved by holding CONTROL-Click and dragging."); ctk_help_heading(b, &i, "Layout Hidden Label"); ctk_help_para(b, &i, "%s", __layout_hidden_label_help); + + if (gpu) { + switch (gpu->mosaic_type) { + case MOSAIC_TYPE_SLI_MOSAIC: + ctk_help_heading(b, &i, "Enable SLI Mosaic"); + ctk_help_para(b, &i, "%s", __layout_sli_mosaic_button_help); + break; + case MOSAIC_TYPE_BASE_MOSAIC: + ctk_help_heading(b, &i, "Enable Base Mosaic"); + ctk_help_para(b, &i, "%s", __layout_base_mosaic_full_button_help); + break; + case MOSAIC_TYPE_BASE_MOSAIC_LIMITED: + ctk_help_heading(b, &i, "Enable Base Mosaic (Surround)"); + ctk_help_para(b, &i, "%s", __layout_base_mosaic_surround_button_help); + break; + default: + break; + } + } + ctk_help_heading(b, &i, "Enable Xinerama"); ctk_help_para(b, &i, "%s This setting is only available when multiple " "X screens are present.", __layout_xinerama_button_help); @@ -2207,6 +2231,13 @@ GtkTextBuffer *ctk_display_config_create_help(GtkTextTagTable *table, ctk_help_para(b, &i, "The following options are available when a display " "device is selected in the Selection drop-down to configure " "the settings for that display device."); + ctk_help_heading(b, &i, "Configuration"); + ctk_help_para(b, &i, "%s \"Disabled\" disables the selected display " + "device. \"X screen <number>\" associates the selected " + "display device with the specified X Screen. \"New X screen " + "(requires X restart)\" creates a new X Screen and " + "associates the selected display device with it.", + __dpy_configuration_mnu_help); ctk_help_heading(b, &i, "Resolution"); ctk_help_para(b, &i, "%s", __dpy_resolution_mnu_help); ctk_help_heading(b, &i, "Refresh"); @@ -7064,11 +7095,11 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, modified_current_metamode = FALSE; } else { nv_info_msg(TAB, "Modifying current MetaMode to: %s...", - metamode->string); + metamode->cpl_str); ret = NvCtrlSetStringAttribute(screen->handle, NV_CTRL_STRING_CURRENT_METAMODE, - metamode->string, + metamode->cpl_str, NULL); if (ret == NvCtrlSuccess) { metamode->id = old_rate; @@ -7080,7 +7111,8 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, nv_warning_msg("Failed to set MetaMode (%d) '%s' " "(Mode: %dx%d, id: %d) on X screen %d!", - screen->cur_metamode_idx+1, metamode->string, new_width, + screen->cur_metamode_idx+1, metamode->cpl_str, + new_width, new_height, new_rate, NvCtrlGetTargetId(screen->handle)); @@ -7088,7 +7120,8 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, msg = g_strdup_printf("Failed to set MetaMode (%d) '%s' " "(Mode %dx%d, id: %d) on X screen %d\n\n" "Would you like to remove this MetaMode?", - screen->cur_metamode_idx+1, metamode->string, + screen->cur_metamode_idx+1, + metamode->cpl_str, new_width, new_height, new_rate, NvCtrlGetTargetId(screen->handle)); dlg = gtk_message_dialog_new @@ -7100,7 +7133,8 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, } else { msg = g_strdup_printf("Failed to set MetaMode (%d) '%s' " "(Mode %dx%d, id: %d) on X screen %d.", - screen->cur_metamode_idx+1, metamode->string, + screen->cur_metamode_idx+1, + metamode->cpl_str, new_width, new_height, new_rate, NvCtrlGetTargetId(screen->handle)); dlg = gtk_message_dialog_new @@ -7206,18 +7240,18 @@ static Bool switch_to_current_metamode(CtkDisplayConfig *ctk_object, -/** find_metamode_string_by_id() ************************************* +/** link_metamode_string_by_id() ************************************* * * Looks in the list of strings (metamode_strs) for a metamode with - * the given id (defined by string 'id_str') and returns the pointer - * to it, or NULL if not found. + * the given id (defined by string 'id_str'). If found, sets the metamode + * id and x_id appropriately. * **/ -static char *find_metamode_string_by_id(char *metamode_strs, int match_id, - int *match_idx) +static void link_metamode_string_by_id(char *metamode_strs, int match_id, + nvMetaModePtr metamode) { - int idx = 0; + int x_idx = 0; char *m; for (m = metamode_strs; m && strlen(m); m += strlen(m) +1) { @@ -7225,16 +7259,14 @@ static char *find_metamode_string_by_id(char *metamode_strs, int match_id, if (str) { int id = atoi(str+3); if (id && (id == match_id)) { - if (match_idx) { - *match_idx = idx; - } - return m; + metamode->id = id; + metamode->x_idx = x_idx; + metamode->x_str_entry = m; + return; } } - idx++; + x_idx++; } - - return NULL; } @@ -7253,13 +7285,13 @@ static Bool add_cpl_metamode_to_X(nvScreenPtr screen, nvMetaModePtr metamode, ret = NvCtrlStringOperation(screen->handle, 0, NV_CTRL_STRING_OPERATION_ADD_METAMODE, - metamode->string, &tokens); + metamode->cpl_str, &tokens); /* Grab the metamode ID from the returned tokens */ if ((ret != NvCtrlSuccess) || !tokens) { nv_error_msg("Failed to add MetaMode '%s' to X for " "screen %d", - metamode->string, screen->scrnum); + metamode->cpl_str, screen->scrnum); return FALSE; } @@ -7272,7 +7304,7 @@ static Bool add_cpl_metamode_to_X(nvScreenPtr screen, nvMetaModePtr metamode, nv_info_msg(TAB, "Added MetaMode (# %d, ID: %d) > [%s]", metamode_idx, metamode->id, - metamode->string); + metamode->cpl_str); return TRUE; } @@ -7296,31 +7328,17 @@ static void stub_metamode_str(char *str) } - -/** preprocess_metamodes() ******************************************* - * - * Does preprocess work to the metamode strings: - * - * - Generates the metamode strings for the screen's metamodes - * that will be used for creating the metamode list on the X - * Server. - * - * - Stubs out each string in the metamode_strs list that should - * not be deleted (it has a matching metamode in "screen".) +/** setup_metamodes_for_apply() ************************************** * - * - Adds new metamodes to the X server screen that are specified - * in "screen" but not found in metamode_strs. + * Prepares the list of CPL metamodes to be applied to the X server. * **/ -static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs, - char *cur_metamode_str, - int num_metamodes_in_X, - int cur_metamode_idx) +static void setup_metamodes_for_apply(nvScreenPtr screen, + char *metamode_strs) { nvMetaModePtr metamode; ReturnStatus ret; - char *str; char *tmp; int metamode_idx; @@ -7329,95 +7347,210 @@ static void preprocess_metamodes(nvScreenPtr screen, char *metamode_strs, metamode; metamode = metamode->next, metamode_idx++) { - /* Generate the metamode's string */ - free(metamode->string); metamode->id = -1; metamode->x_idx = -1; - metamode->string = screen_get_metamode_str(screen, metamode_idx, 1); - if (!metamode->string) continue; - /* See if the metamode already exists and if so, get its ID */ + /* Get metamode string from CPL */ + metamode->cpl_str = screen_get_metamode_str(screen, metamode_idx, 1); + if (!metamode->cpl_str) { + continue; + } + + /* Parse CPL string into X metamode string */ ret = NvCtrlStringOperation(screen->handle, 0, NV_CTRL_STRING_OPERATION_PARSE_METAMODE, - metamode->string, &str); - if (ret != NvCtrlSuccess) { - /* XXX Something's wrong with the metamode, ignore it for now. */ + metamode->cpl_str, &metamode->x_str); + if ((ret != NvCtrlSuccess) || + !metamode->x_str) { continue; } - /* XXX Later, we'll ask X to parse this metamode on updates - * and already have an ID so we'll know already which metamodes - * need to be deleted/added/moved. - */ - - tmp = strstr(str, "id="); + /* Identify metamode id and position in X */ + tmp = strstr(metamode->x_str, "id="); if (tmp) { int id = atoi(tmp+3); - tmp = find_metamode_string_by_id(metamode_strs, id, - &(metamode->x_idx)); - if (tmp) { - metamode->id = id; + link_metamode_string_by_id(metamode_strs, id, metamode); + } + } +} - /* We matched a CPL metamode with an X metamode, so stub the - * metamode from the X list so we don't delete it later. - */ - stub_metamode_str(tmp); - /* - nv_info_msg(TAB, "%3d - Matched MetaMode (ID:%3d, X idx:%3d) > [%s]", - metamode_idx, - metamode->id, - metamode->x_idx, - metamode->string); - */ - /* Process the next metamode */ +/** cleanup_metamodes_for_apply() ************************************ + * + * Releases memory used for applying metamodes to X. + * + **/ + +static void cleanup_metamodes_for_apply(nvScreenPtr screen) +{ + nvMetaModePtr metamode; + + for (metamode = screen->metamodes; + metamode; + metamode = metamode->next) { + + cleanup_metamode(metamode); + } +} + + + +/** remove_duplicate_cpl_metamodes() ********************************* + * + * Removes duplicate metamodes in the CPL + * + **/ + +static void remove_duplicate_cpl_metamodes(CtkDisplayConfig *ctk_object, + nvScreenPtr screen) +{ + nvMetaModePtr m1; + nvMetaModePtr m2; + int m1_idx; + int m1_old_idx; + int m2_idx; + + m1 = screen->metamodes; + m1_idx = 0; + m1_old_idx = 0; + while (m1) { + Bool found = FALSE; + + if (!m1->x_str) { + m1 = m1->next; + m1_idx++; + m1_old_idx++; + continue; + } + + for (m2 = screen->metamodes, m2_idx = 0; + m2 != m1; + m2 = m2->next, m2_idx++) { + + if (!m2->x_str) { + continue; + } + + if (strcmp(m1->x_str, m2->x_str)) { continue; } + + /* m1 and m2 are the same, delete m1 (since it comes after) */ + if (m1 == screen->cur_metamode) { + ctk_display_layout_set_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, m2_idx); + } + + m1 = m1->next; + + ctk_display_layout_delete_screen_metamode + (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout), + screen, m1_idx, FALSE); + + nv_info_msg(TAB, "Removed MetaMode %d on Screen %d (is " + "duplicate of MetaMode %d)\n", m1_old_idx+1, + screen->scrnum, + m2_idx+1); + + found = TRUE; + break; } - /* If the CPL metamode did not match any of the metamodes in X, we - * should add it. Note, however, that since we have not yet gone - * through the whole list of CPL MetaModes (the currently active - * MetaMode in X may match a CPL MetaMode we have not yet encountered), - * we don't yet know if the current metamode should be modified via - * NV_CTRL_STRING_CURRENT_METAMODE, or added then swapped to, so ignore - * it for now and handle it once we've gone through all the CPL - * MetaModes. + if (!found) { + m1 = m1->next; + m1_idx++; + } + m1_old_idx++; + } +} + + + +/** preprocess_metamodes() ******************************************* + * + * Does preprocess work to the metamode strings: + * + * - Generates the metamode strings for the screen's metamodes + * that will be used for creating the metamode list on the X + * Server. + * + * - Stubs out each string in the metamode_strs list that should + * not be deleted (it has a matching metamode in "screen".) + * + * - Adds new metamodes to the X server screen that are specified + * in "screen" but not found in metamode_strs. + * + **/ + +static void preprocess_metamodes(CtkDisplayConfig *ctk_object, + nvScreenPtr screen, + char *x_metamode_strs, + char *cur_x_metamode_str, + int num_x_metamodes, + int cur_x_metamode_idx) +{ + nvMetaModePtr metamode; + Bool cur_x_metamode_matched = FALSE; + + + /* Generate metamode strings and match CPL metamodes to X */ + setup_metamodes_for_apply(screen, x_metamode_strs); + + /* Remove duplicate metamodes in CPL based on parsed string */ + remove_duplicate_cpl_metamodes(ctk_object, screen); + + /* Add metamodes from the CPL that aren't in X */ + for (metamode = screen->metamodes; + metamode; + metamode = metamode->next) { + + /* CPL metamode was found in X, stub out the string entry in the X + * metamodes list so we don't delete it later. + */ + if (metamode->x_str_entry) { + stub_metamode_str(metamode->x_str_entry); + /* Track if the current X metamode matched a CPL metamode */ + if (metamode->x_str_entry == cur_x_metamode_str) { + cur_x_metamode_matched = TRUE; + } + continue; + } + + /* CPL metamode was not found in X, so we should add it. */ + + /* Don't add the current metamode (yet). If the current X metamode + * string does not get stubbed out (i.e. it does not match to another + * CPL metamode), then it can be modify via + * NV_CTRL_STRING_CURRENT_METAMODE instead of adding a new metamode, + * switching to it and deleting the old one. */ if (metamode == screen->cur_metamode) { continue; } - /* The metamode was not found, so add it to the X screen's list */ - if (add_cpl_metamode_to_X(screen, metamode, num_metamodes_in_X)) { - num_metamodes_in_X++; + if (add_cpl_metamode_to_X(screen, metamode, num_x_metamodes)) { + num_x_metamodes++; } } - /* If the currently selected MetaMode in the CPL did not match any metamode - * in X, and the current active MetaMode (in X) was linked to another CPL - * MetaMode, then we will need to add the CPL's current MetaMode so we can - * switch to it later. - * - * Note: if a mode was matched above, then the current metamode pointer - * should now point to a stubbed out entry, and this is what we check for - * here. + /* If the currently selected CPL metamode did not match any X metamode, and + * the current active X metamode matched to another CPL metamode, then the + * currently selected CPL metamode will need to be added and switched to. */ - if ((screen->cur_metamode->id < 0)) { - const char *ctmp = parse_skip_whitespace(cur_metamode_str); - - if (!*ctmp) { + if (screen->cur_metamode->id < 0) { + if (cur_x_metamode_matched) { if (add_cpl_metamode_to_X(screen, screen->cur_metamode, - num_metamodes_in_X)) { - num_metamodes_in_X++; + num_x_metamodes)) { + num_x_metamodes++; } } else { /* Current metamode will be overridden, so stub it here so that it * does not get deleted later. */ - stub_metamode_str(cur_metamode_str); - screen->cur_metamode->x_idx = cur_metamode_idx; + stub_metamode_str(cur_x_metamode_str); + screen->cur_metamode->x_idx = cur_x_metamode_idx; } } @@ -7439,15 +7572,15 @@ static Bool screen_move_metamode(nvScreenPtr screen, nvMetaModePtr metamode, int len; ReturnStatus ret; - if (!metamode->string) { + if (!metamode->cpl_str) { goto fail; } /* Append the index we want */ - len = 24 + strlen(metamode->string); + len = 24 + strlen(metamode->cpl_str); update_str = malloc(len); snprintf(update_str, len, "index=%d :: %s", metamode_idx, - metamode->string); + metamode->cpl_str); ret = NvCtrlSetStringAttribute(screen->handle, NV_CTRL_STRING_MOVE_METAMODE, @@ -7460,7 +7593,7 @@ static Bool screen_move_metamode(nvScreenPtr screen, nvMetaModePtr metamode, metamode->id, metamode->x_idx, metamode_idx, - metamode->string); + metamode->cpl_str); /* We moved the metamode to position metamode_idx, so bump the * index of all metamodes from the new position to the old one. @@ -7490,11 +7623,12 @@ static Bool screen_move_metamode(nvScreenPtr screen, nvMetaModePtr metamode, metamode->id, metamode->x_idx, metamode_idx, - metamode->string ? metamode->string : "NULL"); + metamode->cpl_str ? metamode->cpl_str : "NULL"); return FALSE; } + /** order_metamodes() ************************************************ * * Makes sure the metamodes are ordered properly by moving each @@ -7580,7 +7714,9 @@ static void postprocess_metamodes(nvScreenPtr screen, char *metamode_strs) /* Reorder the list of metamodes */ order_metamodes(screen); -} /* postprocess_metamodes() */ + /* Cleanup */ + cleanup_metamodes_for_apply(screen); +} @@ -7696,7 +7832,7 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, /* Add new metamodes and relate MetaModes from CPL to X */ - preprocess_metamodes(screen, metamode_strs, cur_metamode_ptr, + preprocess_metamodes(ctk_object, screen, metamode_strs, cur_metamode_ptr, num_metamodes_in_X, cur_metamode_idx); @@ -7731,7 +7867,7 @@ static int update_screen_metamodes(CtkDisplayConfig *ctk_object, screen->cur_metamode->edim.width, screen->cur_metamode->edim.height); - nv_info_msg(TAB, "Using > %s", screen->cur_metamode->string); + nv_info_msg(TAB, "Using > %s", screen->cur_metamode->cpl_str); clear_apply = 1; } @@ -7830,6 +7966,8 @@ static void apply_clicked(GtkWidget *widget, gpointer user_data) /* re-register to receive events */ register_layout_events(ctk_object); + update_gui(ctk_object); + } /* apply_clicked() */ @@ -8610,21 +8748,42 @@ static int generateXConfig(CtkDisplayConfig *ctk_object, XConfigPtr *pConfig) goto fail; } - if (go.supports_extension_section && layout->xinerama_enabled) { + /* Check if composite should be disabled */ + { + const char *composite_disabled_str = NULL; + nvScreenPtr screen; - if (!config->extensions) { - config->extensions = calloc(1, sizeof(XConfigExtensionsRec)); + /* See if any X screens have overlay, cioverlay, ubb or stereo enabled, + * or depth 8. + */ + for (screen = layout->screens; screen; screen = screen->next_in_layout) { + + composite_disabled_str = + xconfigValidateComposite(config, + &go, + 1, // composite_specified + layout->xinerama_enabled, + screen->depth, + screen->overlay && screen->hw_overlay, + screen->overlay && !screen->hw_overlay, + screen->ubb, + screen->stereo + ); + if (composite_disabled_str) { + break; + } } - /* remove any existing composite extension option and then add the option*/ - xconfigRemoveNamedOption(&(config->extensions->options), "Composite", - NULL); - xconfigAddNewOption(&config->extensions->options, "Composite", "Disable"); - + if (composite_disabled_str) { + if (!config->extensions) { + config->extensions = nvalloc(sizeof(XConfigExtensionsRec)); + } + xconfigRemoveNamedOption(&(config->extensions->options), "Composite", + NULL); + xconfigAddNewOption(&config->extensions->options, "Composite", "Disable"); + } } - - *pConfig = config; return XCONFIG_GEN_OK; diff --git a/src/gtk+-2.x/ctkdisplaydevice.c b/src/gtk+-2.x/ctkdisplaydevice.c index f979e6d..e8900ae 100644 --- a/src/gtk+-2.x/ctkdisplaydevice.c +++ b/src/gtk+-2.x/ctkdisplaydevice.c @@ -58,7 +58,6 @@ static gboolean update_tv_encoder_info(InfoEntry *entry); static gboolean update_chip_info(InfoEntry *entry); static gboolean update_signal_info(InfoEntry *entry); static gboolean update_link_info(InfoEntry *entry); -static gboolean update_native_resolution(InfoEntry *entry); static gboolean update_refresh_rate(InfoEntry *entry); static gboolean register_link_events(InfoEntry *entry); @@ -95,11 +94,6 @@ static const char *__info_signal_help = "Report whether the flat panel is driven by an LVDS, TMDS, or DisplayPort " "signal."; -static const char * __native_res_help = -"The Native Resolution is the width and height in pixels that the display " -"device uses to display the image. All other resolutions must be scaled " -"to this resolution by the GPU and/or the device's built-in scaler."; - static const char * __refresh_rate_help = "The refresh rate displays the rate at which the screen is currently " "refreshing the image."; @@ -144,13 +138,6 @@ static InfoEntryData __info_entry_data[] = { unregister_link_events, }, { - "Native Resolution", - &__native_res_help, - update_native_resolution, - NULL, - NULL, - }, - { "Refresh Rate", &__refresh_rate_help, update_refresh_rate, @@ -695,28 +682,6 @@ static gboolean update_link_info(InfoEntry *entry) -static gboolean update_native_resolution(InfoEntry *entry) -{ - CtkDisplayDevice *ctk_object = entry->ctk_object; - ReturnStatus ret; - gint val; - char *str; - - ret = NvCtrlGetAttribute(ctk_object->handle, - NV_CTRL_FLATPANEL_NATIVE_RESOLUTION, &val); - if (ret != NvCtrlSuccess) { - return FALSE; - } - - str = g_strdup_printf("%dx%d", (val >> 16), (val & 0xFFFF)); - gtk_label_set_text(GTK_LABEL(entry->txt), str); - g_free(str); - - return TRUE; -} - - - static gboolean update_refresh_rate(InfoEntry *entry) { CtkDisplayDevice *ctk_object = entry->ctk_object; diff --git a/src/gtk+-2.x/ctkdisplaylayout.c b/src/gtk+-2.x/ctkdisplaylayout.c index d426a5b..8cdc438 100644 --- a/src/gtk+-2.x/ctkdisplaylayout.c +++ b/src/gtk+-2.x/ctkdisplaylayout.c @@ -61,61 +61,82 @@ #define NUM_COLORS_PER_PALETTE 4 /* Number of colors in a device's palette */ #define NUM_COLORS ((NUM_COLOR_PALETTES) * (NUM_COLORS_PER_PALETTE)) -#if MAX_DEVICES != 8 +#define COLOR_PALETTE_STEP_VALUE 0x181818 + +#if MAX_DEVICES != 64 #warning "Each GPU needs a color palette!" #endif /* Each device will need a unique color palette */ -char *__palettes_color_names[NUM_COLORS] = { - - /* Blue */ - "#D9DBF4", /* View - Has modeline set */ - "#C9CBE4", /* Panning - Has modeline set */ - "#BABCD5", /* View - Off/Disabled */ - "#A3A5BE", /* Panning - OFf/Disabled */ - - /* Orange */ - "#FFDB94", - "#E8C47D", - "#C9A55E", - "#A6823B", - - /* Purple */ - "#E2D4F0", - "#CFC1DD", - "#B7A9C5", - "#9D8FAB", - - /* Beige */ - "#EAF1C9", - "#CBD2AA", - "#ADB48C", - "#838A62", - - /* Green */ - "#96E562", - "#70BF3C", - "#5BAA27", - "#3C8B08", - - /* Pink */ - "#FFD6E9", - "#E1B8CB", - "#C79EB1", - "#A87F92", - - /* Yellow */ - "#EEEE7E", - "#E0E070", - "#D5D565", - "#C4C454", - - /* Teal */ - "#C9EAF1", - "#A2C3CA", - "#8DAEB5", - "#76979E" - }; +int __palettes_color_names[NUM_COLORS] = { + 0xD9DBF4, /* Blue */ + 0xFFDB94, /* Orange */ + 0xE2D4F0, /* Purple */ + 0xEAF1C9, /* Beige */ + 0x96E562, /* Green */ + 0xFFD6E9, /* Pink */ + 0xEEEE7E, /* Yellow */ + 0xC9EAF1, /* Teal */ + + 0xB9F282, + 0xB298FE, + 0x84FAE3, + 0xE1928D, + 0xFF8FE6, + 0xB2F9BF, + 0xA2E0FC, + 0xFEBBAF, + + 0xF5B2FA, + 0xA2B4F7, + 0x96FA94, + 0xE0F7A8, + 0xFFFE9E, + 0xF096BA, + 0xB0FFE9, + 0xFD8B9E, + 0xB996DA, + 0x83F3B0, + 0xFFAF8C, + 0xE086FE, + 0xC4E1CB, + 0xCDA3F7, + 0xF1CEBE, + 0xC0CFFF, + + 0x8A8AFA, + 0xE8D399, + 0xE381B6, + 0xABB7A3, + 0xDFE4E0, + 0xA6FCD2, + 0xFD85CC, + 0x98E387, + 0xF1E8AF, + 0x82C2FF, + 0xCCF599, + 0xAA83F9, + 0xD3FCC4, + 0xFCB4CE, + 0x8FECF8, + 0xA8F4A5, + 0xB0F1FF, + 0x91A5FA, + 0xB3C6EF, + 0xE1B6EC, + 0xD3C1FB, + 0xDEE4BD, + 0xD9F982, + 0xFEE5C4, + 0xEAB6B9, + 0xB6E5E7, + 0x81DCF2, + 0x81F08F, + 0xDCAACC, + 0xCCF0D7, + 0xF49FD4, + 0xC0B7C2 +}; @@ -2570,7 +2591,7 @@ GtkWidget* ctk_display_layout_new(NvCtrlAttributeHandle *handle, CtkDisplayLayout *ctk_object; GtkWidget *tmp; PangoFontDescription *font_description; - int i; + int i, j; /* Make sure we have a handle */ @@ -2619,9 +2640,24 @@ GtkWidget* ctk_display_layout_new(NvCtrlAttributeHandle *handle, /* Parse the device color palettes */ ctk_object->color_palettes = calloc(NUM_COLORS, sizeof(GdkColor)); - for (i = 0; i < NUM_COLORS; i++) { - gdk_color_parse(__palettes_color_names[i], - &(ctk_object->color_palettes[i])); + for (i = 0; i < NUM_COLOR_PALETTES; i++) { + for (j = 0; j < NUM_COLORS_PER_PALETTE; j++) { + + int color = __palettes_color_names[i] - + (j * COLOR_PALETTE_STEP_VALUE); + int index = i * NUM_COLORS_PER_PALETTE + j; + + /* + * Convert the reference 24 bit 0xRRGGBB hex value to the GdkColor + * struct that uses 16 bit ints for each color value. We also need + * to shift the color values to the most significant end of these + * fields. + */ + + ctk_object->color_palettes[index].red = (color & 0xff0000) >> 8; + ctk_object->color_palettes[index].green = (color & 0xff00); + ctk_object->color_palettes[index].blue = (color & 0xff) << 8; + } } @@ -3426,6 +3462,7 @@ void ctk_display_layout_delete_screen_metamode(CtkDisplayLayout *ctk_object, screen->cur_metamode_idx = screen->num_metamodes -1; } + cleanup_metamode(metamode); free(metamode); diff --git a/src/gtk+-2.x/ctkdisplaylayout.h b/src/gtk+-2.x/ctkdisplaylayout.h index a5c7c74..34a7b44 100644 --- a/src/gtk+-2.x/ctkdisplaylayout.h +++ b/src/gtk+-2.x/ctkdisplaylayout.h @@ -54,7 +54,7 @@ G_BEGIN_DECLS /* Maximums */ -#define MAX_DEVICES 8 /* Max number of GPUs */ +#define MAX_DEVICES 64 /* Max number of GPUs */ /* XF86VIDMODE */ @@ -271,7 +271,10 @@ typedef struct nvMetaModeRec { // Used for applying and generating metamodes (effective dimensions) GdkRectangle edim; /* Bounding box of all non-NULL modes */ - char *string; /* Temp string used for modifying the metamode list */ + /* Used to apply the metamode to the running X server */ + char *cpl_str; /* metamode string from CPL */ + char *x_str; /* parsed CPL string from X */ + char *x_str_entry; /* Points to string in metamode strings buffer */ } nvMetaMode, *nvMetaModePtr; @@ -311,6 +314,8 @@ typedef struct nvScreenRec { int depth; /* Depth of the screen */ int stereo; /* Stereo mode enabled on this screen */ int overlay; /* Overlay enabled on this screen */ + int hw_overlay; + int ubb; nvDisplayPtr displays; /* List of displays using this screen */ int num_displays; /* # of displays using this screen */ @@ -331,7 +336,6 @@ typedef struct nvScreenRec { Bool sli; char *sli_mode; char *multigpu_mode; - Bool dynamic_twinview; /* This screen supports dynamic twinview */ Bool no_scanout; /* This screen has no display devices */ Bool stereo_supported; /* Can stereo be configured on this screen */ diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c index 72fb330..a8497dc 100644 --- a/src/gtk+-2.x/ctkevent.c +++ b/src/gtk+-2.x/ctkevent.c @@ -218,7 +218,6 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_SIGNAL(NV_CTRL_MAX_SCREEN_WIDTH); MAKE_SIGNAL(NV_CTRL_MAX_SCREEN_HEIGHT); MAKE_SIGNAL(NV_CTRL_MAX_DISPLAYS); - MAKE_SIGNAL(NV_CTRL_DYNAMIC_TWINVIEW); MAKE_SIGNAL(NV_CTRL_MULTIGPU_DISPLAY_OWNER); MAKE_SIGNAL(NV_CTRL_GPU_SCALING); MAKE_SIGNAL(NV_CTRL_GPU_SCALING_DEFAULT_TARGET); @@ -329,6 +328,9 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_SIGNAL(NV_CTRL_BASE_MOSAIC); MAKE_SIGNAL(NV_CTRL_MULTIGPU_MASTER_POSSIBLE); MAKE_SIGNAL(NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE); + MAKE_SIGNAL(NV_CTRL_XV_SYNC_TO_DISPLAY_ID); + MAKE_SIGNAL(NV_CTRL_BACKLIGHT_BRIGHTNESS); + MAKE_SIGNAL(NV_CTRL_THERMAL_COOLER_SPEED); #undef MAKE_SIGNAL /* @@ -338,7 +340,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) * knows about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_THERMAL_COOLER_SPEED #warning "There are attributes that do not emit signals!" #endif @@ -390,6 +392,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class) MAKE_STRING_SIGNAL(NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX); MAKE_STRING_SIGNAL(NV_CTRL_STRING_DISPLAY_NAME_RANDR); MAKE_STRING_SIGNAL(NV_CTRL_STRING_GPU_UUID); + MAKE_STRING_SIGNAL(NV_CTRL_STRING_GPU_UTILIZATION); MAKE_STRING_SIGNAL(NV_CTRL_STRING_MULTIGPU_MODE); #undef MAKE_STRING_SIGNAL diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c index 5454646..fe43a31 100644 --- a/src/gtk+-2.x/ctkframelock.c +++ b/src/gtk+-2.x/ctkframelock.c @@ -20,7 +20,9 @@ #include <gtk/gtk.h> #include <gdk-pixbuf/gdk-pixdata.h> -#include <NvCtrlAttributes.h> +#include "NvCtrlAttributes.h" +#include "NVCtrlLib.h" + #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -73,6 +75,19 @@ enum }; /* + * These signals get hooked up (to the display_state_received() function) + * for all frame lock display devices that are included in the list. When the + * entry is removed, these signals also get removed. + */ + +const char *__DisplaySignals[] = + { + CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE), + CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE_3), + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_DISPLAY_CONFIG), + }; + +/* * These signals get hooked up (to the gpu_state_received() function) * for all frame lock devices that are included in the list. When the * frame lock device entry is removed, these signals also get removed for @@ -81,13 +96,8 @@ enum const char *__GPUSignals[] = { - 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_REFRESH_RATE), - CTK_EVENT_NAME(NV_CTRL_REFRESH_RATE_3), - CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SLAVEABLE) }; /* @@ -102,7 +112,7 @@ const char *__FrameLockSignals[] = CTK_EVENT_NAME(NV_CTRL_USE_HOUSE_SYNC), CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_SYNC_INTERVAL), CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_POLARITY), - CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_VIDEO_MODE) + CTK_EVENT_NAME(NV_CTRL_FRAMELOCK_VIDEO_MODE), }; typedef struct _nvListTreeRec nvListTreeRec, *nvListTreePtr; @@ -161,8 +171,11 @@ struct _nvListTreeRec { struct _nvDisplayDataRec { - - gpointer handle; /* NV-CONTROL GPU Target */ + + gpointer handle; /* NV-CONTROL Display Target */ + + gboolean serverable; + gboolean clientable; GtkWidget *label; @@ -191,8 +204,6 @@ struct _nvGPUDataRec { gpointer handle; /* NV-CONTROL GPU Target */ - guint server_mask; - guint clients_mask; gboolean enabled; /* Sync enabled */ GtkWidget *timing_label; @@ -821,30 +832,37 @@ static gchar *get_display_name(nvDisplayDataPtr data, gboolean simple) { ReturnStatus ret; char *display_name; - char *display_type; + char *display_type = NULL; char *name; - - ret = NvCtrlGetStringDisplayAttribute(data->handle, - data->device_mask, - NV_CTRL_STRING_DISPLAY_DEVICE_NAME, - &display_name); + + ret = NvCtrlGetStringAttribute(data->handle, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &display_name); if (ret != NvCtrlSuccess) { display_name = NULL; } - display_type = - display_device_mask_to_display_device_name(data->device_mask); + if (!simple) { + ret = + NvCtrlGetStringAttribute(data->handle, + NV_CTRL_STRING_DISPLAY_NAME_RANDR, + &display_type); + if (ret != NvCtrlSuccess) { + display_type = NULL; + } + } - if (simple) { - name = g_strconcat(display_name?display_name:"Unknown Display", - NULL); - } else { - name = g_strconcat(display_name?display_name:"Unknown Display", + if (display_type) { + name = g_strconcat((display_name ? display_name : "Unknown Display"), " (", display_type, ")", NULL); + XFree(display_type); + } else { + name = g_strconcat((display_name ? display_name : "Unknown Display"), + NULL); } if (display_name) { - free(display_name); + XFree(display_name); } return name; @@ -1123,6 +1141,24 @@ static nvListEntryPtr get_display_server_entry(nvListTreePtr tree) +/** get_display_server_data() **************************************** + * + * Retrieves the display list entry'sdata that is the currently + * selected server. + * + */ +static nvDisplayDataPtr get_display_server_data(nvListTreePtr tree) +{ + nvListEntryPtr entry = get_display_server_entry(tree); + if (!entry) { + return NULL; + } + + return (nvDisplayDataPtr)entry->data; +} + + + /** list_entry_update_framelock_controls() *************************** * * Updates a Quadro Sync list entry's GUI controls based on the current @@ -1166,27 +1202,7 @@ static void list_entry_update_framelock_controls(CtkFramelock *ctk_framelock, static void list_entry_update_gpu_controls(CtkFramelock *ctk_framelock, nvListEntryPtr entry) { - nvGPUDataPtr data = (nvGPUDataPtr)(entry->data); - int slaveables; - nvDisplayDataPtr display_data; - nvListEntryPtr child; - ReturnStatus ret; - - - ret = NvCtrlGetDisplayAttribute(data->handle, - ~0, /* Query all displays */ - NV_CTRL_FRAMELOCK_SLAVEABLE, - &slaveables); - - /* Update the slaveable flag of the GPU's display devices */ - child = entry->children; - while (child) { - display_data = (nvDisplayDataPtr)(child->data); - /* Assume device is slaveable if slaveable query fails. */ - display_data->slaveable = ((ret != NvCtrlSuccess) || - (display_data->device_mask & slaveables)); - child = child->next_sibling; - } + /* No controls to update */ } static gboolean framelock_refresh_rates_compatible(int server, int client) @@ -1215,64 +1231,52 @@ static gboolean framelock_refresh_rates_compatible(int server, int client) static void list_entry_update_display_controls(CtkFramelock *ctk_framelock, nvListEntryPtr entry) { - nvDisplayDataPtr data = (nvDisplayDataPtr)(entry->data); + nvDisplayDataPtr display_data = (nvDisplayDataPtr)(entry->data); gboolean framelock_enabled = ctk_framelock->framelock_enabled; gboolean sensitive; - - nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); - nvListEntryPtr server_entry = get_display_server_entry(tree); - nvDisplayDataPtr server_data = NULL; - + nvDisplayDataPtr server_data = get_display_server_data(entry->tree); - if (server_entry) { - server_data = (nvDisplayDataPtr)(server_entry->data); - if (!server_data) { - return; /* Oops */ - } - } - /* Server Checkbox is unavailable when framelock is enabled, - * this display cannot be master - * (display is driven by GPU that is connected through a - * secondary connector.). + /* Display can be set as the server if Framelock is disabled and the + * display is serverable. */ - sensitive = (!framelock_enabled && data->masterable); - gtk_widget_set_sensitive(data->server_label, sensitive); - gtk_widget_set_sensitive(data->server_checkbox, sensitive); - - /* When a server is selected, this display can only become a - * client if the X server reports that it can frame lock this - * client correctly. + sensitive = (!framelock_enabled && display_data->serverable); + gtk_widget_set_sensitive(display_data->server_label, sensitive); + gtk_widget_set_sensitive(display_data->server_checkbox, sensitive); + + /* Display can be set as a client if Framelock is disabled and the + * display is clientable. Noce that if a server is currently selected, + * and this display does not match the refresh rate, we still allow users + * to select this display as a client - at which point we'll implicitly + * disable the server. */ - sensitive = (!framelock_enabled && data->slaveable); - gtk_widget_set_sensitive(data->client_label, sensitive); - gtk_widget_set_sensitive(data->client_checkbox, sensitive); + sensitive = (!framelock_enabled && display_data->clientable); + gtk_widget_set_sensitive(display_data->client_label, sensitive); + gtk_widget_set_sensitive(display_data->client_checkbox, sensitive); - /* Gray out the display device's refresh rate when it is not - * the same as the current server's, or the X server tells us - * the client cannot be frame locked. + /* Gray out the display device's refresh rate when it is not the same as + * the current server's, or the X server tells us the client cannot be + * framelocked. */ - sensitive = (data->slaveable && - (!server_data || - framelock_refresh_rates_compatible(server_data->rate_mHz, - data->rate_mHz))); - gtk_widget_set_sensitive(data->rate_label, 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 = (display_data->clientable && + (!server_data || + framelock_refresh_rates_compatible(server_data->rate_mHz, + display_data->rate_mHz))); + gtk_widget_set_sensitive(display_data->rate_label, sensitive); + gtk_widget_set_sensitive(display_data->rate_text, sensitive); + gtk_widget_set_sensitive(display_data->label, sensitive); + + + ctk_config_set_tooltip(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 the GPU's clients list */ + /* If display cannot be a client, make sure it is not set as such */ if (!sensitive && gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON(data->client_checkbox))) { + (GTK_TOGGLE_BUTTON(display_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(display_data->client_checkbox), FALSE); } } @@ -1315,30 +1319,84 @@ static void list_entry_update_controls(CtkFramelock *ctk_framelock, -/** any_gpu_has_selection() ****************************************** +/** has_client_selected() ******************************************** * - * Returns TRUE if any of the gpus have a server/client selected + * Returns TRUE if any of the displays in the tree are configured as + * clients. * */ -static gboolean any_gpu_has_selection(nvListEntryPtr entry) +static gboolean has_client_selected(nvListEntryPtr entry) { if (!entry) return FALSE; - if (entry->data_type == ENTRY_DATA_GPU && - (((nvGPUDataPtr)(entry->data))->server_mask || - ((nvGPUDataPtr)(entry->data))->clients_mask)) { + if (entry->data_type == ENTRY_DATA_DISPLAY) { + nvDisplayDataPtr data = (nvDisplayDataPtr) entry->data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->client_checkbox))) { + return TRUE; + } + } + + if (has_client_selected(entry->children)) { return TRUE; } - if (any_gpu_has_selection(entry->children)) { + return has_client_selected(entry->next_sibling); +} + + + +/** has_server_selected() ******************************************** + * + * Returns TRUE if any of the displays in the tree are configured as + * the server. + * + */ +static gboolean has_server_selected(nvListEntryPtr entry) +{ + if (!entry) return FALSE; + + if (entry->data_type == ENTRY_DATA_DISPLAY) { + nvDisplayDataPtr data = (nvDisplayDataPtr) entry->data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->server_checkbox))) { + return TRUE; + } + } + + if (has_server_selected(entry->children)) { return TRUE; } - if (any_gpu_has_selection(entry->next_sibling)) { + return has_server_selected(entry->next_sibling); +} + + + +/** has_display_selected() ******************************************* + * + * Returns TRUE if any of the displays are selected as a server or + * client. + * + */ +static gboolean has_display_selected(nvListEntryPtr entry) +{ + if (!entry) return FALSE; + + if (entry->data_type == ENTRY_DATA_DISPLAY) { + nvDisplayDataPtr data = (nvDisplayDataPtr) entry->data; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->client_checkbox)) || + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->server_checkbox))) { + return TRUE; + } + } + + if (has_display_selected(entry->children)) { return TRUE; } - return FALSE; + return has_display_selected(entry->next_sibling); } @@ -1354,12 +1412,12 @@ static gboolean any_gpu_has_selection(nvListEntryPtr entry) static void update_framelock_controls(CtkFramelock *ctk_framelock) { nvListTreePtr tree; - gboolean enabled; + gboolean framelock_enabled; gboolean something_selected; tree = (nvListTreePtr)(ctk_framelock->tree); - enabled = ctk_framelock->framelock_enabled; + framelock_enabled = ctk_framelock->framelock_enabled; /* Quadro Sync Buttons */ gtk_widget_set_sensitive(ctk_framelock->remove_devices_button, @@ -1372,18 +1430,17 @@ static void update_framelock_controls(CtkFramelock *ctk_framelock) (G_OBJECT(ctk_framelock->sync_state_button), G_CALLBACK(toggle_sync_enable), (gpointer) ctk_framelock); - - something_selected = - any_gpu_has_selection(((nvListTreePtr)ctk_framelock->tree)->entries); + + something_selected = has_display_selected(tree->entries); gtk_widget_set_sensitive(ctk_framelock->sync_state_button, - tree->nentries && something_selected); + something_selected); gtk_container_remove (GTK_CONTAINER(ctk_framelock->sync_state_button), ctk_framelock->selected_syncing_label); - if (tree->nentries && enabled) { + if (tree->nentries && framelock_enabled) { ctk_framelock->selected_syncing_label = ctk_framelock->disable_syncing_label; gtk_toggle_button_set_active @@ -1407,7 +1464,7 @@ static void update_framelock_controls(CtkFramelock *ctk_framelock) /* Test link */ gtk_widget_set_sensitive(ctk_framelock->test_link_button, - (enabled && tree->server_entry)); + (framelock_enabled && tree->server_entry)); /* Update the frame lock Quadro Sync frame */ list_entry_update_controls(ctk_framelock, tree->entries); @@ -1421,41 +1478,6 @@ static void update_framelock_controls(CtkFramelock *ctk_framelock) -/** get_display_on_gpu() ********************************************* - * - * Returns the display list entry that matches the device mask and - * is connected to the gpu list entry. - * - */ -static nvListEntryPtr get_display_on_gpu(nvListEntryPtr gpu_entry, - guint device_mask) -{ - nvListEntryPtr display_entry; - nvDisplayDataPtr display_data; - - if (!device_mask) { - return NULL; - } - - /* Gather bitmask of server/clients */ - display_entry = gpu_entry->children; - for (display_entry = gpu_entry->children; display_entry; - display_entry = display_entry->next_sibling) { - - if (display_entry->data_type != ENTRY_DATA_DISPLAY) { - continue; - } - - display_data = (nvDisplayDataPtr)(display_entry->data); - if (display_data->device_mask & device_mask) { - return display_entry; - } - } - return NULL; -} - - - /** any_gpu_enabled() ************************************************ * * Returns TRUE if any of the gpus have frame lock enabled. @@ -1743,7 +1765,7 @@ static void list_entry_remove_expander_button(nvListEntryPtr entry) * a tree keep their parent-child relationship. * */ -static nvListEntryPtr list_entry_new(void) +static nvListEntryPtr list_entry_new(nvListTreePtr tree) { nvListEntryPtr entry; @@ -1752,6 +1774,8 @@ static nvListEntryPtr list_entry_new(void) return NULL; } + entry->tree = tree; + /* Create the vertical box that holds this entry and its children */ entry->vbox = gtk_vbox_new(FALSE, 0); @@ -2057,7 +2081,8 @@ static void list_entry_remove_children(nvListEntryPtr entry) * data. * */ -static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data) +static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data, + nvListTreePtr tree) { nvListEntryPtr entry; @@ -2067,7 +2092,7 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data) GtkWidget *padding; - entry = list_entry_new(); + entry = list_entry_new(tree); if (!entry) { return NULL; } @@ -2160,7 +2185,8 @@ static nvListEntryPtr list_entry_new_with_framelock(nvFrameLockDataPtr data) * - Creates a new list entry that will hold the given gpu data. * */ -static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data) +static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data, + nvListTreePtr tree) { nvListEntryPtr entry; @@ -2169,7 +2195,7 @@ static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data) GtkWidget *padding; - entry = list_entry_new(); + entry = list_entry_new(tree); if (!entry) { return NULL; } @@ -2206,7 +2232,8 @@ static nvListEntryPtr list_entry_new_with_gpu(nvGPUDataPtr data) * - Creates a new list entry that will hold the given display data. * */ -static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data) +static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data, + nvListTreePtr tree) { nvListEntryPtr entry; @@ -2216,12 +2243,13 @@ static nvListEntryPtr list_entry_new_with_display(nvDisplayDataPtr data) GtkWidget *padding; - entry = list_entry_new(); + entry = list_entry_new(tree); if (!entry) { return NULL; } entry->data = (gpointer)(data); entry->data_type = ENTRY_DATA_DISPLAY; + entry->ctk_event = CTK_EVENT(ctk_event_new(data->handle)); /* Pack the data's widgets into the list entry data hbox */ @@ -2303,7 +2331,7 @@ static void list_tree_add_entry(nvListTreePtr tree, nvListEntryPtr entry) { nvListEntryPtr e; - if (!tree || !entry || entry->tree) { + if (!tree || !entry) { return; } entry->tree = tree; @@ -2763,18 +2791,28 @@ static void expand_all_clicked(GtkWidget *widget, gpointer data) */ static void toggle_server(GtkWidget *widget, gpointer data) { - nvListEntryPtr entry = (nvListEntryPtr)data; - nvListEntryPtr server_entry = NULL; - nvDisplayDataPtr display_data = (nvDisplayDataPtr)(entry->data); - nvDisplayDataPtr server_entry_display_data = NULL; - nvListTreePtr tree = (nvListTreePtr)(entry->tree); - nvGPUDataPtr gpu_data = (nvGPUDataPtr)(entry->parent->data); + nvListEntryPtr display_entry = (nvListEntryPtr)data; + nvDisplayDataPtr display_data; + nvGPUDataPtr gpu_data; + nvListTreePtr tree; + CtkFramelock *ctk_framelock; gboolean server_checked; - if (entry->data_type != ENTRY_DATA_DISPLAY) { + if (display_entry->data_type != ENTRY_DATA_DISPLAY) { return; } + display_data = (nvDisplayDataPtr)(display_entry->data); + gpu_data = (nvGPUDataPtr)(display_entry->parent->data); + tree = (nvListTreePtr)(display_entry->tree); + ctk_framelock = tree->ctk_framelock; + + /* Make sure FrameLock is disabled on the GPU */ + NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC, + NV_CTRL_FRAMELOCK_SYNC_DISABLE); + gpu_data->enabled = FALSE; + ctk_framelock->framelock_enabled = any_gpu_enabled(tree->entries); + server_checked = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(display_data->server_checkbox)); @@ -2784,35 +2822,35 @@ static void toggle_server(GtkWidget *widget, gpointer data) * it was selected as server before. */ if (server_checked) { - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->client_checkbox), FALSE); - server_entry = get_display_server_entry(tree); - if (server_entry) { - server_entry_display_data = (nvDisplayDataPtr)server_entry->data; + nvDisplayDataPtr server_data = + get_display_server_data(display_entry->tree); + if (server_data && + (server_data != display_data)) { gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(server_entry_display_data->server_checkbox), - FALSE); + (GTK_TOGGLE_BUTTON(server_data->server_checkbox), FALSE); } - } - - entry->tree->server_entry = (server_checked ? entry : NULL); - gpu_data->server_mask = (server_checked ? display_data->device_mask : 0); + tree->server_entry = display_entry; - /* Update X server state, making sure FrameLock sync is disabled */ - NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC, - NV_CTRL_FRAMELOCK_SYNC_DISABLE); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), FALSE); - NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_MASTER, - gpu_data->server_mask); + NvCtrlSetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER); + } else { + if (tree->server_entry == display_entry) { + tree->server_entry = NULL; + } - gpu_data->enabled = FALSE; - entry->tree->ctk_framelock->framelock_enabled = - any_gpu_enabled(entry->tree->entries); + NvCtrlSetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED); + } /* Update GUI state */ - update_framelock_controls(entry->tree->ctk_framelock); + update_framelock_controls(ctk_framelock); - ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config, + ctk_config_statusbar_message(ctk_framelock->ctk_config, "%s frame lock server device.", (server_checked ? "Selected" : "Unselected")); } @@ -2827,47 +2865,53 @@ static void toggle_server(GtkWidget *widget, gpointer data) */ static void toggle_client(GtkWidget *widget, gpointer data) { - nvListEntryPtr entry = (nvListEntryPtr)data; - nvDisplayDataPtr display_data = (nvDisplayDataPtr)(entry->data); - nvGPUDataPtr gpu_data = (nvGPUDataPtr)(entry->parent->data); + nvListEntryPtr display_entry = (nvListEntryPtr)data; + nvDisplayDataPtr display_data; + nvGPUDataPtr gpu_data; + nvListTreePtr tree; + CtkFramelock *ctk_framelock; gboolean client_checked; - if (entry->data_type != ENTRY_DATA_DISPLAY) { + if (display_entry->data_type != ENTRY_DATA_DISPLAY) { return; } + display_data = (nvDisplayDataPtr)(display_entry->data); + gpu_data = (nvGPUDataPtr)(display_entry->parent->data); + tree = (nvListTreePtr)(display_entry->tree); + ctk_framelock = tree->ctk_framelock; + + /* Make sure FrameLock is disabled on the GPU */ + NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC, + NV_CTRL_FRAMELOCK_SYNC_DISABLE); + gpu_data->enabled = FALSE; + ctk_framelock->framelock_enabled = any_gpu_enabled(tree->entries); + client_checked = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(display_data->client_checkbox)); - - if (client_checked) { - gpu_data->clients_mask |= display_data->device_mask; - /* - * if the device is selected as client, uncheck the server box - * for the same. - */ + /* + * if the device is selected as client, uncheck the server box + * for the same. + */ + if (client_checked) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(display_data->server_checkbox), FALSE); + + NvCtrlSetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT); } else { - gpu_data->clients_mask &= ~(display_data->device_mask); + NvCtrlSetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED); } - /* Update X server state, make sure FrameLock Sync is disabled */ - NvCtrlSetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_SYNC, - NV_CTRL_FRAMELOCK_SYNC_DISABLE); - - 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); + update_framelock_controls(ctk_framelock); - ctk_config_statusbar_message(entry->tree->ctk_framelock->ctk_config, + ctk_config_statusbar_message(ctk_framelock->ctk_config, "%s frame lock client device.", (client_checked ? "Selected" : "Unselected")); } @@ -2932,7 +2976,7 @@ static gboolean set_enable_sync_clients(nvListEntryPtr entry_list, /* Go through all entries and activate/disable all entries that * aren't the server. */ - + for (entry = entry_list; entry; entry = entry->next_sibling) { nvGPUDataPtr data; @@ -2941,19 +2985,20 @@ static gboolean set_enable_sync_clients(nvListEntryPtr entry_list, enable); framelock_enabled = (framelock_enabled || something_enabled); } - + if (entry == server_gpu_entry || entry->data_type != ENTRY_DATA_GPU) { continue; } data = (nvGPUDataPtr)(entry->data); - + /* Only send protocol if there is something to enable */ - if (!data->clients_mask) continue; + if (!has_client_selected(entry)) continue; ret = NvCtrlSetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, enable); if (ret != NvCtrlSuccess) continue; + /* Verify state w/ the server */ ret = NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC, &(something_enabled)); if (ret != NvCtrlSuccess) continue; @@ -3534,7 +3579,7 @@ static void toggle_detect_video_mode(GtkToggleButton *button, /** list_entry_update_framelock_status() ***************************** * - * Updates the state of the GUI for a frame lock list entry by + * Updates the dynamic state of the GUI for a frame lock list entry by * querying the current state of the X Server. * */ @@ -3642,8 +3687,8 @@ static void list_entry_update_framelock_status(CtkFramelock *ctk_framelock, /** list_entry_update_gpu_status() *********************************** * - * Updates the state of the GUI for a gpu list entry by querying the - * current state of the X Server. + * Updates the dynamic state of the GUI for a gpu list entry by + * querying the current state of the X Server. * */ static void list_entry_update_gpu_status(CtkFramelock *ctk_framelock, @@ -3670,8 +3715,8 @@ static void list_entry_update_gpu_status(CtkFramelock *ctk_framelock, &house); } - has_client = data->clients_mask; - has_server = data->server_mask; + has_client = has_client_selected(entry); + has_server = has_server_selected(entry); /* Update the Timing LED: * @@ -3702,8 +3747,8 @@ static void list_entry_update_gpu_status(CtkFramelock *ctk_framelock, /** list_entry_update_display_status() ******************************* * - * Updates the state of the GUI for a display list entry by querying - * the current state of the X Server. + * Updates the dynamic state of the GUI for a display list entry by + * querying the current state of the X Server. * */ static void list_entry_update_display_status(CtkFramelock *ctk_framelock, @@ -3741,28 +3786,30 @@ static void list_entry_update_display_status(CtkFramelock *ctk_framelock, gtk_widget_set_sensitive(data->stereo_label, FALSE); update_image(data->stereo_hbox, ctk_framelock->led_grey_pixbuf); } else { - nvGPUDataPtr gpu_data; - gint timing = TRUE; - gint stereo_sync; - /* If the display's GPU is not receiving timing, activate the * stereo label but make sure to gray out the LED. */ gtk_widget_set_sensitive(data->stereo_label, TRUE); if (entry->parent) { - gpu_data = (nvGPUDataPtr)(entry->parent->data); - NvCtrlGetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_TIMING, - &timing); - } - if (!timing) { - update_image(data->stereo_hbox, ctk_framelock->led_grey_pixbuf); - } else { - NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, - &stereo_sync); - update_image(data->stereo_hbox, - (stereo_sync ? ctk_framelock->led_green_pixbuf : - ctk_framelock->led_red_pixbuf)); + GdkPixbuf *pixbuf = ctk_framelock->led_grey_pixbuf; + nvGPUDataPtr gpu_data = (nvGPUDataPtr)(entry->parent->data); + ReturnStatus ret; + int val; + + ret = NvCtrlGetAttribute(gpu_data->handle, NV_CTRL_FRAMELOCK_TIMING, + &val); + if ((ret == NvCtrlSuccess) && + (val == NV_CTRL_FRAMELOCK_TIMING_TRUE)) { + ret = NvCtrlGetAttribute(gpu_data->handle, + NV_CTRL_FRAMELOCK_STEREO_SYNC, &val); + if (ret == NvCtrlSuccess) { + pixbuf = (val == NV_CTRL_FRAMELOCK_STEREO_SYNC_TRUE) ? + ctk_framelock->led_green_pixbuf : + ctk_framelock->led_red_pixbuf; + } + } + update_image(data->stereo_hbox, pixbuf); } } } @@ -4034,176 +4081,262 @@ static void update_display_rate_txt(nvDisplayDataPtr data, -/** gpu_state_received() ********************************************* +/** validate_clients_against_server() ******************************** * - * Signal handler for gpu target events. + * Validates that the given client entries (siblings and any children + * of 'entry') match the server display's refresh rate, and disables + * any client entries that don't. * */ -static void gpu_state_received(GtkObject *object, - gpointer arg1, gpointer user_data) + +static void validate_clients_against_server(nvListEntryPtr entry, + nvDisplayDataPtr server_display_data) { - CtkEventStruct *event = (CtkEventStruct *) arg1; - nvListEntryPtr gpu_entry = (nvListEntryPtr) user_data; - nvGPUDataPtr gpu_data = (nvGPUDataPtr) gpu_entry->data; + nvDisplayDataPtr display_data; - nvListEntryPtr display_entry = NULL; - nvDisplayDataPtr display_data = NULL; + if (!entry || !server_display_data) return; - CtkFramelock *ctk_framelock = gpu_entry->tree->ctk_framelock; - gboolean sensitive; - gboolean checked; - int rateMultiplier = 1; - int precision = 3; + if (entry->data_type == ENTRY_DATA_DISPLAY) { + display_data = (nvDisplayDataPtr)entry->data; - switch (event->attribute) { - case NV_CTRL_FRAMELOCK_MASTER: - - /* Unset the previous master */ - display_entry = get_display_server_entry(gpu_entry->tree); - if (display_entry) { - display_data = (nvDisplayDataPtr)(display_entry->data); - - /* Clear the server checkbox */ - g_signal_handlers_block_by_func - (G_OBJECT(display_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); - + if ((display_data != server_display_data) && + (!framelock_refresh_rates_compatible(server_display_data->rate_mHz, + display_data->rate_mHz))) { gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->server_checkbox), 0); - - g_signal_handlers_unblock_by_func - (G_OBJECT(display_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); - - /* If the server display device is on another gpu, tell the - * X Server we are unsetting it. - */ - if (display_entry->parent != gpu_entry) { - 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); - } - ((nvGPUDataPtr)(display_entry->parent->data))->server_mask = 0; - gpu_entry->tree->server_entry = NULL; + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), FALSE); } + } - /* Set the new master */ - display_entry = get_display_on_gpu(gpu_entry, event->value); - if (display_entry) { - display_data = (nvDisplayDataPtr)(display_entry->data); + validate_clients_against_server(entry->children, + server_display_data); - /* Set the server checkbox */ - g_signal_handlers_block_by_func - (G_OBJECT(display_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->server_checkbox), 1); - - g_signal_handlers_unblock_by_func - (G_OBJECT(display_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); - - gpu_entry->tree->server_entry = display_entry; + validate_clients_against_server(entry->next_sibling, + server_display_data); +} + + + +/** update_display_config() ****************************************** + * + * Updates the UI to reflect the current configuration of a display + * device. This function is meant to be used as a handler for + * NV_CTRL_FRAMELOCK_DISPLAY_CONFIG events, as well as initialization. + * + * As a side effect, calling this function may possibly disable the + * currently selected server, incompatible clients, and/or framelock sync. + * This occurs if a new framelock server is being configured, or a client is + * selected that does not properly match the currently selected server's + * refresh rate. + * + */ + +static void update_display_config(nvListEntryPtr display_entry, int config) +{ + nvDisplayDataPtr display_data = (nvDisplayDataPtr)display_entry->data; + ReturnStatus ret; + NVCTRLAttributeValidValuesRec valid_config; + gboolean serverable = FALSE; + gboolean clientable = FALSE; + + nvDisplayDataPtr old_server_display_data; + + + /* Get what is possible */ + ret = NvCtrlGetValidAttributeValues(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + &valid_config); + + if (ret == NvCtrlSuccess && + (valid_config.type == ATTRIBUTE_TYPE_INT_BITS)) { + if (valid_config.u.bits.ints & + (1<<NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT)) { + clientable = TRUE; } - - gpu_data->server_mask = event->value; + if (valid_config.u.bits.ints & + (1<<NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER)) { + serverable = TRUE; + } + } - /* See if anything was disabled */ - ctk_framelock->framelock_enabled = - any_gpu_enabled(gpu_entry->tree->entries); + display_data->serverable = serverable; + display_data->clientable = clientable; - update_framelock_controls(gpu_entry->tree->ctk_framelock); - break; + if (!clientable && config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT) { + config = NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED; + } + if (!serverable && config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER) { + config = NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED; + } - case NV_CTRL_FRAMELOCK_SLAVES: - - /* Set all client devices on this GPU. If a client is found - * to not match the selected server's refresh rate, unselect - * the server. The user will have to reselect the server. + gtk_widget_set_sensitive(display_data->client_label, clientable); + gtk_widget_set_sensitive(display_data->client_checkbox, clientable); + + gtk_widget_set_sensitive(display_data->server_label, serverable); + gtk_widget_set_sensitive(display_data->server_checkbox, serverable); + + + /* Ensure we'll end up in a valid configuration. + * + * If a client is being enabled: + * - Disable the server if its refresh rate does not match. (It will be + * up to the client to re-select a propper server.) + * + * If a (new) server is being enabled: + * - Disable any previous server. + * - Disable any configured clients that do not match the new server's + * refresh rate. + * + */ + + old_server_display_data = get_display_server_data(display_entry->tree); + + if (config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT) { + /* Disable existing server if the rates don't match, and make user re- + * select the server. */ - for (display_entry = gpu_entry->children; display_entry; - display_entry = display_entry->next_sibling) { - display_data = - (nvDisplayDataPtr)(display_entry->data); - - sensitive = - GTK_WIDGET_IS_SENSITIVE(display_data->client_checkbox); - checked = ((display_data->device_mask) & event->value); - - /* Update the display list entry gui */ - - g_signal_handlers_block_by_func - (G_OBJECT(display_data->client_checkbox), - G_CALLBACK(toggle_client), - (gpointer) display_entry); - + if (old_server_display_data && + (display_data != old_server_display_data) && + (!framelock_refresh_rates_compatible(old_server_display_data->rate_mHz, + display_data->rate_mHz))) { gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->client_checkbox), checked); - - g_signal_handlers_unblock_by_func - (G_OBJECT(display_data->client_checkbox), - G_CALLBACK(toggle_client), - (gpointer) display_entry); - - /* If there is an inconsistency, unselect the server */ - - if (checked && !sensitive && gpu_entry->tree->server_entry) { - - nvListEntryPtr server_entry = - get_display_server_entry(gpu_entry->tree); - nvDisplayDataPtr server_data = - (nvDisplayDataPtr)(server_entry->data); - - /* Clear the server checkbox */ - g_signal_handlers_block_by_func - (G_OBJECT(server_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(server_data->server_checkbox), 0); - - g_signal_handlers_unblock_by_func - (G_OBJECT(server_data->server_checkbox), - G_CALLBACK(toggle_server), - (gpointer) display_entry); + (GTK_TOGGLE_BUTTON(old_server_display_data->server_checkbox), + FALSE); + } - NvCtrlSetAttribute(server_data->handle, - NV_CTRL_FRAMELOCK_MASTER, 0); - ((nvGPUDataPtr)(server_entry->parent->data))->server_mask = 0; - gpu_entry->tree->server_entry = NULL; - } + } else if (config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER) { + /* Disable any previous servers */ + if (old_server_display_data && + (display_data != old_server_display_data)) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(old_server_display_data->server_checkbox), + FALSE); } - /* Save the client state */ - gpu_data->clients_mask = event->value; + /* Disable any configured clients that don't match the new refresh + * rate. + */ + validate_clients_against_server(display_entry->tree->entries, + display_data); + } + - /* See if anything was disabled */ - ctk_framelock->framelock_enabled = - any_gpu_enabled(gpu_entry->tree->entries); + /* Apply the setting to the display device */ + + g_signal_handlers_block_matched(G_OBJECT(display_entry->ctk_event), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + (gpointer)display_entry); + + if (config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), TRUE); + } else { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->client_checkbox), FALSE); + } + + if (config == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER) { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox), TRUE); + } else { + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(display_data->server_checkbox), FALSE); + } + + g_signal_handlers_unblock_matched(G_OBJECT(display_entry->ctk_event), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + (gpointer)display_entry); +} + + + +/** display_state_received() ***************************************** + * + * Signal handler for display target events. + * + */ +static void display_state_received(GtkObject *object, + gpointer arg1, gpointer user_data) +{ + CtkEventStruct *event = (CtkEventStruct *) arg1; + nvListEntryPtr display_entry = (nvListEntryPtr) user_data; + nvDisplayDataPtr display_data; + nvListTreePtr tree; + CtkFramelock *ctk_framelock; + + int rateMultiplier = 1; + int precision = 3; + + if (!display_entry || + !display_entry->data || + !display_entry->data_type != ENTRY_DATA_DISPLAY) { + return; + } - update_framelock_controls(gpu_entry->tree->ctk_framelock); + display_data = (nvDisplayDataPtr) display_entry->data; + tree = display_entry->tree; + ctk_framelock = tree->ctk_framelock; + + switch (event->attribute) { + + case NV_CTRL_REFRESH_RATE: + rateMultiplier = 10; + precision = 2; + /* fallthrough */ + case NV_CTRL_REFRESH_RATE_3: + update_display_rate_txt(display_data, + event->value * rateMultiplier, /* rate_mHz */ + precision); + + /* Update the UI */ + update_framelock_controls(ctk_framelock); break; - + + case NV_CTRL_FRAMELOCK_DISPLAY_CONFIG: + update_display_config(display_entry, event->value); + + /* Update the UI */ + update_framelock_controls(ctk_framelock); + break; + } +} + + + +/** gpu_state_received() ********************************************* + * + * Signal handler for gpu target events. + * + */ +static void gpu_state_received(GtkObject *object, + gpointer arg1, gpointer user_data) +{ + CtkEventStruct *event = (CtkEventStruct *) arg1; + nvListEntryPtr gpu_entry = (nvListEntryPtr) user_data; + nvGPUDataPtr gpu_data; + nvListTreePtr tree; + CtkFramelock *ctk_framelock; + + if (!gpu_entry || + !gpu_entry->data || + !gpu_entry->data_type != ENTRY_DATA_GPU) { + return; + } + + gpu_data = (nvGPUDataPtr) gpu_entry->data; + tree = gpu_entry->tree; + ctk_framelock = tree->ctk_framelock; + + switch (event->attribute) { case NV_CTRL_FRAMELOCK_SYNC: /* Cache the enable/disable state of the gpu sync */ gpu_data->enabled = event->value; - + /* Look to see if any gpu is enabled/disabled */ ctk_framelock->framelock_enabled = - any_gpu_enabled(gpu_entry->tree->entries); + any_gpu_enabled(tree->entries); g_signal_handlers_block_by_func (G_OBJECT(ctk_framelock->sync_state_button), @@ -4219,10 +4352,9 @@ static void gpu_state_received(GtkObject *object, G_CALLBACK(toggle_sync_enable), (gpointer) ctk_framelock); - update_framelock_controls(gpu_entry->tree->ctk_framelock); + update_framelock_controls(ctk_framelock); break; - case NV_CTRL_FRAMELOCK_TEST_SIGNAL: switch (event->value) { case NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE: @@ -4248,11 +4380,11 @@ static void gpu_state_received(GtkObject *object, (G_OBJECT(ctk_framelock->test_link_button), G_CALLBACK(toggle_test_link), (gpointer) ctk_framelock); - + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), ctk_framelock->test_link_enabled); - + g_signal_handlers_unblock_by_func (G_OBJECT(ctk_framelock->test_link_button), G_CALLBACK(toggle_test_link), @@ -4264,39 +4396,11 @@ static void gpu_state_received(GtkObject *object, "Test link complete.")); break; - - case NV_CTRL_REFRESH_RATE: - rateMultiplier = 10; - precision = 2; - /* fallthrough */ - case NV_CTRL_REFRESH_RATE_3: - /* Update the display device's refresh rate */ - display_entry = get_display_on_gpu(gpu_entry, event->display_mask); - if (display_entry && display_entry->data) { - display_data = - (nvDisplayDataPtr)(display_entry->data); - - update_display_rate_txt(display_data, - event->value * rateMultiplier, - precision); - } - - /* Make sure the framelock controls are in a consistent state */ - update_framelock_controls(ctk_framelock); - break; - - - case NV_CTRL_FRAMELOCK_SLAVEABLE: - /* Update slaveable relationships in the GUI */ - update_framelock_controls(ctk_framelock); - break; - - default: /* Oops */ break; } - + } /* gpu_state_received() */ @@ -5088,238 +5192,203 @@ static void remove_devices_response(GtkWidget *button, gint response, -/** add_display_devices() ******************************************** +/** add_display_device() ********************************************* * - * Adds (as children list entries) all enabled display devices that - * are bound to the given GPU List Entry. + * Adds an display device to the give GPU entry. * */ -static void add_display_devices(CtkFramelock *ctk_framelock, - nvListEntryPtr gpu_entry) +static gboolean add_display_device(CtkFramelock *ctk_framelock, + nvListEntryPtr gpu_entry, + int display_id) { - nvDisplayDataPtr display_data = NULL; - - nvGPUDataPtr gpu_data; - nvListEntryPtr entry; - ReturnStatus ret; - - unsigned int enabled_displays; - unsigned int display_mask; + nvGPUDataPtr gpu_data = (nvGPUDataPtr)(gpu_entry->data); + nvDisplayDataPtr display_data = NULL; + nvListEntryPtr entry = NULL; + nvListTreePtr tree = (nvListTreePtr)(ctk_framelock->tree); - unsigned int master_mask; - unsigned int slaves_mask; + ReturnStatus ret; + int val; + int rate; + int precision; + gboolean hdmi3D; + int i; - nvListEntryPtr server_entry = NULL; + display_data = (nvDisplayDataPtr) calloc(1, sizeof(nvDisplayDataRec)); + if (!display_data) { + goto fail; + } - if (!gpu_entry || gpu_entry->data_type != ENTRY_DATA_GPU) { + display_data->handle = + NvCtrlAttributeInit(NvCtrlGetDisplayPtr(gpu_data->handle), + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id, + NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM); + if (!display_data->handle) { goto fail; } - server_entry = - get_display_server_entry((nvListTreePtr)(ctk_framelock->tree)); - gpu_data = (nvGPUDataPtr)(gpu_entry->data); + /* Create, pack and link the display device UI widgets */ - /* Query list of devices on this GPU. */ - ret = NvCtrlGetAttribute(gpu_data->handle, - NV_CTRL_ENABLED_DISPLAYS, - (int *)&enabled_displays); - if (ret != NvCtrlSuccess || !enabled_displays) { - goto fail; - } + display_data->label = gtk_label_new(""); - /* Query master device */ - ret = NvCtrlGetAttribute(gpu_data->handle, - NV_CTRL_FRAMELOCK_MASTER, - (int *)&master_mask); - if (ret != NvCtrlSuccess) { - goto fail; - } + display_data->server_label = gtk_label_new("Server"); + display_data->server_checkbox = gtk_check_button_new(); + ctk_config_set_tooltip(ctk_framelock->ctk_config, + display_data->server_checkbox, + __server_checkbox_help); - /* Query slave devices */ - ret = NvCtrlGetAttribute(gpu_data->handle, - NV_CTRL_FRAMELOCK_SLAVES, - (int *)&slaves_mask); - if (ret != NvCtrlSuccess) { + display_data->client_label = gtk_label_new("Client"); + display_data->client_checkbox = gtk_check_button_new(); + ctk_config_set_tooltip(ctk_framelock->ctk_config, + display_data->client_checkbox, + __client_checkbox_help); + + display_data->rate_label = gtk_label_new("Refresh:"); + display_data->rate_text = gtk_label_new(""); + + display_data->stereo_label = gtk_label_new("Stereo"); + display_data->stereo_hbox = gtk_hbox_new(FALSE, 0); + + entry = list_entry_new_with_display(display_data, tree); + if (!entry) { goto fail; } - - /* If the tree already has a master and this display is also set - * as master, unset this entry and make it a slave. */ - if (server_entry && master_mask) { - /* 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; + list_entry_add_child(gpu_entry, entry); - ret = NvCtrlSetAttribute(gpu_data->handle, - NV_CTRL_FRAMELOCK_MASTER, 0); - if (ret != NvCtrlSuccess) { - goto fail; - } - slaves_mask |= master_mask; - master_mask = 0; - ret = NvCtrlSetAttribute(gpu_data->handle, - NV_CTRL_FRAMELOCK_SLAVES, slaves_mask); + + /* Query current configuration */ + + /* Name */ + update_entry_label(ctk_framelock, entry); + + /* Refresh rate */ + ret = NvCtrlGetAttribute(display_data->handle, NV_CTRL_REFRESH_RATE_3, + &rate); + if (ret != NvCtrlSuccess) { + ret = NvCtrlGetAttribute(display_data->handle, NV_CTRL_REFRESH_RATE, + &rate); if (ret != NvCtrlSuccess) { - goto fail; + rate = 0; + precision = 0; + } else { + rate = rate * 10; + precision = 2; } + } else { + precision = 3; } + update_display_rate_txt(display_data, rate, precision); + + /* HDMI 3D */ + ret = NvCtrlGetDisplayAttribute(display_data->handle, + display_data->device_mask, + NV_CTRL_DPY_HDMI_3D, &hdmi3D); + display_data->hdmi3D = hdmi3D; - /* Cache the server/clients masks */ - gpu_data->server_mask = master_mask; - gpu_data->clients_mask = slaves_mask; + /* Configuration */ + ret = NvCtrlGetAttribute(display_data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + &val); + if (ret != NvCtrlSuccess) { + val = NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED; + } + if (val == NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER) { + tree->server_entry = entry; + } - /* Add all enabled displays found on the GPU */ - display_mask = 1; - while (display_mask) { - int rate; - int precision; - gboolean hdmi3D; + update_display_config(entry, val); - if (display_mask & enabled_displays) { - /* Create the display structure */ - display_data = - (nvDisplayDataPtr) calloc(1, sizeof(nvDisplayDataRec)); - if (!display_data) { - goto fail; - } + /* Update status (LEDs) based on current state */ - /* Setup the display information */ - display_data->handle = gpu_data->handle; - display_data->device_mask = display_mask; + list_entry_update_status(ctk_framelock, entry); - ret = NvCtrlGetDisplayAttribute(gpu_data->handle, - display_mask, - NV_CTRL_FRAMELOCK_MASTERABLE, - &(display_data->masterable)); - if (ret != NvCtrlSuccess) { - goto fail; - } - display_data->label = gtk_label_new(""); - - display_data->server_label = gtk_label_new("Server"); - display_data->server_checkbox = gtk_check_button_new(); - ctk_config_set_tooltip(ctk_framelock->ctk_config, - display_data->server_checkbox, - __server_checkbox_help); - - display_data->client_label = gtk_label_new("Client"); - display_data->client_checkbox = gtk_check_button_new(); - ctk_config_set_tooltip(ctk_framelock->ctk_config, - display_data->client_checkbox, - __client_checkbox_help); - - - display_data->rate_label = gtk_label_new("Refresh:"); - display_data->rate_text = gtk_label_new(""); - - display_data->stereo_label = gtk_label_new("Stereo"); - display_data->stereo_hbox = gtk_hbox_new(FALSE, 0); - - /* Create the display entry */ - entry = list_entry_new_with_display(display_data); - - update_entry_label(ctk_framelock, entry); - list_entry_update_status(ctk_framelock, entry); - - /* Add display to GPU entry */ - list_entry_add_child(gpu_entry, entry); - - /* Determine if display is HDMI 3D */ - ret = NvCtrlGetDisplayAttribute(display_data->handle, - display_data->device_mask, - NV_CTRL_DPY_HDMI_3D, &hdmi3D); - - display_data->hdmi3D = hdmi3D; - - /* Refresh Rate */ - ret = NvCtrlGetDisplayAttribute(display_data->handle, - display_data->device_mask, - NV_CTRL_REFRESH_RATE_3, &rate); - if (ret != NvCtrlSuccess) { - ret = NvCtrlGetDisplayAttribute(display_data->handle, - display_data->device_mask, - NV_CTRL_REFRESH_RATE, &rate); - if (ret != NvCtrlSuccess) { - rate = 0; - precision = 0; - } else { - rate = rate * 10; - precision = 2; - } - } else { - precision = 3; - } - update_display_rate_txt(display_data, rate, precision); - - /* Setup state */ - if (!display_data->masterable) { - gtk_widget_set_sensitive(display_data->server_label, FALSE); - gtk_widget_set_sensitive(display_data->server_checkbox, FALSE); - - } else if (master_mask & display_mask) { - - /* If this entry is the new master, make the tree point - * point to it so other displays that may have the master - * mask aren't added as masters too by mistake. - * - * NOTE: At this point the entry will not actually - * be in the tree. This gets resolved since - * by adding this display device the parent - * GPU and frame lock devices will also be - * added. If this changes (display device - * gets added but for some reason the GPU/ - * frame lock device get thrown out), then - * more code will be required to make sure - * the tree->selected_entry is set to NULL - * (if it was NULL before.) - */ - ((nvListTreePtr)(ctk_framelock->tree))->server_entry = - entry; - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->server_checkbox), TRUE); - gtk_widget_set_sensitive(display_data->client_label, FALSE); - gtk_widget_set_sensitive(display_data->client_checkbox, FALSE); - } + /* Listen to events */ - /* Set display device as slave */ - if (slaves_mask & display_mask) { - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(display_data->client_checkbox), TRUE); - gtk_widget_set_sensitive(display_data->server_label, FALSE); - gtk_widget_set_sensitive(display_data->server_checkbox, FALSE); - } - - /* Connect signals */ - g_signal_connect(G_OBJECT(display_data->server_checkbox), - "toggled", - G_CALLBACK(toggle_server), - (gpointer) entry); - - g_signal_connect(G_OBJECT(display_data->client_checkbox), - "toggled", - G_CALLBACK(toggle_client), - (gpointer) entry); - } - display_mask <<= 1; + for (i = 0; i < ARRAY_LEN(__DisplaySignals); i++) { + g_signal_connect(G_OBJECT(entry->ctk_event), + __DisplaySignals[i], + G_CALLBACK(display_state_received), + (gpointer) entry); } - return; + g_signal_connect(G_OBJECT(display_data->server_checkbox), + "toggled", + G_CALLBACK(toggle_server), + (gpointer) entry); + g_signal_connect(G_OBJECT(display_data->client_checkbox), + "toggled", + G_CALLBACK(toggle_client), + (gpointer) entry); + return TRUE; - /* Handle failures */ fail: - display_data_free(display_data); + if (entry) { + list_entry_free(entry); + } else if (display_data) { + display_data_free(display_data); + } + return FALSE; +} + + + +/** add_display_devices() ******************************************** + * + * Adds (as children list entries) all enabled display devices that + * are bound to the given GPU entry. + * + */ +static void add_display_devices(CtkFramelock *ctk_framelock, + nvListEntryPtr gpu_entry) +{ + nvGPUDataPtr gpu_data; + ReturnStatus ret; + int *pData; + + if (!gpu_entry || gpu_entry->data_type != ENTRY_DATA_GPU) { + return; + } + + gpu_data = (nvGPUDataPtr)(gpu_entry->data); + ret = + NvCtrlGetBinaryAttribute(gpu_data->handle, 0, + NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, + (unsigned char **)(&pData), + NULL); + if (ret == NvCtrlSuccess) { + int i; + + for (i = 0; i < pData[0]; i++) { + int display_id = pData[1+i]; + Bool valid; + int enabled; + + /* Only add enabled display devices */ + valid = + XNVCTRLQueryTargetAttribute(NvCtrlGetDisplayPtr(gpu_data->handle), + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id, + 0, + NV_CTRL_DISPLAY_ENABLED, + &enabled); + if (valid && enabled) { + add_display_device(ctk_framelock, gpu_entry, display_id); + } + } + XFree(pData); + } } + /** add_gpu_devices() ************************************************ * * Adds (as children list entries) all GPU devices that are bound to @@ -5381,8 +5450,9 @@ static void add_gpu_devices(CtkFramelock *ctk_framelock, gpu_data->timing_hbox = gtk_hbox_new(FALSE, 0); /* Create the GPU list entry */ - entry = list_entry_new_with_gpu(gpu_data); - + entry = list_entry_new_with_gpu(gpu_data, + (nvListTreePtr)(ctk_framelock->tree)); + update_entry_label(ctk_framelock, entry); list_entry_update_status(ctk_framelock, entry); @@ -5527,7 +5597,8 @@ static void add_framelock_devices(CtkFramelock *ctk_framelock, framelock_data->server_id = server_id; /* Create the frame lock list entry */ - entry = list_entry_new_with_framelock(framelock_data); + entry = list_entry_new_with_framelock(framelock_data, + (nvListTreePtr)(ctk_framelock->tree)); update_entry_label(ctk_framelock, entry); list_entry_update_status(ctk_framelock, entry); @@ -5711,13 +5782,13 @@ static void add_devices(CtkFramelock *ctk_framelock, * to the parsed attribute list. * */ -#define __ADD_ATTR(x,y,z) \ +#define __ADD_ATTR(ATTR,VAL) \ a.display = display_name; \ a.target_type = target_type; \ a.target_id = target_id; \ - a.attr = (x); \ - a.val.i = (y); \ - a.display_device_mask = (z); \ + a.attr = (ATTR); \ + a.val.i = (VAL); \ + a.display_device_mask = 0; \ a.flags |= NV_PARSER_HAS_TARGET; \ nv_parsed_attribute_add(head, &a); @@ -5744,18 +5815,18 @@ static void add_entry_to_parsed_attributes(nvListEntryPtr entry, display_name = NvCtrlGetDisplayName(data->handle); target_type = NV_CTRL_TARGET_TYPE_FRAMELOCK; target_id = NvCtrlGetTargetId(data->handle); - + NvCtrlGetAttribute(data->handle, NV_CTRL_USE_HOUSE_SYNC, &use_house_sync); - __ADD_ATTR(NV_CTRL_USE_HOUSE_SYNC, use_house_sync, 0); + __ADD_ATTR(NV_CTRL_USE_HOUSE_SYNC, use_house_sync); /* If use house sync is enabled, also save other house sync info */ if (use_house_sync) { int sync_interval; int sync_edge; int video_mode; - + NvCtrlGetAttribute(data->handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL, &sync_interval); @@ -5766,35 +5837,40 @@ static void add_entry_to_parsed_attributes(nvListEntryPtr entry, NV_CTRL_FRAMELOCK_VIDEO_MODE, &video_mode); - __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_INTERVAL, sync_interval, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_POLARITY, sync_edge, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_VIDEO_MODE, video_mode, 0); + __ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_INTERVAL, sync_interval); + __ADD_ATTR(NV_CTRL_FRAMELOCK_POLARITY, sync_edge); + __ADD_ATTR(NV_CTRL_FRAMELOCK_VIDEO_MODE, video_mode); } if (display_name) { free(display_name); } - } + } break; case ENTRY_DATA_GPU: + /* Nothing to save for GPU targets */ + break; + + case ENTRY_DATA_DISPLAY: { - nvGPUDataPtr data = (nvGPUDataPtr)(entry->data); - display_name = NvCtrlGetDisplayName(data->handle); - target_type = NV_CTRL_TARGET_TYPE_GPU; - target_id = NvCtrlGetTargetId(data->handle); + nvDisplayDataPtr data = (nvDisplayDataPtr)(entry->data); + int config; + ReturnStatus ret; - __ADD_ATTR(NV_CTRL_FRAMELOCK_MASTER, data->server_mask, 0); - __ADD_ATTR(NV_CTRL_FRAMELOCK_SLAVES, data->clients_mask, 0); + display_name = NvCtrlGetDisplayName(data->handle); - if (display_name) { - free(display_name); - } - } - break; + ret = NvCtrlGetAttribute(data->handle, + NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, + &config); + if (ret != NvCtrlSuccess) { + config = NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED; + } + target_type = NV_CTRL_TARGET_TYPE_DISPLAY; + target_id = NvCtrlGetTargetId(data->handle); - case ENTRY_DATA_DISPLAY: - /* Nothing to save */ + __ADD_ATTR(NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, config); + } break; default: @@ -5816,17 +5892,13 @@ static void add_entry_to_parsed_attributes(nvListEntryPtr entry, static void add_entries_to_parsed_attributes(nvListEntryPtr entry, ParsedAttribute *head) { - if (!entry) return; - - /* Add GPU entries to parsed attributes list */ - if (entry->data_type == ENTRY_DATA_GPU) { - add_entry_to_parsed_attributes(entry, head); + if (!entry) { + return; } - - /* add children */ - add_entries_to_parsed_attributes(entry->children, head); - /* add siblings */ + add_entry_to_parsed_attributes(entry, head); + + add_entries_to_parsed_attributes(entry->children, head); add_entries_to_parsed_attributes(entry->next_sibling, head); } @@ -5837,8 +5909,9 @@ static void add_entries_to_parsed_attributes(nvListEntryPtr entry, * Add to the ParsedAttribute list any attributes that we want saved * in the config file. * - * This includes all the clients/server bitmasks for all GPUs and - * the house sync settings of the selected master frame lock device. + * This includes all the clients/server display configurations for all + * GPUs and the house sync settings of the selected master frame lock + * device. * */ void ctk_framelock_config_file_attributes(GtkWidget *w, diff --git a/src/gtk+-2.x/ctkgpu.c b/src/gtk+-2.x/ctkgpu.c index 2f9d7d2..e681c86 100644 --- a/src/gtk+-2.x/ctkgpu.c +++ b/src/gtk+-2.x/ctkgpu.c @@ -22,7 +22,9 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include "msg.h" #include "parse.h" #include "ctkbanner.h" @@ -35,11 +37,17 @@ static void probe_displays_received(GtkObject *object, gpointer arg1, gpointer user_data); -static gboolean update_gpu_memory_used(gpointer); +static gboolean update_gpu_usage(gpointer); #define ARRAY_ELEMENTS 16 #define DEFAULT_UPDATE_GPU_INFO_TIME_INTERVAL 3000 +typedef struct { + gint graphics; + gint video; + gint pcie; +} utilizationEntry, * utilizationEntryPtr; + GType ctk_gpu_get_type( void ) @@ -133,44 +141,43 @@ void get_bus_type_str(NvCtrlAttributeHandle *handle, } } -void get_bus_id_str(NvCtrlAttributeHandle *handle, - gchar **pci_bus_id) +gchar *get_bus_id_str(NvCtrlAttributeHandle *handle) { int ret; int pci_domain, pci_bus, pci_device, pci_func; gchar *bus_id; - const gchar *__pci_bus_id_unknown = "?@?:?:?"; /* NV_CTRL_PCI_DOMAIN & NV_CTRL_PCI_BUS & * NV_CTRL_PCI_DEVICE & NV__CTRL_PCI_FUNCTION */ - bus_id = NULL; ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_DOMAIN, &pci_domain); - if (ret != NvCtrlSuccess) goto bus_id_fallback; + if (ret != NvCtrlSuccess) { + return NULL; + } ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_BUS, &pci_bus); - if (ret != NvCtrlSuccess) goto bus_id_fallback; + if (ret != NvCtrlSuccess) { + return NULL; + } ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_DEVICE, &pci_device); - if (ret != NvCtrlSuccess) goto bus_id_fallback; + if (ret != NvCtrlSuccess) { + return NULL; + } ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_FUNCTION, &pci_func); - if (ret != NvCtrlSuccess) goto bus_id_fallback; - - bus_id = malloc(32); - if (bus_id) { - xconfigFormatPciBusString(bus_id, 32, pci_domain, pci_bus, - pci_device, pci_func); + if (ret != NvCtrlSuccess) { + return NULL; } - bus_id_fallback: - + bus_id = g_malloc(32); if (!bus_id) { - bus_id = g_strdup(__pci_bus_id_unknown); + return NULL; } - - *pci_bus_id = bus_id; + xconfigFormatPciBusString(bus_id, 32, pci_domain, pci_bus, + pci_device, pci_func); + return bus_id; } @@ -249,20 +256,17 @@ GtkWidget* ctk_gpu_new( } /* Get Bus related information */ - - get_bus_id_str(handle, &pci_bus_id); - + + pci_bus_id = get_bus_id_str(handle); + /* NV_CTRL_PCI_ID */ - pci_device_id[ARRAY_ELEMENTS-1] = '\0'; - pci_vendor_id[ARRAY_ELEMENTS-1] = '\0'; + memset(&pci_device_id, 0, sizeof(pci_device_id)); + memset(&pci_vendor_id, 0, sizeof(pci_vendor_id)); ret = NvCtrlGetAttribute(handle, NV_CTRL_PCI_ID, &pci_id); - if (ret != NvCtrlSuccess) { - snprintf(pci_device_id, ARRAY_ELEMENTS, "Unknown"); - snprintf(pci_vendor_id, ARRAY_ELEMENTS, "Unknown"); - } else { + if (ret == NvCtrlSuccess) { snprintf(pci_device_id, ARRAY_ELEMENTS, "0x%04x", (pci_id & 0xFFFF)); snprintf(pci_vendor_id, ARRAY_ELEMENTS, "0x%04x", (pci_id >> 16)); } @@ -382,6 +386,7 @@ GtkWidget* ctk_gpu_new( ctk_gpu->handle = handle; ctk_gpu->gpu_cores = (gpu_cores != NULL) ? 1 : 0; + ctk_gpu->gpu_uuid = (gpu_uuid != NULL) ? 1 : 0; ctk_gpu->memory_interface = (memory_interface != NULL) ? 1 : 0; ctk_gpu->ctk_config = ctk_config; ctk_gpu->ctk_event = ctk_event; @@ -438,18 +443,22 @@ GtkWidget* ctk_gpu_new( add_table_row(table, row++, 0, 0.5, "Graphics Processor:", 0, 0.5, product_name); - add_table_row(table, row++, - 0, 0.5, "GPU UUID:", - 0, 0.5, gpu_uuid); + if ( ctk_gpu->gpu_uuid ) { + add_table_row(table, row++, + 0, 0.5, "GPU UUID:", + 0, 0.5, gpu_uuid); + } if ( ctk_gpu->gpu_cores ) { gtk_table_resize(GTK_TABLE(table), ++total_rows, 2); add_table_row(table, row++, 0, 0.5, "CUDA Cores:", 0, 0.5, gpu_cores); } - add_table_row(table, row++, - 0, 0.5, "VBIOS Version:", - 0, 0.5, vbios_version); + if ( vbios_version ) { + add_table_row(table, row++, + 0, 0.5, "VBIOS Version:", + 0, 0.5, vbios_version); + } add_table_row(table, row++, 0, 0.5, "Total Memory:", 0, 0.5, video_ram); @@ -460,30 +469,45 @@ GtkWidget* ctk_gpu_new( add_table_row(table, row++, 0, 0.5, "Used Dedicated Memory:", 0, 0.5, NULL); - update_gpu_memory_used(ctk_gpu); if ( ctk_gpu->memory_interface ) { gtk_table_resize(GTK_TABLE(table), ++total_rows, 2); add_table_row(table, row++, 0, 0.5, "Memory Interface:", 0, 0.5, memory_interface); } + ctk_gpu->gpu_utilization_label = + add_table_row(table, row++, + 0, 0.5, "GPU Utilization:", + 0, 0.5, NULL); + ctk_gpu->video_utilization_label = + add_table_row(table, row++, + 0, 0.5, "Video Engine Utilization:", + 0, 0.5, NULL); /* spacing */ row += 3; add_table_row(table, row++, 0, 0.5, "Bus Type:", 0, 0.5, bus); - add_table_row(table, row++, - 0, 0.5, "Bus ID:", - 0, 0.5, pci_bus_id); - add_table_row(table, row++, - 0, 0.5, "PCI Device ID:", - 0, 0.5, pci_device_id); - add_table_row(table, row++, - 0, 0.5, "PCI Vendor ID:", - 0, 0.5, pci_vendor_id); - add_table_row(table, row++, - 0, 0.5, "IRQ:", - 0, 0.5, irq); + if ( pci_bus_id ) { + add_table_row(table, row++, + 0, 0.5, "Bus ID:", + 0, 0.5, pci_bus_id); + } + if ( pci_device_id[0] ) { + add_table_row(table, row++, + 0, 0.5, "PCI Device ID:", + 0, 0.5, pci_device_id); + } + if (pci_vendor_id[0] ) { + add_table_row(table, row++, + 0, 0.5, "PCI Vendor ID:", + 0, 0.5, pci_vendor_id); + } + if ( irq ) { + add_table_row(table, row++, + 0, 0.5, "IRQ:", + 0, 0.5, irq); + } if (ctk_gpu->pcie_gen_queriable) { /* spacing */ row += 3; @@ -496,12 +520,18 @@ GtkWidget* ctk_gpu_new( add_table_row(table, row++, 0, 0.5, "Maximum PCIe Link Speed:", 0, 0.5, link_speed_str); + ctk_gpu->pcie_utilization_label = + add_table_row(table, row++, + 0, 0.5, "PCIe Bandwidth Utilization:", + 0, 0.5, NULL); + g_free(link_speed_str); g_free(link_width_str); g_free(pcie_gen_str); row++; } + update_gpu_usage(ctk_gpu); /* spacing */ row += 3; add_table_row(table, row++, @@ -543,7 +573,7 @@ GtkWidget* ctk_gpu_new( ctk_config_add_timer(ctk_gpu->ctk_config, DEFAULT_UPDATE_GPU_INFO_TIME_INTERVAL, tmp_str, - (GSourceFunc) update_gpu_memory_used, + (GSourceFunc) update_gpu_usage, (gpointer) ctk_gpu); g_free(tmp_str); @@ -571,6 +601,12 @@ GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *table, ctk_help_heading(b, &i, "Graphics Processor"); ctk_help_para(b, &i, "This is the product name of the GPU."); + if (ctk_gpu->gpu_uuid) { + ctk_help_heading(b, &i, "GPU UUID"); + ctk_help_para(b, &i, "This is the global unique identifier " + "of the GPU."); + } + if (ctk_gpu->gpu_cores) { ctk_help_heading(b, &i, "CUDA Cores"); ctk_help_para(b, &i, "This is the number of CUDA cores supported by " @@ -603,6 +639,12 @@ GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *table, "memory interface."); } + ctk_help_heading(b, &i, "GPU Utilization"); + ctk_help_para(b, &i, "This is the percentage usage of graphics engine."); + + ctk_help_heading(b, &i, "Video Engine Utilization"); + ctk_help_para(b, &i, "This is the percentage usage of video engine"); + ctk_help_heading(b, &i, "Bus Type"); ctk_help_para(b, &i, "This is the bus type which is " "used to connect the NVIDIA GPU to the rest of " @@ -646,7 +688,12 @@ GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *table, "This is expressed in gigatransfers per second " "(GT/s). The link may be dynamically trained to a " "slower speed, based on the GPU's utilization and " - "performance settings."); + "performance settings."); + + ctk_help_heading(b, &i, "PCIe Bandwidth Utilization"); + ctk_help_para(b, &i, "This is the percentage usage of " + "PCIe bandwidth."); + } ctk_help_heading(b, &i, "X Screens"); @@ -676,13 +723,35 @@ static void probe_displays_received(GtkObject *object, gpointer arg1, g_free(str); } -static gboolean update_gpu_memory_used(gpointer user_data) + + +static void apply_gpu_utilization_token(char *token, char *value, void *data) +{ + utilizationEntryPtr pEntry = (utilizationEntryPtr) data; + + if (!strcasecmp("graphics", token)) { + pEntry->graphics = atoi(value); + } else if (!strcasecmp("video", token)) { + pEntry->video = atoi(value); + } else if (!strcasecmp("pcie", token)) { + pEntry->pcie = atoi(value); + } else { + nv_warning_msg("Unknown GPU utilization token value pair: %s=%s", + token, value); + } +} + + + +static gboolean update_gpu_usage(gpointer user_data) { CtkGpu *ctk_gpu; gchar *memory_text; + gchar *utilization_text = NULL; ReturnStatus ret; - int value; - static int num_failures = 0; + gchar *utilizationStr = NULL; + gint value = 0; + utilizationEntry entry; ctk_gpu = CTK_GPU(user_data); @@ -691,9 +760,7 @@ static gboolean update_gpu_memory_used(gpointer user_data) &value); if (ret != NvCtrlSuccess || value > ctk_gpu->gpu_memory || value < 0) { gtk_label_set_text(GTK_LABEL(ctk_gpu->gpu_memory_used_label), "Unknown"); - if(num_failures++ >= 10) { - return FALSE; - } + return FALSE; } else { if (ctk_gpu->gpu_memory > 0) { memory_text = g_strdup_printf("%d MB (%.0f%%)", @@ -708,6 +775,47 @@ static gboolean update_gpu_memory_used(gpointer user_data) g_free(memory_text); } + /* GPU utilization */ + ret = NvCtrlGetStringAttribute(ctk_gpu->handle, + NV_CTRL_STRING_GPU_UTILIZATION, + &utilizationStr); + if (ret != NvCtrlSuccess) { + gtk_label_set_text(GTK_LABEL(ctk_gpu->gpu_utilization_label), "Unknown"); + gtk_label_set_text(GTK_LABEL(ctk_gpu->video_utilization_label), + "Unknown"); + if (ctk_gpu->pcie_utilization_label) { + gtk_label_set_text(GTK_LABEL(ctk_gpu->pcie_utilization_label), + "Unknown"); + } + return FALSE; + } else { + memset(&entry, -1, sizeof(&entry)); + parse_token_value_pairs(utilizationStr, apply_gpu_utilization_token, + &entry); + if (entry.graphics != -1) { + utilization_text = g_strdup_printf("%d %%", + entry.graphics); + + gtk_label_set_text(GTK_LABEL(ctk_gpu->gpu_utilization_label), + utilization_text); + } + if (entry.video != -1) { + utilization_text = g_strdup_printf("%d %%", + entry.video); + + gtk_label_set_text(GTK_LABEL(ctk_gpu->video_utilization_label), + utilization_text); + } + if ((entry.pcie != -1) && + (ctk_gpu->pcie_utilization_label)) { + utilization_text = g_strdup_printf("%d %%", + entry.pcie); + + gtk_label_set_text(GTK_LABEL(ctk_gpu->pcie_utilization_label), + utilization_text); + } + g_free(utilization_text); + } return TRUE; } @@ -715,10 +823,14 @@ void ctk_gpu_page_select(GtkWidget *widget) { CtkGpu *ctk_gpu = CTK_GPU(widget); + /* Update GPU usage */ + + update_gpu_usage(ctk_gpu); + /* Start the gpu timer */ ctk_config_start_timer(ctk_gpu->ctk_config, - (GSourceFunc) update_gpu_memory_used, + (GSourceFunc) update_gpu_usage, (gpointer) ctk_gpu); } @@ -729,7 +841,7 @@ void ctk_gpu_page_unselect(GtkWidget *widget) /* Stop the gpu timer */ ctk_config_stop_timer(ctk_gpu->ctk_config, - (GSourceFunc) update_gpu_memory_used, + (GSourceFunc) update_gpu_usage, (gpointer) ctk_gpu); } diff --git a/src/gtk+-2.x/ctkgpu.h b/src/gtk+-2.x/ctkgpu.h index eb95a0d..38d96e0 100644 --- a/src/gtk+-2.x/ctkgpu.h +++ b/src/gtk+-2.x/ctkgpu.h @@ -61,8 +61,13 @@ struct _CtkGpu GtkWidget *displays; GtkWidget *gpu_memory_used_label; + GtkWidget *gpu_utilization_label; + GtkWidget *video_utilization_label; + GtkWidget *pcie_utilization_label; gint gpu_memory; + gint gpu_utilization; gint gpu_cores; + gint gpu_uuid; gint memory_interface; gboolean pcie_gen_queriable; }; @@ -80,8 +85,7 @@ GtkWidget* ctk_gpu_new (NvCtrlAttributeHandle *handle, void get_bus_type_str(NvCtrlAttributeHandle *handle, gchar **bus); -void get_bus_id_str(NvCtrlAttributeHandle *handle, - gchar **pci_bus_id); +gchar *get_bus_id_str(NvCtrlAttributeHandle *handle); GtkTextBuffer *ctk_gpu_create_help(GtkTextTagTable *, CtkGpu *); diff --git a/src/gtk+-2.x/ctkgvi.c b/src/gtk+-2.x/ctkgvi.c index d0fd5db..f44a51c 100644 --- a/src/gtk+-2.x/ctkgvi.c +++ b/src/gtk+-2.x/ctkgvi.c @@ -538,7 +538,7 @@ GtkWidget* ctk_gvi_new(NvCtrlAttributeHandle *handle, /* Get Bus related information */ get_bus_type_str(handle, &bus); - get_bus_id_str(handle, &pci_bus_id); + pci_bus_id = get_bus_id_str(handle); /* NV_CTRL_IRQ */ diff --git a/src/gtk+-2.x/ctklicense.c b/src/gtk+-2.x/ctklicense.c index a28edf3..233cdcd 100644 --- a/src/gtk+-2.x/ctklicense.c +++ b/src/gtk+-2.x/ctklicense.c @@ -29,11 +29,6 @@ #include "ctkhelp.h" #include "ctkbanner.h" -static const char * __enable_confirm_msg = -"To use the features on the %s panel you\n" -"must agree to the terms of the preceding license agreement.\n" -"Do you accept this agreement?"; - static const char * __license_pre_msg = "Please read and accept the following license agreement:"; @@ -284,7 +279,10 @@ GtkWidget* ctk_license_dialog_new(GtkWidget *parent, gchar *panel_name) gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ctk_license_dialog->dialog)->vbox), hbox, TRUE, TRUE, 10); hbox = gtk_hbox_new(FALSE, 10); - enable_message = g_strdup_printf(__enable_confirm_msg, panel_name); + enable_message = g_strdup_printf("To use the features on the %s panel you\n" + "must agree to the terms of the preceding " + "license agreement.\nDo you accept this " + "agreement?", panel_name); label = gtk_label_new(enable_message); g_free(enable_message); diff --git a/src/gtk+-2.x/ctkpowermizer.c b/src/gtk+-2.x/ctkpowermizer.c index 9c326e1..3bdf176 100644 --- a/src/gtk+-2.x/ctkpowermizer.c +++ b/src/gtk+-2.x/ctkpowermizer.c @@ -38,6 +38,8 @@ static gboolean update_powermizer_info(gpointer); static void update_powermizer_menu_info(CtkPowermizer *ctk_powermizer); +static void set_powermizer_menu_label_txt(CtkPowermizer *ctk_powermizer, + gint powerMizerMode); static void powermizer_menu_changed(GtkWidget*, gpointer); static void update_powermizer_menu_event(GtkObject *object, gpointer arg1, @@ -70,8 +72,8 @@ static const char *__performance_level_help = static const char *__gpu_clock_freq_help = "This indicates the current Graphics Clock frequency."; -static const char *__memory_clock_freq_help = -"This indicates the current Memory Clock frequency."; +static const char *__memory_transfer_rate_freq_help = +"This indicates the current Memory transfer rate."; static const char *__processor_clock_freq_help = "This indicates the current Processor Clock frequency."; @@ -144,12 +146,12 @@ GType ctk_powermizer_get_type(void) typedef struct { gint perf_level; gint nvclock; - gint memclock; gint processorclock; gint nvclockmin; gint nvclockmax; - gint memclockmin; - gint memclockmax; + gint memtransferrate; + gint memtransferratemin; + gint memtransferratemax; gint processorclockmin; gint processorclockmax; } perfModeEntry, * perfModeEntryPtr; @@ -167,12 +169,12 @@ static void apply_perf_mode_token(char *token, char *value, void *data) pEntry->nvclockmin = atoi(value); } else if (!strcasecmp("nvclockmax", token)) { pEntry->nvclockmax = atoi(value); - } else if (!strcasecmp("memclock", token)) { - pEntry->memclock = atoi(value); - } else if (!strcasecmp("memclockmin", token)) { - pEntry->memclockmin = atoi(value); - } else if (!strcasecmp("memclockmax", token)) { - pEntry->memclockmax = atoi(value); + } else if (!strcasecmp("memtransferrate", token)) { + pEntry->memtransferrate = atoi(value); + } else if (!strcasecmp("memtransferratemin", token)) { + pEntry->memtransferratemin = atoi(value); + } else if (!strcasecmp("memtransferratemax", token)) { + pEntry->memtransferratemax = atoi(value); } else if (!strcasecmp("processorclock", token)) { pEntry->processorclock = atoi(value); } else if (!strcasecmp("processorclockmin", token)) { @@ -197,6 +199,7 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, char tmp_str[24]; gint ret; gint row_idx = 0; /* Where to insert into the perf mode table */ + gint col_idx = 0; /* Column index adjustment factor */ gboolean active; GtkWidget *vsep; perfModeEntryPtr pEntry = NULL; @@ -237,14 +240,14 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, /* Only add complete perf mode entries */ if ((pEntry[index].perf_level != -1) && - (pEntry[index].nvclockmax != -1) && - (pEntry[index].memclockmax != -1)) { + (pEntry[index].nvclockmax != -1)) { /* Set hasDecoupledClocks flag to decide new/old clock * interface to show. */ if (!ctk_powermizer->hasDecoupledClock && ((pEntry[index].nvclockmax != pEntry[index].nvclockmin) || - (pEntry[index].memclockmax != pEntry[index].memclockmin) || + (pEntry[index].memtransferratemax != + pEntry[index].memtransferratemin) || (pEntry[index].processorclockmax != pEntry[index].processorclockmin))) { ctk_powermizer->hasDecoupledClock = TRUE; @@ -268,6 +271,7 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, if (ctk_powermizer->hasDecoupledClock) { table = gtk_table_new(2, 15, FALSE); row_idx = row_idx + 3; + col_idx = 0; gtk_table_set_row_spacings(GTK_TABLE(table), 3); gtk_table_set_col_spacings(GTK_TABLE(table), 15); gtk_container_set_border_width(GTK_CONTAINER(table), 5); @@ -287,75 +291,71 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0); } - if (ctk_powermizer->gpu_clock && ctk_powermizer->memory_clock) { + if (ctk_powermizer->gpu_clock) { /* Graphics clock */ label = gtk_label_new("Graphics Clock"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 5, 0, 1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - label = gtk_label_new("Current"); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+4, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Min"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 3, 4, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Max"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 4, 5, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+3, col_idx+4, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); /* Vertical separator */ vsep = gtk_vseparator_new(); - gtk_table_attach(GTK_TABLE(table), vsep, 5, 6, 0, row_idx, + gtk_table_attach(GTK_TABLE(table), vsep, col_idx+4, col_idx+5, 0, + row_idx, GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0); - - /* Memory clock */ - label = gtk_label_new("Memory Clock"); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 6, 9, 0, 1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - label = gtk_label_new("Current"); + col_idx += 4; + } + + /* Memory transfer rate */ + if (ctk_powermizer->memory_transfer_rate && + pEntry[i].memtransferrate != -1) { + label = gtk_label_new("Memory Transfer Rate"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 6, 7, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+3, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Min"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 7, 8, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Max"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 8, 9, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - + /* Vertical separator */ vsep = gtk_vseparator_new(); - gtk_table_attach(GTK_TABLE(table), vsep, 9, 10, 0, row_idx, + gtk_table_attach(GTK_TABLE(table), vsep, col_idx+3, col_idx+4, + 0, row_idx, GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0); + col_idx += 4; } if (ctk_powermizer->processor_clock) { /* Processor clock */ label = gtk_label_new("Processor Clock"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 10, 11, 0, 1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - label = gtk_label_new("Current"); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 11, 12, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+3, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Min"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 12, 13, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); label = gtk_label_new("Max"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 13, 14, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); /* Vertical separator */ vsep = gtk_vseparator_new(); - gtk_table_attach(GTK_TABLE(table), vsep, 14, 15, 0, row_idx, + gtk_table_attach(GTK_TABLE(table), vsep, col_idx+3, col_idx+4, + 0, row_idx, GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0); } } else { @@ -375,23 +375,27 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); } - if (ctk_powermizer->gpu_clock && ctk_powermizer->memory_clock) { + if (ctk_powermizer->gpu_clock) { label = gtk_label_new("Graphics Clock"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx++; + } - - label = gtk_label_new("Memory Clock"); + if (pEntry[i].memtransferrate != -1 && + ctk_powermizer->memory_transfer_rate) { + label = gtk_label_new("Memory Transfer Rate"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx++; } if (ctk_powermizer->processor_clock) { label = gtk_label_new("Processor Clock"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 3, 4, 0, 1, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); } } @@ -400,11 +404,11 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, row_idx = 0; //reset value used to calculate vseparator. row_idx = 3; for (i = 0; i < index; i++) { + col_idx = 0; /* Only add complete perf mode entries */ if (ctk_powermizer->hasDecoupledClock && (pEntry[i].perf_level != -1) && - (pEntry[i].nvclockmax != -1) && - (pEntry[i].memclockmax != -1)) { + (pEntry[i].nvclockmax != -1)) { active = (pEntry[i].perf_level == perf_level); @@ -420,85 +424,63 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, gtk_table_attach(GTK_TABLE(table), label, 0, 1, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx +=1; } - if (ctk_powermizer->gpu_clock && ctk_powermizer->memory_clock) { - if (active) { - g_snprintf(tmp_str, 24, "%d MHz", ctk_powermizer->nvclock); - label = gtk_label_new(tmp_str); - gtk_widget_set_sensitive(label, active); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, - row_idx, row_idx+1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - } + if (ctk_powermizer->gpu_clock) { g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].nvclockmin); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 3, 4, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].nvclockmax); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 4, 5, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - - if (active) { - g_snprintf(tmp_str, 24, "%d MHz", ctk_powermizer->memclock); - label = gtk_label_new(tmp_str); - gtk_widget_set_sensitive(label, active); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 6, 7, - row_idx, row_idx+1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - } - g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memclockmin); + col_idx +=3; + } + if (ctk_powermizer->memory_transfer_rate && + pEntry[i].memtransferrate != -1) { + g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memtransferratemin); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 7, 8, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memclockmax); + g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memtransferratemax); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 8, 9, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx +=3; } if (ctk_powermizer->processor_clock) { - if (active) { - g_snprintf(tmp_str, 24, "%d MHz", ctk_powermizer->processorclock); - label = gtk_label_new(tmp_str); - gtk_widget_set_sensitive(label, active); - gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 11, 12, row_idx, row_idx+1, - GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); - } g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].processorclockmin); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 12, 13, + gtk_table_attach(GTK_TABLE(table), label, col_idx+1, col_idx+2, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].processorclockmax); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 13, 14, + gtk_table_attach(GTK_TABLE(table), label, col_idx+2, col_idx+3, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); } row_idx++; } else if ((pEntry[i].perf_level != -1) && - (pEntry[i].nvclock != -1) && - (pEntry[i].memclock != -1)) { + (pEntry[i].nvclock != -1)) { active = (pEntry[i].perf_level == perf_level); @@ -514,39 +496,46 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, gtk_table_attach(GTK_TABLE(table), label, 0, 1, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx++; } - if (ctk_powermizer->gpu_clock && ctk_powermizer->memory_clock) { + if (ctk_powermizer->gpu_clock) { g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].nvclock); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 1, 2, + gtk_table_attach(GTK_TABLE(table), label, col_idx, col_idx+1, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx++; + } + if (ctk_powermizer->memory_transfer_rate && + pEntry[i].memtransferrate != -1) { - g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memclock); + g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].memtransferrate); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, + gtk_table_attach(GTK_TABLE(table), label, col_idx, col_idx+1, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + col_idx++; } if (ctk_powermizer->processor_clock) { g_snprintf(tmp_str, 24, "%d MHz", pEntry[i].processorclock); label = gtk_label_new(tmp_str); gtk_widget_set_sensitive(label, active); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 3, 4, row_idx, row_idx+1, + gtk_table_attach(GTK_TABLE(table), label, col_idx, col_idx+1, + row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); } row_idx++; } else { nv_warning_msg("Incomplete Perf Mode (perf=%d, nvclock=%d," - " memclock=%d)", + " memtransferrate=%d)", pEntry[i].perf_level, pEntry[i].nvclock, - pEntry[i].memclock); + pEntry[i].memtransferrate); } } @@ -562,12 +551,14 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer, static gboolean update_powermizer_info(gpointer user_data) { gint power_source, adaptive_clock, perf_level; - gint clockret, gpu_clock, memory_clock, processor_clock; + gint gpu_clock, memory_transfer_rate; CtkPowermizer *ctk_powermizer; NvCtrlAttributeHandle *handle; gint ret; gchar *s; + char *clock_string = NULL; + perfModeEntry pEntry; ctk_powermizer = CTK_POWERMIZER(user_data); handle = ctk_powermizer->attribute_handle; @@ -589,36 +580,44 @@ static gboolean update_powermizer_info(gpointer user_data) gtk_label_set_text(GTK_LABEL(ctk_powermizer->adaptive_clock_status), s); g_free(s); } - - ret = NvCtrlGetAttribute(handle, NV_CTRL_GPU_CURRENT_CLOCK_FREQS, - &clockret); - if (ret == NvCtrlSuccess && ctk_powermizer->gpu_clock && - ctk_powermizer->memory_clock) { - memory_clock = clockret & 0x0000FFFF; - gpu_clock = (clockret >> 16); + /* Get the current values of clocks */ - ctk_powermizer->nvclock = gpu_clock; - ctk_powermizer->memclock = memory_clock; + ret = NvCtrlGetStringAttribute(ctk_powermizer->attribute_handle, + NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS, + &clock_string); - s = g_strdup_printf("%d Mhz", gpu_clock); - gtk_label_set_text(GTK_LABEL(ctk_powermizer->gpu_clock), s); - g_free(s); + if (ret == NvCtrlSuccess && ctk_powermizer->gpu_clock) { - s = g_strdup_printf("%d Mhz", memory_clock); - gtk_label_set_text(GTK_LABEL(ctk_powermizer->memory_clock), s); - g_free(s); - } + /* Invalidate the entries */ + memset(&pEntry, -1, sizeof(pEntry)); - ret = NvCtrlGetAttribute(handle, - NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS, - &processor_clock); - if (ret == NvCtrlSuccess && ctk_powermizer->processor_clock) { - ctk_powermizer->processorclock = processor_clock; - s = g_strdup_printf("%d Mhz", processor_clock); - gtk_label_set_text(GTK_LABEL(ctk_powermizer->processor_clock), s); - g_free(s); + parse_token_value_pairs(clock_string, apply_perf_mode_token, + &pEntry); + + if (pEntry.nvclock != -1) { + gpu_clock = pEntry.nvclock; + s = g_strdup_printf("%d Mhz", gpu_clock); + gtk_label_set_text(GTK_LABEL(ctk_powermizer->gpu_clock), s); + g_free(s); + + } + + if (ctk_powermizer->memory_transfer_rate && + pEntry.memtransferrate != -1) { + memory_transfer_rate = pEntry.memtransferrate; + s = g_strdup_printf("%d Mhz", memory_transfer_rate); + gtk_label_set_text(GTK_LABEL(ctk_powermizer->memory_transfer_rate), s); + g_free(s); + } + + if (ctk_powermizer->processor_clock && pEntry.processorclock != -1) { + s = g_strdup_printf("%d Mhz", pEntry.processorclock); + gtk_label_set_text(GTK_LABEL(ctk_powermizer->processor_clock), s); + g_free(s); + } } + XFree(clock_string); ret = NvCtrlGetAttribute(handle, NV_CTRL_GPU_POWER_SOURCE, &power_source); if (ret == NvCtrlSuccess && ctk_powermizer->power_source) { @@ -659,8 +658,7 @@ static gboolean update_powermizer_info(gpointer user_data) g_free(s); } - if (ctk_powermizer->performance_level && ctk_powermizer->gpu_clock && - ctk_powermizer->memory_clock) { + if (ctk_powermizer->performance_level && ctk_powermizer->gpu_clock) { /* update the perf table */ update_perf_mode_table(ctk_powermizer, perf_level); @@ -758,14 +756,17 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, gint row = 0; gchar *s = NULL; gint tmp; + gboolean gpu_clock_available = FALSE; + gboolean mem_transfer_rate_available = FALSE; gboolean processor_clock_available = FALSE; gboolean power_source_available = FALSE; gboolean perf_level_available = FALSE; gboolean adaptive_clock_state_available = FALSE; - gboolean clock_freqs_available = FALSE; gboolean cuda_dp_ui = FALSE; gboolean pcie_gen_queriable = FALSE; NVCTRLAttributeValidValuesRec valid_modes; + char *clock_string = NULL; + perfModeEntry pEntry; /* make sure we have a handle */ @@ -790,17 +791,31 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, adaptive_clock_state_available = TRUE; } - ret = NvCtrlGetAttribute(handle, NV_CTRL_GPU_CURRENT_CLOCK_FREQS, - &val); - if (ret == NvCtrlSuccess) { - clock_freqs_available = TRUE; - } + /* Check if reporting value of the clock supported */ + + ret = NvCtrlGetStringAttribute(handle, + NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS, + &clock_string); - ret = NvCtrlGetAttribute(handle, NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS, - &val); if (ret == NvCtrlSuccess) { - processor_clock_available = TRUE; + + /* Invalidate the entries */ + memset(&pEntry, -1, sizeof(pEntry)); + + parse_token_value_pairs(clock_string, apply_perf_mode_token, + &pEntry); + + if (pEntry.nvclock != -1) { + gpu_clock_available = TRUE; + } + if (pEntry.memtransferrate != -1) { + mem_transfer_rate_available = TRUE; + } + if (pEntry.processorclock != -1) { + processor_clock_available = TRUE; + } } + XFree(clock_string); /* NV_CTRL_GPU_PCIE_GENERATION */ @@ -811,7 +826,7 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, /* return early if query to attributes fail */ if (!power_source_available && !perf_level_available && - !adaptive_clock_state_available && clock_freqs_available && + !adaptive_clock_state_available && !gpu_clock_available && !processor_clock_available && !pcie_gen_queriable) { return NULL; } @@ -871,7 +886,7 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, /* Clock Frequencies */ - if (clock_freqs_available) { + if (gpu_clock_available) { /* spacing */ row += 3; ctk_powermizer->gpu_clock = @@ -885,21 +900,23 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, 0.0, 0.5, NULL); - - ctk_powermizer->memory_clock = + } else { + ctk_powermizer->gpu_clock = NULL; + } + if (mem_transfer_rate_available) { + ctk_powermizer->memory_transfer_rate = add_table_row_with_help_text(table, ctk_config, - __memory_clock_freq_help, + __memory_transfer_rate_freq_help, row++, //row 0, // column 0.0f, 0.5, - "Memory Clock:", + "Memory Transfer Rate:", 0.0, 0.5, NULL); } else { - ctk_powermizer->gpu_clock = NULL; - ctk_powermizer->memory_clock = NULL; + ctk_powermizer->memory_transfer_rate = NULL; } /* Processor clock */ if (processor_clock_available) { @@ -992,7 +1009,7 @@ GtkWidget* ctk_powermizer_new(NvCtrlAttributeHandle *handle, /* Available Performance Level Title */ - if (perf_level_available && clock_freqs_available) { + if (perf_level_available && gpu_clock_available) { hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); @@ -1264,13 +1281,35 @@ static void update_powermizer_menu_event(GtkObject *object, +static void set_powermizer_menu_label_txt(CtkPowermizer *ctk_powermizer, + gint powerMizerMode) +{ + gint actualPowerMizerMode; + gchar *label; + + if (powerMizerMode == NV_CTRL_GPU_POWER_MIZER_MODE_AUTO) { + actualPowerMizerMode = ctk_powermizer->powermizer_default_mode; + } else { + actualPowerMizerMode = powerMizerMode; + } + + label = get_powermizer_menu_label(actualPowerMizerMode); + gtk_label_set_text(GTK_LABEL(ctk_powermizer->powermizer_txt), label); + g_free(label); +} + + + static void update_powermizer_menu_info(CtkPowermizer *ctk_powermizer) { - gint powerMizerMode, defaultPowerMizerMode, actualPowerMizerMode; - gchar* label; + gint powerMizerMode, defaultPowerMizerMode; ReturnStatus ret1, ret2; CtkDropDownMenu *menu; + if (!ctk_powermizer->powermizer_menu) { + return; + } + menu = CTK_DROP_DOWN_MENU(ctk_powermizer->powermizer_menu); ret1 = NvCtrlGetAttribute(ctk_powermizer->attribute_handle, @@ -1288,17 +1327,11 @@ static void update_powermizer_menu_info(CtkPowermizer *ctk_powermizer) G_CALLBACK(powermizer_menu_changed), (gpointer) ctk_powermizer); - if (powerMizerMode == NV_CTRL_GPU_POWER_MIZER_MODE_AUTO) { - actualPowerMizerMode = defaultPowerMizerMode; - } else { - actualPowerMizerMode = powerMizerMode; - } + ctk_powermizer->powermizer_default_mode = defaultPowerMizerMode; ctk_drop_down_menu_set_current_value(menu, powerMizerMode); - label = get_powermizer_menu_label(actualPowerMizerMode); - gtk_label_set_text(GTK_LABEL(ctk_powermizer->powermizer_txt), label); - g_free(label); + set_powermizer_menu_label_txt(ctk_powermizer, powerMizerMode); g_signal_handlers_unblock_by_func(G_OBJECT(ctk_powermizer->powermizer_menu), G_CALLBACK(powermizer_menu_changed), @@ -1332,7 +1365,7 @@ static void powermizer_menu_changed(GtkWidget *widget, return; } - update_powermizer_menu_info(user_data); + set_powermizer_menu_label_txt(ctk_powermizer, powerMizerMode); post_powermizer_menu_update(ctk_powermizer); } @@ -1519,14 +1552,17 @@ GtkTextBuffer *ctk_powermizer_create_help(GtkTextTagTable *table, ctk_help_para(b, &i, "%s", __adaptive_clock_help); } - if (ctk_powermizer->gpu_clock && ctk_powermizer->memory_clock) { + if (ctk_powermizer->gpu_clock) { ctk_help_heading(b, &i, "Clock Frequencies"); - if (ctk_powermizer->processor_clock) { + if (ctk_powermizer->memory_transfer_rate && + ctk_powermizer->processor_clock) { s = "This indicates the GPU's current Graphics Clock, " - "Memory Clock and Processor Clock frequencies."; - } else { + "Memory transfer rate and Processor Clock frequencies."; + } else if (ctk_powermizer->memory_transfer_rate) { s = "This indicates the GPU's current Graphics Clock and " - "Memory Clock frequencies."; + "Memory transfer rate."; + } else { + s = "This indicates the GPU's current Graphics Clock ferquencies."; } ctk_help_para(b, &i, "%s", s); } diff --git a/src/gtk+-2.x/ctkpowermizer.h b/src/gtk+-2.x/ctkpowermizer.h index e1919e8..fc0f971 100644 --- a/src/gtk+-2.x/ctkpowermizer.h +++ b/src/gtk+-2.x/ctkpowermizer.h @@ -56,7 +56,7 @@ struct _CtkPowermizer GtkWidget *adaptive_clock_status; GtkWidget *gpu_clock; - GtkWidget *memory_clock; + GtkWidget *memory_transfer_rate; GtkWidget *processor_clock; GtkWidget *power_source; GtkWidget *performance_level; @@ -72,9 +72,7 @@ struct _CtkPowermizer gboolean dp_toggle_warning_dlg_shown; gboolean hasDecoupledClock; gint attribute; - gint nvclock; - gint memclock; - gint processorclock; + gint powermizer_default_mode; GtkWidget *status; GtkWidget *link_width; diff --git a/src/gtk+-2.x/ctkscreen.c b/src/gtk+-2.x/ctkscreen.c index 56bce3f..421fe21 100644 --- a/src/gtk+-2.x/ctkscreen.c +++ b/src/gtk+-2.x/ctkscreen.c @@ -48,7 +48,6 @@ static const _CtkStereoMode stereoMode[] = { { NV_CTRL_STEREO_3D_VISION, "NVIDIA 3D Vision Stereo" }, { NV_CTRL_STEREO_3D_VISION_PRO, "NVIDIA 3D Vision Pro Stereo" }, { NV_CTRL_STEREO_HDMI_3D, "HDMI 3D Stereo" }, - { -1, NULL}, }; void ctk_screen_event_handler(GtkWidget *widget, @@ -64,7 +63,7 @@ static void info_update_gpu_error(GtkObject *object, gpointer arg1, static const char *get_stereo_mode_string(int stereo_mode) { int i; - for (i = 0; stereoMode[i].name; i++) { + for (i = 0; i < ARRAY_LEN(stereoMode); i++) { if (stereoMode[i].stereo_mode == stereo_mode) { return stereoMode[i].name; } @@ -273,12 +272,6 @@ GtkWidget* ctk_screen_new(NvCtrlAttributeHandle *handle, snprintf(tmp, 16, "%d", gpu_errors); - /* get the stereo mode set for this X screen */ - ret = NvCtrlGetAttribute(handle, NV_CTRL_STEREO, (int *)&stereo_mode); - if (ret != NvCtrlSuccess) { - stereo_mode = -1; - } - /* now, create the object */ object = g_object_new(CTK_TYPE_SCREEN, NULL); @@ -288,6 +281,10 @@ GtkWidget* ctk_screen_new(NvCtrlAttributeHandle *handle, ctk_screen->handle = handle; + /* get the stereo mode set for this X screen */ + ret = NvCtrlGetAttribute(handle, NV_CTRL_STEREO, (int *)&stereo_mode); + ctk_screen->stereo_available = (ret == NvCtrlSuccess); + /* set container properties of the object */ gtk_box_set_spacing(GTK_BOX(ctk_screen), 10); @@ -340,8 +337,10 @@ GtkWidget* ctk_screen_new(NvCtrlAttributeHandle *handle, /* gpu errors */ ctk_screen->gpu_errors = add_table_row(table, 19, 0, 0, "Recovered GPU Errors:", 0, 0, tmp); - add_table_row(table, 20, 0, 0, "Stereo Mode:", 0, 0, - get_stereo_mode_string(stereo_mode)); + if (ctk_screen->stereo_available) { + add_table_row(table, 20, 0, 0, "Stereo Mode:", 0, 0, + get_stereo_mode_string(stereo_mode)); + } g_free(screen_number); free(display_name); @@ -376,6 +375,7 @@ GtkWidget* ctk_screen_new(NvCtrlAttributeHandle *handle, GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *table, + CtkScreen *ctk_screen, const gchar *screen_name) { GtkTextIter i; @@ -428,8 +428,10 @@ GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *table, "GPU received and the NVIDIA X driver successfully recovered " "from."); - ctk_help_heading(b, &i, "Stereo Mode"); - ctk_help_para(b, &i, "This is the stereo mode set for the X screen."); + if (ctk_screen->stereo_available) { + ctk_help_heading(b, &i, "Stereo Mode"); + ctk_help_para(b, &i, "This is the stereo mode set for the X screen."); + } ctk_help_finish(b); diff --git a/src/gtk+-2.x/ctkscreen.h b/src/gtk+-2.x/ctkscreen.h index 6ea0b18..13bc003 100644 --- a/src/gtk+-2.x/ctkscreen.h +++ b/src/gtk+-2.x/ctkscreen.h @@ -57,6 +57,8 @@ struct _CtkScreen GtkWidget *dimensions; GtkWidget *displays; GtkWidget *gpu_errors; + + int stereo_available; }; struct _CtkScreenClass @@ -73,7 +75,8 @@ GType ctk_screen_get_type (void) G_GNUC_CONST; GtkWidget* ctk_screen_new (NvCtrlAttributeHandle *handle, CtkEvent *ctk_event); -GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *, const gchar *); +GtkTextBuffer *ctk_screen_create_help(GtkTextTagTable *, CtkScreen *, + const gchar *); G_END_DECLS diff --git a/src/gtk+-2.x/ctkslimm.c b/src/gtk+-2.x/ctkslimm.c index 85f4f7a..bfbc638 100644 --- a/src/gtk+-2.x/ctkslimm.c +++ b/src/gtk+-2.x/ctkslimm.c @@ -1259,6 +1259,19 @@ static nvDisplayPtr intersect_modelines(nvLayoutPtr layout) return display; } +#define STEREO_IS_3D_VISION(stereo) \ + (((stereo) == NV_CTRL_STEREO_3D_VISION) || \ + ((stereo) == NV_CTRL_STEREO_3D_VISION_PRO)) + +static int get_display_stereo_mode(nvDisplayPtr display) +{ + if ((display->screen == NULL) || + (display->screen->stereo_supported == FALSE)) { + return NV_CTRL_STEREO_OFF; + } else { + return display->screen->stereo; + } +} GtkWidget* ctk_slimm_new(NvCtrlAttributeHandle *handle, CtkEvent *ctk_event, CtkConfig *ctk_config) @@ -1279,6 +1292,7 @@ GtkWidget* ctk_slimm_new(NvCtrlAttributeHandle *handle, CtkDropDownMenu *menu; gchar *err_str = NULL; + gchar *str; gchar *tmp; gchar *sli_mode = NULL; ReturnStatus ret; @@ -1415,41 +1429,66 @@ GtkWidget* ctk_slimm_new(NvCtrlAttributeHandle *handle, /* If we failed to load, tell the user why */ if (err_str || !layout) { - gchar *str; + goto slimm_fail; + } - if (!err_str) { - str = g_strdup("Unable to load SLI Mosaic Mode Settings page."); - } else { - str = g_strdup_printf("Unable to load SLI Mosaic Mode Settings " - "page:\n\n%s", err_str); - g_free(err_str); - } + display = intersect_modelines(layout); - label = gtk_label_new(str); - g_free(str); - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - gtk_container_add(GTK_CONTAINER(object), label); + if (display == NULL) { + err_str = g_strdup("Unable to find active display with " + "intersected modelines."); + goto slimm_fail; + } else if ((display->modelines == NULL) && + (display->cur_mode->modeline == NULL)) { + /* The modepool for the active display did not have any modes in + * its modepool matching any of the modes on the modepool of any + * other display in the layout, causing intersect_modelines to + * remove every mode from the list of available modes for SLI mosaic + * mode. + * + * This can happen if one display had its modepool trimmed and modified + * to support 3D vision, while other displays (either on X screens + * without stereo currently enabled, or on screenless GPUs) did not. + * Find if that is the case, and display an informative message if so. + */ + nvGpuPtr gpu; + nvDisplayPtr d; + int stereo = get_display_stereo_mode(display); - /* Show the GUI */ - gtk_widget_show_all(GTK_WIDGET(ctk_object)); + for (gpu = layout->gpus; gpu; gpu = gpu->next_in_layout) { + for (d = gpu->displays; d; d = d->next_on_gpu) { + int other_stereo; - return GTK_WIDGET(ctk_object); - } + if (display == d) { + continue; + } - display = intersect_modelines(layout); + other_stereo = get_display_stereo_mode(d); - if (display == NULL) { - gchar *str = g_strdup("Unable to find active display with " - "intersected modelines."); - label = gtk_label_new(str); - g_free(str); - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - gtk_container_add(GTK_CONTAINER(object), label); + if ((STEREO_IS_3D_VISION(stereo) && + !STEREO_IS_3D_VISION(other_stereo)) || + (!STEREO_IS_3D_VISION(stereo) && + STEREO_IS_3D_VISION(other_stereo))) { - /* Show the GUI */ - gtk_widget_show_all(GTK_WIDGET(ctk_object)); + err_str = g_strdup("Unable to find common modelines between\n" + "all connected displays due to 3D vision\n" + "being enabled on some displays and not\n" + "others. Please make sure that 3D vision\n" + "is enabled on all connected displays\n" + "before enabling SLI mosaic mode."); - return GTK_WIDGET(ctk_object); + goto slimm_fail; + } + } + } + + /* The intersected modepool was empty, but not because of a mismatch + * in 3D Vision settings. + */ + err_str = g_strdup("Unable to find find common modelines between " + "all connected displays."); + + goto slimm_fail; } @@ -1457,11 +1496,8 @@ GtkWidget* ctk_slimm_new(NvCtrlAttributeHandle *handle, ctk_object->modelines = display->modelines; if (display->cur_mode->modeline) { ctk_object->cur_modeline = display->cur_mode->modeline; - } else if (ctk_object->modelines) { - ctk_object->cur_modeline = ctk_object->modelines; } else { - /* This is an error. */ - return NULL; + ctk_object->cur_modeline = ctk_object->modelines; } ctk_object->num_modelines = display->num_modelines; @@ -1737,6 +1773,30 @@ GtkWidget* ctk_slimm_new(NvCtrlAttributeHandle *handle, gtk_widget_show_all(GTK_WIDGET(object)); return GTK_WIDGET(object); + +slimm_fail: + + if (layout) { + layout_free(layout); + } + + if (!err_str) { + str = g_strdup("Unable to load SLI Mosaic Mode Settings page."); + } else { + str = g_strdup_printf("Unable to load SLI Mosaic Mode Settings " + "page:\n\n%s", err_str); + g_free(err_str); + } + + label = gtk_label_new(str); + g_free(str); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_container_add(GTK_CONTAINER(object), label); + + /* Show the GUI */ + gtk_widget_show_all(GTK_WIDGET(ctk_object)); + + return GTK_WIDGET(ctk_object); } diff --git a/src/gtk+-2.x/ctkthermal.c b/src/gtk+-2.x/ctkthermal.c index a3c4ac7..d5f2947 100644 --- a/src/gtk+-2.x/ctkthermal.c +++ b/src/gtk+-2.x/ctkthermal.c @@ -97,8 +97,11 @@ static const char * __enable_button_help = static const char * __fan_id_help = "This shows the GPU Fan's index."; +static const char * __fan_rpm_help = +"This shows the current GPU Fan Speed in rotations per minute (RPM)."; + static const char * __fan_speed_help = -"This shows the current GPU Fan Speed."; +"This shows the current GPU Fan Speed level as a percentage."; static const char * __fan_control_type_help = "Fan Type indicates if and how this fan may be controlled. Possible " @@ -155,7 +158,7 @@ GType ctk_thermal_get_type(void) */ static gboolean update_cooler_info(gpointer user_data) { - int i, level, cooler_type, cooler_target; + int i, speed, level, cooler_type, cooler_target; gchar *tmp_str; CtkThermal *ctk_thermal; GtkWidget *table, *label, *eventbox; @@ -190,18 +193,26 @@ static gboolean update_cooler_info(gpointer user_data) gtk_container_add(GTK_CONTAINER(eventbox), label); ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox, __fan_id_help); - label = gtk_label_new("Speed (%)"); + label = gtk_label_new("Speed (RPM)"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); eventbox = gtk_event_box_new(); gtk_table_attach(GTK_TABLE(table), eventbox, 1, 2, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); gtk_container_add(GTK_CONTAINER(eventbox), label); + ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox, __fan_rpm_help); + + label = gtk_label_new("Speed (%)"); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + eventbox = gtk_event_box_new(); + gtk_table_attach(GTK_TABLE(table), eventbox, 2, 3, 0, 1, + GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + gtk_container_add(GTK_CONTAINER(eventbox), label); ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox, __fan_speed_help); label = gtk_label_new("Control Type"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); eventbox = gtk_event_box_new(); - gtk_table_attach(GTK_TABLE(table), eventbox, 2, 3, 0, 1, + gtk_table_attach(GTK_TABLE(table), eventbox, 3, 4, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); gtk_container_add(GTK_CONTAINER(eventbox), label); ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox, @@ -210,7 +221,7 @@ static gboolean update_cooler_info(gpointer user_data) label = gtk_label_new("Cooling Target"); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); eventbox = gtk_event_box_new(); - gtk_table_attach(GTK_TABLE(table), eventbox, 3, 4, 0, 1, + gtk_table_attach(GTK_TABLE(table), eventbox, 4, 5, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); gtk_container_add(GTK_CONTAINER(eventbox), label); ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox, @@ -220,7 +231,7 @@ static gboolean update_cooler_info(gpointer user_data) for (i = 0; i < ctk_thermal->cooler_count; i++) { row_idx = i+1; - gtk_table_resize(GTK_TABLE(table), row_idx+1, 4); + gtk_table_resize(GTK_TABLE(table), row_idx+1, 5); tmp_str = g_strdup_printf("%d", i); label = gtk_label_new(tmp_str); @@ -230,6 +241,21 @@ static gboolean update_cooler_info(gpointer user_data) free(tmp_str); ret = NvCtrlGetAttribute(ctk_thermal->cooler_control[i].handle, + NV_CTRL_THERMAL_COOLER_SPEED, + &speed); + if (ret == NvCtrlSuccess) { + tmp_str = g_strdup_printf("%d", speed); + } + else { + tmp_str = g_strdup_printf("Unsupported"); + } + label = gtk_label_new(tmp_str); + gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + gtk_table_attach(GTK_TABLE(table), label, 1, 2, row_idx, row_idx+1, + GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + free(tmp_str); + + ret = NvCtrlGetAttribute(ctk_thermal->cooler_control[i].handle, NV_CTRL_THERMAL_COOLER_LEVEL, &level); if (ret != NvCtrlSuccess) { @@ -239,7 +265,7 @@ static gboolean update_cooler_info(gpointer user_data) tmp_str = g_strdup_printf("%d", level); label = gtk_label_new(tmp_str); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 1, 2, row_idx, row_idx+1, + gtk_table_attach(GTK_TABLE(table), label, 2, 3, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); free(tmp_str); @@ -259,7 +285,7 @@ static gboolean update_cooler_info(gpointer user_data) } label = gtk_label_new(tmp_str); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, row_idx, row_idx+1, + gtk_table_attach(GTK_TABLE(table), label, 3, 4, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); free(tmp_str); @@ -288,7 +314,7 @@ static gboolean update_cooler_info(gpointer user_data) } label = gtk_label_new(tmp_str); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); - gtk_table_attach(GTK_TABLE(table), label, 3, 4, row_idx, row_idx+1, + gtk_table_attach(GTK_TABLE(table), label, 4, 5, row_idx, row_idx+1, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); free(tmp_str); } @@ -1661,6 +1687,9 @@ next_help: ctk_help_heading(b, &i, "ID"); ctk_help_para(b, &i, "%s", __fan_id_help); + ctk_help_heading(b, &i, "Speed (RPM)"); + ctk_help_para(b, &i,"%s", __fan_rpm_help); + ctk_help_heading(b, &i, "Speed (%%)"); ctk_help_para(b, &i, "%s", __fan_speed_help); diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c index b92c076..7ade747 100644 --- a/src/gtk+-2.x/ctkwindow.c +++ b/src/gtk+-2.x/ctkwindow.c @@ -341,47 +341,27 @@ static void tree_selection_changed(GtkTreeSelection *selection, -/* - * tree_view_key_event() - callback for additional keyboard events we - * want to track (space and Return) to expand and collapse collapsible - * categories in the treeview. +/* + * row_activated_event() - callback for row-activated event + * - handles key presses automatically + * - allows the mouse to collapse/expand the menu even when the + * expand button/triangle is not working. */ -static gboolean tree_view_key_event(GtkWidget *tree_view, GdkEvent *event, - gpointer user_data) +static void row_activated_event(GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *col, + gpointer user_data) { - GdkEventKey *key_event = (GdkEventKey *) event; CtkWindow *ctk_window = CTK_WINDOW(user_data); - - if ((key_event->keyval == GDK_space) || - (key_event->keyval == GDK_Return)) { - - GtkTreeSelection* selection; - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreePath* path; - - selection = gtk_tree_view_get_selection(ctk_window->treeview); - - if (!gtk_tree_selection_get_selected(selection, &model, &iter)) - return FALSE; - - path = gtk_tree_model_get_path(model, &iter); - - if (gtk_tree_view_row_expanded(ctk_window->treeview, path)) { - gtk_tree_view_collapse_row(ctk_window->treeview, path); - } else { - gtk_tree_view_expand_row(ctk_window->treeview, path, FALSE); - } - - gtk_tree_path_free(path); - - return TRUE; - } - - return FALSE; -} /* tree_view_key_event() */ + if (gtk_tree_view_row_expanded(ctk_window->treeview, path)) { + gtk_tree_view_collapse_row(ctk_window->treeview, path); + } else { + gtk_tree_view_expand_row(ctk_window->treeview, path, FALSE); + } +} + static gboolean has_randr_gamma(NvCtrlAttributeHandle *handle) @@ -544,10 +524,10 @@ GtkWidget *ctk_window_new(ParsedAttribute *p, ConfigProperties *conf, ctk_window->treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model)); g_object_unref(ctk_window->tree_store); - /* catch keyboard events to the tree view */ + /* Added row activated event to the tree view */ - g_signal_connect(ctk_window->treeview, "key_press_event", - G_CALLBACK(tree_view_key_event), GTK_OBJECT(ctk_window)); + g_signal_connect(ctk_window->treeview, "row_activated", + G_CALLBACK(row_activated_event), GTK_OBJECT(ctk_window)); selection = gtk_tree_view_get_selection(ctk_window->treeview); @@ -660,8 +640,10 @@ GtkWidget *ctk_window_new(ParsedAttribute *p, ConfigProperties *conf, gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_WIDGET_COLUMN, child, -1); gtk_tree_store_set(ctk_window->tree_store, &iter, - CTK_WINDOW_HELP_COLUMN, - ctk_screen_create_help(tag_table, screen_name), -1); + CTK_WINDOW_HELP_COLUMN, + ctk_screen_create_help(tag_table, CTK_SCREEN(child), + screen_name), + -1); gtk_tree_store_set(ctk_window->tree_store, &iter, CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN, NULL, -1); @@ -1438,16 +1420,18 @@ static void add_display_devices(CtkWindow *ctk_window, GtkTreeIter *iter, * saved to the RC file when the UI is closed. */ - if (handles) { - display_handle = nv_get_target_handle(handles, - NV_CTRL_TARGET_TYPE_DISPLAY, - display_id); - } else { - display_handle = NULL; - } + display_handle = nv_get_target_handle(handles, + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id); if (!display_handle) { - continue; + display_handle = + nv_add_target(handles, NvCtrlGetDisplayPtr(gpu_handle), + NV_CTRL_TARGET_TYPE_DISPLAY, display_id); + + if (!display_handle) { + continue; + } } /* diff --git a/src/gtk+-2.x/ctkxvideo.c b/src/gtk+-2.x/ctkxvideo.c index 32bcf7c..8d33c5c 100644 --- a/src/gtk+-2.x/ctkxvideo.c +++ b/src/gtk+-2.x/ctkxvideo.c @@ -21,12 +21,13 @@ #include <stdio.h> #include <gtk/gtk.h> #include "NvCtrlAttributes.h" +#include "NVCtrlLib.h" -#include "ctkbanner.h" +#include "msg.h" +#include "ctkbanner.h" #include "ctkxvideo.h" -#include "ctkscale.h" - +#include "ctkutils.h" #include "ctkhelp.h" @@ -34,35 +35,9 @@ static const char *__xv_sync_to_display_help = "This controls which display device will be synched to when " "XVideo Sync To VBlank is enabled."; -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 *prev_radio, - char *label, - gint value, - int index); - -static void -xv_sync_to_display_update_radio_buttons(CtkXVideo *ctk_xvideo, gint value, - gboolean update_status); - -static void xv_sync_to_display_changed(GtkWidget *widget, gpointer user_data); - -static void xv_sync_to_display_update_received(GtkObject *object, gpointer arg1, - gpointer user_data); - -static void post_xv_sync_to_display_changed(CtkXVideo *ctk_xvideo, - GtkWidget *widget); -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 - #define __XV_SYNC_TO_DISPLAY 1 @@ -93,298 +68,285 @@ GType ctk_xvideo_get_type( return ctk_xvideo_type; } + + /* - * xv_sync_to_display_radio_button_add() - create a radio button and plug it - * into the xv_sync_display radio group. + * Updates the status bar for when a change occured. */ - -static GtkWidget *xv_sync_to_display_radio_button_add(CtkXVideo *ctk_xvideo, - GtkWidget *prev_radio, - char *label, - gint value, - int index) +static void post_xv_sync_to_display_update(CtkXVideo *ctk_xvideo, + GtkWidget *active_button) { - 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(ctk_xvideo->xv_sync_to_display_button_box), - radio, FALSE, FALSE, 0); + const gchar *label; - g_object_set_data(G_OBJECT(radio), "xv_sync_to_display", - GINT_TO_POINTER(value)); - - g_signal_connect(G_OBJECT(radio), "toggled", - G_CALLBACK(xv_sync_to_display_changed), - (gpointer) ctk_xvideo); + label = gtk_button_get_label(GTK_BUTTON(active_button)); - ctk_xvideo->xv_sync_to_display_buttons[index] = radio; + ctk_config_statusbar_message(ctk_xvideo->ctk_config, + "XVideo application syncing to %s.", + label); +} - return radio; - -} /* xv_sync_to_display_radio_button_add() */ -static void -xv_sync_to_display_update_radio_buttons(CtkXVideo *ctk_xvideo, - gint value, gboolean update_status) +/* + * xv_sync_to_display_id_toggled() - callback function for changes to the + * sync_to_display radio button group; if the specified radio button is + * active, send xv_sync_to_display state to the server + */ +static void xv_sync_to_display_id_toggled(GtkWidget *widget, + gpointer user_data) { - GtkWidget *b, *button = NULL; - int i; + CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data); + gboolean enabled; + gint device_id; + + enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + if (!enabled) { + /* Ignore 'disable' events. */ + return; + } - button = ctk_xvideo->xv_sync_to_display_buttons[value]; - - if (!button) return; + user_data = g_object_get_data(G_OBJECT(widget), "display_id"); - /* turn off signal handling for all the sync buttons */ + device_id = GPOINTER_TO_INT(user_data); - for (i = 0; i < 24; i++) { - b = ctk_xvideo->xv_sync_to_display_buttons[i]; - if (!b) continue; + NvCtrlSetAttribute(ctk_xvideo->handle, NV_CTRL_XV_SYNC_TO_DISPLAY_ID, + device_id); - g_signal_handlers_block_by_func - (G_OBJECT(b), G_CALLBACK(xv_sync_to_display_changed), - (gpointer) ctk_xvideo); - } - - /* set the appropriate button active */ + post_xv_sync_to_display_update(ctk_xvideo, widget); +} + + + +/* + * Sets the radio button at the given index as enabled. + */ +static void xv_sync_to_display_set_enabled(CtkXVideo *ctk_xvideo, + GtkWidget *button, + gboolean update_status) +{ + /* turn off signal handling. Note that we only disable events + * for the button being enabled since we ignore disable events. + */ + g_signal_handlers_block_by_func + (G_OBJECT(button), G_CALLBACK(xv_sync_to_display_id_toggled), + (gpointer) ctk_xvideo); + + /* set the button as active */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE); - - /* turn on signal handling for all the sync buttons */ - for (i = 0; i < 24; i++) { - b = ctk_xvideo->xv_sync_to_display_buttons[i]; - if (!b) continue; + /* turn on signal handling */ - g_signal_handlers_unblock_by_func - (G_OBJECT(b), G_CALLBACK(xv_sync_to_display_changed), - (gpointer) ctk_xvideo); - } + g_signal_handlers_unblock_by_func + (G_OBJECT(button), G_CALLBACK(xv_sync_to_display_id_toggled), + (gpointer) ctk_xvideo); if (update_status) { - post_xv_sync_to_display_changed(ctk_xvideo, button); + post_xv_sync_to_display_update(ctk_xvideo, button); } +} -} /* xv_sync_to_display_update_radio_buttons() */ /* - * xv_sync_to_display_changed() - callback function for changes to the - * sync_to_display radio button group; if the specified radio button is - * active, send xv_sync_to_display state to the server + * xv_sync_to_display_radio_button_add() - create a radio button and plug it + * into the xv_sync_display_buttons radio group. */ - -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 *last_button, + gint display_id) { - CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data); - gboolean enabled; - gint device_mask; - - enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + Bool valid; + char *name; + char *randr; + gchar *label; + GtkWidget *button; + GSList *slist; + + + valid = + XNVCTRLQueryTargetStringAttribute(NvCtrlGetDisplayPtr(ctk_xvideo->handle), + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id, + 0, + NV_CTRL_STRING_DISPLAY_DEVICE_NAME, + &name); + if (!valid) { + name = NULL; + } - if (!enabled) { - /* Ignore 'disable' events. */ - return; + valid = + XNVCTRLQueryTargetStringAttribute(NvCtrlGetDisplayPtr(ctk_xvideo->handle), + NV_CTRL_TARGET_TYPE_DISPLAY, + display_id, + 0, + NV_CTRL_STRING_DISPLAY_NAME_RANDR, + &randr); + if (!valid) { + randr = NULL; } - user_data = g_object_get_data(G_OBJECT(widget), "xv_sync_to_display"); + if (name && randr) { + label = g_strdup_printf("%s (%s)", name, randr); + } else { + label = g_strdup_printf("%s", + name ? name : (randr ? randr : "Unknown")); + } - device_mask = GPOINTER_TO_INT(user_data); + XFree(name); + XFree(randr); - NvCtrlSetAttribute(ctk_xvideo->handle, - NV_CTRL_XV_SYNC_TO_DISPLAY, device_mask); + if (last_button) { + slist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(last_button)); + } else { + slist = NULL; + } + button = gtk_radio_button_new_with_label(slist, label); + g_free(label); - post_xv_sync_to_display_changed(ctk_xvideo, widget); + gtk_box_pack_start(GTK_BOX(ctk_xvideo->xv_sync_to_display_button_box), + button, FALSE, FALSE, 0); -}/* xv_sync_to_display_changed() */ + g_object_set_data(G_OBJECT(button), "display_id", + GINT_TO_POINTER(display_id)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); -static void post_xv_sync_to_display_changed(CtkXVideo *ctk_xvideo, - GtkWidget *active_button) -{ - const gchar *label; + g_signal_connect(G_OBJECT(button), "toggled", + G_CALLBACK(xv_sync_to_display_id_toggled), + (gpointer) ctk_xvideo); - label = gtk_button_get_label(GTK_BUTTON(active_button)); + ctk_config_set_tooltip(ctk_xvideo->ctk_config, button, + __xv_sync_to_display_help); - ctk_config_statusbar_message(ctk_xvideo->ctk_config, - "XVideo application syncing to %s.", - label); + return button; } + + /* - * xv_sync_to_display_radio_button_remove() + * Rebuilds the list of display devices available for syncing. */ -static void xv_sync_to_display_radio_button_remove(CtkXVideo *ctk_xvideo, - gint value) +static void xv_sync_to_display_rebuild_buttons(CtkXVideo *ctk_xvideo, + gboolean update_status) { - 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; - } + ReturnStatus ret; + int enabled_display_id; + int *pData; + int len; + int i; + + GtkWidget *last_button; + + + /* Remove all buttons */ + + ctk_empty_container(ctk_xvideo->xv_sync_to_display_button_box); + + + /* Rebuild the list based on the curren configuration */ + + ret = NvCtrlGetAttribute(ctk_xvideo->handle, + NV_CTRL_XV_SYNC_TO_DISPLAY_ID, + &enabled_display_id); + if (ret != NvCtrlSuccess) { + nv_warning_msg("Failed to query XV Sync display ID on X screen %d.", + NvCtrlGetTargetId(ctk_xvideo->handle)); + return; + } + + ret = NvCtrlGetBinaryAttribute(ctk_xvideo->handle, 0, + NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN, + (unsigned char **)(&pData), &len); + if (ret != NvCtrlSuccess) { + nv_warning_msg("Failed to query list of displays assigned to X screen " + " %d.", + NvCtrlGetTargetId(ctk_xvideo->handle)); + return; + } + + + /* Add a button for each display device */ + + last_button = NULL; + for (i = 0; i < pData[0]; i++) { + GtkWidget *button; + int display_id = pData[1+i]; + + button = xv_sync_to_display_radio_button_add(ctk_xvideo, + last_button, + display_id); + if (!button) { + continue; + } + + /* Make sure the enabled display is marked as so */ + if (display_id == enabled_display_id) { + xv_sync_to_display_set_enabled(ctk_xvideo, button, + update_status); } + + /* Track the first button */ + if (!last_button) { + ctk_xvideo->xv_sync_to_display_buttons = button; + } + + last_button = button; } -} /* xv_sync_to_display_radio_button_remove() */ + + gtk_widget_show_all(ctk_xvideo->xv_sync_to_display_button_box); +} + + /* - * nv_ctrl_enabled_displays() + * Handles NV_CTRL_ENABLED_DISPLAYS events and updates + * the list of displays in the UI. */ -static void nv_ctrl_enabled_displays(GtkObject *object, gpointer arg1, +static void enabled_displays_handler(GtkObject *object, gpointer arg1, gpointer user_data) { CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data); - int i, enabled, prev_enabled = 0; - int remove_devices_mask, add_devices_mask; - unsigned int mask; - gpointer udata; - GtkWidget *b; - ReturnStatus ret; - - /* - * The event data passed in gives us the enabled displays mask - * for all displays on all X Screens on this GPU. Since we can - * only sync to a display on this X Screen, we need to have the - * correct enabled displays. - */ - ret = NvCtrlGetAttribute(ctk_xvideo->handle, - NV_CTRL_ENABLED_DISPLAYS, - &enabled); - if (ret != NvCtrlSuccess) { - enabled = 0; - } - - /* 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); - } - 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_rebuild_buttons(ctk_xvideo, TRUE); +} - 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 - * to display settings; this is called when we receive an event indicating that - * another NV-CONTROL client changed any of the settings that we care - * about. + * Handler for NV_CTRL_XV_SYNC_TO_DISPLAY_ID events. */ - -static void xv_sync_to_display_update_received(GtkObject *object, - gpointer arg1, - gpointer user_data) +static void xv_sync_to_display_id_handler(GtkObject *object, + gpointer arg1, + gpointer user_data) { CtkEventStruct *event_struct = (CtkEventStruct *) arg1; CtkXVideo *ctk_xvideo = CTK_XVIDEO(user_data); - gint i; - GtkWidget *b; - - switch (event_struct->attribute) { - case NV_CTRL_XV_SYNC_TO_DISPLAY: - for (i = 0; i < 24; i++) { - b = ctk_xvideo->xv_sync_to_display_buttons[i]; - if (!b) continue; - user_data = g_object_get_data(G_OBJECT(b), "xv_sync_to_display"); - - if (GPOINTER_TO_INT(user_data) == event_struct->value) { - xv_sync_to_display_update_radio_buttons(ctk_xvideo, i, - TRUE); - break; - } + GSList *slist; + + /* Find the right button and enable it */ + + slist = + gtk_radio_button_get_group(GTK_RADIO_BUTTON(ctk_xvideo->xv_sync_to_display_buttons)); + + while (slist) { + GtkWidget *button = GTK_WIDGET(slist->data); + + user_data = g_object_get_data(G_OBJECT(button), "display_id"); + if (GPOINTER_TO_INT(user_data) == event_struct->value) { + xv_sync_to_display_set_enabled(ctk_xvideo, button, TRUE); + break; } - break; - - default: - break; + + slist = g_slist_next(slist); } - -} /* xv_sync_to_display_update_received() */ +} + /* * ctk_xvideo_new() - constructor for the XVideo widget */ - GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, CtkConfig *ctk_config, CtkEvent *ctk_event) @@ -395,147 +357,107 @@ GtkWidget* ctk_xvideo_new(NvCtrlAttributeHandle *handle, GtkWidget *frame; GtkWidget *alignment; GtkWidget *vbox; - int sync_mask; int xv_overlay_present, xv_texture_present, xv_blitter_present; + gboolean show_page; ReturnStatus ret; /* * before we do anything else, determine if any of the Xv adapters * are present */ - + ret = NvCtrlGetAttribute(handle, NV_CTRL_ATTR_EXT_XV_OVERLAY_PRESENT, &xv_overlay_present); - - if (ret != NvCtrlSuccess) xv_overlay_present = FALSE; - + if (ret != NvCtrlSuccess) { + xv_overlay_present = FALSE; + } + ret = NvCtrlGetAttribute(handle, NV_CTRL_ATTR_EXT_XV_TEXTURE_PRESENT, &xv_texture_present); + if (ret != NvCtrlSuccess) { + xv_texture_present = FALSE; + } - if (ret != NvCtrlSuccess) xv_texture_present = FALSE; - ret = NvCtrlGetAttribute(handle, NV_CTRL_ATTR_EXT_XV_BLITTER_PRESENT, &xv_blitter_present); - - if (ret != NvCtrlSuccess) xv_blitter_present = FALSE; - + if (ret != NvCtrlSuccess) { + xv_blitter_present = FALSE; + } + if (!xv_overlay_present && !xv_texture_present && !xv_blitter_present) { return NULL; } - - + + /* If nothing to show, bail */ + + show_page = FALSE; + if (xv_texture_present || xv_blitter_present) { + int display_id; + ret = NvCtrlGetAttribute(handle, + NV_CTRL_XV_SYNC_TO_DISPLAY_ID, + &display_id); + if (ret == NvCtrlSuccess) { + show_page = TRUE; + } + } + + if (!show_page) { + return NULL; + } + + /* create the XVideo widget */ - + object = g_object_new(CTK_TYPE_XVIDEO, NULL); ctk_xvideo = CTK_XVIDEO(object); - + ctk_xvideo->handle = handle; ctk_xvideo->ctk_config = ctk_config; ctk_xvideo->active_attributes = 0; - + gtk_box_set_spacing(GTK_BOX(ctk_xvideo), 10); - - + + /* Video film banner */ - + banner = ctk_banner_image_new(BANNER_ARTWORK_XVIDEO); gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0); + /* Sync to display selection */ - if (xv_texture_present || xv_blitter_present) { - ret = NvCtrlGetAttribute(handle, - NV_CTRL_XV_SYNC_TO_DISPLAY, - &sync_mask); - if (ret == NvCtrlSuccess) { - 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; - 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->xv_sync_to_display_button_box = vbox; - - for (n=0, i = 0; i < 24; i++) { - - mask = 1 << i; - if (!(enabled & mask)) continue; - - /* get the name of the display device */ - - ret = NvCtrlGetStringDisplayAttribute(handle, mask, - NV_CTRL_STRING_DISPLAY_DEVICE_NAME, - &name); - - if ((ret != NvCtrlSuccess) || (!name)) { - name = g_strdup("Unknown"); - } - - /* get the display device type */ - - type = display_device_mask_to_display_device_name(mask); - - name_str = g_strdup_printf("%s (%s)", name, type); - XFree(name); - free(type); - - if (n==0) { - prev_radio = NULL; - } 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; - } - - 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); - - if (current != -1) { - xv_sync_to_display_update_radio_buttons(ctk_xvideo, - current, FALSE); - } - } - } - } - + + 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->xv_sync_to_display_button_box = vbox; + + xv_sync_to_display_rebuild_buttons(ctk_xvideo, FALSE); + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_XV_SYNC_TO_DISPLAY_ID), + G_CALLBACK(xv_sync_to_display_id_handler), + (gpointer) ctk_xvideo); + + g_signal_connect(G_OBJECT(ctk_event), + CTK_EVENT_NAME(NV_CTRL_ENABLED_DISPLAYS), + G_CALLBACK(enabled_displays_handler), + (gpointer) ctk_xvideo); + + alignment = gtk_alignment_new(1, 1, 0, 0); gtk_box_pack_start(GTK_BOX(object), alignment, TRUE, TRUE, 0); - + /* finally, show the widget */ gtk_widget_show_all(GTK_WIDGET(ctk_xvideo)); return GTK_WIDGET(ctk_xvideo); - -} /* ctk_xvideo_new() */ +} + + GtkTextBuffer *ctk_xvideo_create_help(GtkTextTagTable *table, CtkXVideo *ctk_xvideo) @@ -544,19 +466,19 @@ GtkTextBuffer *ctk_xvideo_create_help(GtkTextTagTable *table, GtkTextBuffer *b; b = gtk_text_buffer_new(table); - + gtk_text_buffer_get_iter_at_offset(b, &i, 0); ctk_help_title(b, &i, "X Server XVideo Settings Help"); ctk_help_para(b, &i, "The X Server XVideo Settings page uses the XVideo " "X extension."); - + if (ctk_xvideo->active_attributes & __XV_SYNC_TO_DISPLAY) { ctk_help_heading(b, &i, "Sync to this display device"); ctk_help_para(b, &i, "%s", __xv_sync_to_display_help); } - + ctk_help_finish(b); return b; diff --git a/src/gtk+-2.x/ctkxvideo.h b/src/gtk+-2.x/ctkxvideo.h index 56025fd..06cad06 100644 --- a/src/gtk+-2.x/ctkxvideo.h +++ b/src/gtk+-2.x/ctkxvideo.h @@ -54,7 +54,8 @@ struct _CtkXVideo NvCtrlAttributeHandle *handle; CtkConfig *ctk_config; - GtkWidget *xv_sync_to_display_buttons[24]; + GtkWidget *xv_sync_to_display_buttons; /* first button in group */ + GtkWidget *xv_sync_to_display_button_box; unsigned int active_attributes; }; @@ -65,8 +66,8 @@ struct _CtkXVideoClass }; GType ctk_xvideo_get_type (void) G_GNUC_CONST; -GtkWidget* ctk_xvideo_new (NvCtrlAttributeHandle *, CtkConfig *, - CtkEvent *ctk_event); +GtkWidget* ctk_xvideo_new (NvCtrlAttributeHandle *handle, + CtkConfig *ctk_config, CtkEvent *ctk_event); GtkTextBuffer *ctk_xvideo_create_help(GtkTextTagTable *, CtkXVideo *); diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h index e1ab891..e50dd98 100644 --- a/src/libXNVCtrl/NVCtrl.h +++ b/src/libXNVCtrl/NVCtrl.h @@ -1891,19 +1891,7 @@ /* - * NV_CTRL_FLATPANEL_NATIVE_RESOLUTION - Returns the dimensions of the - * native resolution of the flat panel as determined by the - * NVIDIA X Driver. - * - * The native resolution is the resolution at which a flat panel - * must display any image. All other resolutions must be scaled to this - * resolution through GPU scaling or the DFP's native scaling capabilities - * in order to be displayed. - * - * This attribute is only valid for flat panel (DFP) display devices. - * - * This attribute is a packed integer; the width is packed in the upper - * 16-bits and the height is packed in the lower 16-bits. + * NV_CTRL_FLATPANEL_NATIVE_RESOLUTION - not supported */ #define NV_CTRL_FLATPANEL_NATIVE_RESOLUTION 251 /* R-DG */ @@ -3298,7 +3286,25 @@ */ #define NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE 400 /* R--G */ -#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE +/* + * NV_CTRL_XV_SYNC_TO_DISPLAY_ID - When XVideo Sync To VBlank is enabled, this + * controls which display device will be synched to. + */ +#define NV_CTRL_XV_SYNC_TO_DISPLAY_ID 401 /* RW- */ + +/* + * NV_CTRL_BACKLIGHT_BRIGHTNESS - The backlight brightness of an internal panel. + */ +#define NV_CTRL_BACKLIGHT_BRIGHTNESS 402 /* RWD- */ + +/* + * NV_CTRL_THERMAL_COOLER_SPEED - Returns cooler's current operating speed in + * rotations per minute (RPM). + */ + +#define NV_CTRL_THERMAL_COOLER_SPEED 405 /* R--C */ + +#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_THERMAL_COOLER_SPEED /**************************************************************************/ @@ -3701,6 +3707,12 @@ * "memclock" integer - the memory clocks (in MHz) for the perf level * "memclockmin" integer - the memory clocks min (in MHz) for the perf level * "memclockmax" integer - the memory clocks max (in MHz) for the perf level + * "memtransferrate" integer - the memory transfer rate (in MHz) + * for the perf level + * "memtransferratemin" integer - the memory transfer rate min (in MHz) + * for the perf level + * "memtransferratemax" integer - the memory transfer rate max (in MHz) + * for the perf level * "processorclock" integer - the processor clocks (in MHz) * for the perf level * "processorclockmin" integer - the processor clocks min (in MHz) @@ -3711,9 +3723,11 @@ * Example: * * perf=0, nvclock=324, nvclockmin=324, nvclockmax=324, memclock=324, - * memclockmin=324, memclockmax=324 ; + * memclockmin=324, memclockmax=324, memtransferrate=648, + * memtransferratemin=648,memtransferratemax=648 ; * perf=1, nvclock=324, nvclockmin=324, nvclockmax=640, memclock=810, - * memclockmin=810, memclockmax=810 ; + * memclockmin=810, memclockmax=810, memtransferrate=1620, + * memtransferrate=1620, memtransferrate=1620 ; * * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. @@ -3842,6 +3856,12 @@ * "memclock" integer - the memory clocks (in MHz) for the perf level * "memclockmin" integer - the memory clocks min (in MHz) for the perf level * "memclockmax" integer - the memory clocks (max in MHz) for the perf level + * "memtransferrate" integer - the memory transfer rate (in MHz) + * for the perf level + * "memtransferratemin" integer - the memory transfer rate min (in MHz) + * for the perf level + * "memtransferratemax" integer - the memory transfer rate max (in MHz) + * for the perf level * "processorclock" integer - the processor clocks (in MHz) * for the perf level * "processorclockmin" integer - the processor clocks min (in MHz) @@ -3852,7 +3872,7 @@ * Example: * * nvclock=324, nvclockmin=324, nvclockmax=324, - * memclock=324, memclockmin=324, memclockmax=324 + * memclock=324, memclockmin=324, memclockmax=324, memtrasferrate=628 * * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() * using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. @@ -3998,6 +4018,34 @@ */ #define NV_CTRL_STRING_GPU_UUID 52 /* R--G */ +/* + * NV_CTRL_STRING_GPU_UTILIZATION - Returns the current percentage usage + * of the various components of the GPU. + * + * Current valid tokens are "graphics", "memory", "video" and "PCIe". + * Not all tokens will be reported on all GPUs, and additional tokens + * may be added in the future. + * + * Utilization values are returned as a comma-separated list of + * "token=value" pairs. + * Valid tokens: + * + * Token Value + * "graphics" integer - the percentage usage of graphics engine. + * "memory" integer - the percentage usage of FB. + * "video" integer - the percentage usage of video engine. + * "PCIe" integer - the percentage usage of PCIe bandwidth. + * + * + * Example: + * + * graphics=45, memory=6, video=0, PCIe=0 + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using an NV_CTRL_TARGET_TYPE_GPU. + */ +#define NV_CTRL_STRING_GPU_UTILIZATION 53 /* R--G */ + /* * NV_CTRL_STRING_MULTIGPU_MODE - returns a string describing the current diff --git a/src/nvidia-settings.c b/src/nvidia-settings.c index acfa685..bda2b20 100644 --- a/src/nvidia-settings.c +++ b/src/nvidia-settings.c @@ -29,6 +29,9 @@ #include <stdlib.h> +extern int __list_targets; + + int main(int argc, char **argv) { ConfigProperties conf; @@ -119,11 +122,11 @@ int main(int argc, char **argv) } /* - * if the user requested that we only load the config file, then - * exit now + * if the user requested that we only load the config file, or that + * we only list the resolved targets, then exit now. */ - - if (op->only_load) { + + if (op->only_load || __list_targets) { return ret ? 0 : 1; } diff --git a/src/option-table.h b/src/option-table.h index 50b0356..403f19c 100644 --- a/src/option-table.h +++ b/src/option-table.h @@ -170,6 +170,16 @@ static const NVGetoptOption __options[] = { "The first page with a name matching the &PAGE& argument will be used. " "By default, the \"X Server Information\" page is displayed." }, + { "list-targets-only", 'L', NVGETOPT_HELP_ALWAYS, NULL, + "When performing an attribute query (from the '--query' command line " + "option) or an attribute assignment (from the '--assign' command line " + "option or when loading an ~/.nvidia-settings-rc file), nvidia-settings " + "identifies one or more targets on which to query/assign the attribute.\n" + "\n" + "'--list-targets-only' will cause nvidia-settings to list the targets on " + " which the query/assign operation would have been performed, without " + "actually performing the operation(s), and exit." }, + { NULL, 0, 0, NULL, NULL}, }; diff --git a/src/parse.c b/src/parse.c index 1f7d125..7aa50b1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -39,6 +39,9 @@ static void nv_free_strtoks(char **s, int n); static int ctoi(const char c); static int count_number_of_chars(char *o, char d); +static uint32 display_device_name_to_display_device_mask(const char *str); + + /* * Table of all attribute names recognized by the attribute string * parser. Binds attribute names to attribute integers (for use in @@ -61,6 +64,7 @@ static int count_number_of_chars(char *o, char d); #define W NV_PARSER_TYPE_VALUE_IS_SWITCH_DISPLAY #define M NV_PARSER_TYPE_SDI_CSC #define T NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE +#define V NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID const AttributeTableEntry attributeTable[] = { @@ -88,7 +92,6 @@ const AttributeTableEntry attributeTable[] = { { "AssociatedDisplays", NV_CTRL_ASSOCIATED_DISPLAY_DEVICES, N|D, "Display device mask indicating which display devices are \"associated\" with the specified X screen (i.e., are available for displaying the desktop)." }, { "ProbeDisplays", NV_CTRL_PROBE_DISPLAYS, A|D, "When this attribute is queried, the X driver re-probes the hardware to detect which display devices are connected to the GPU or DPU driving the specified X screen. Returns a display mask of the currently connected display devices." }, { "InitialPixmapPlacement", NV_CTRL_INITIAL_PIXMAP_PLACEMENT, N, "Controls where X pixmaps are initially created." }, - { "DynamicTwinview", NV_CTRL_DYNAMIC_TWINVIEW, N, "Does the X screen support dynamic TwinView." }, { "MultiGpuDisplayOwner", NV_CTRL_MULTIGPU_DISPLAY_OWNER, N, "GPU ID of the GPU that has the display device(s) used for showing the X screen." }, { "HWOverlay", NV_CTRL_HWOVERLAY, 0, "When a workstation overlay is in use, this value is 1 if the hardware overlay is used, or 0 if the overlay is emulated." }, { "OnDemandVBlankInterrupts", NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS, 0, "Enable/Disable/Query of on-demand vertical blanking interrupt control on the GPU. The 'OnDemandVBlankInterrupts' X server configuration option must be enabled for this option to be available." }, @@ -174,8 +177,9 @@ const AttributeTableEntry attributeTable[] = { { "ECCDoubleBitErrors", NV_CTRL_GPU_ECC_DOUBLE_BIT_ERRORS, N, "Returns the number of double-bit ECC errors detected by the targeted GPU since the last POST." }, { "ECCAggregateDoubleBitErrors", NV_CTRL_GPU_ECC_AGGREGATE_DOUBLE_BIT_ERRORS, N, "Returns the number of double-bit ECC errors detected by the targeted GPU since the last counter reset." }, { "GPUFanControlState", NV_CTRL_GPU_COOLER_MANUAL_CONTROL, N, "The current fan control state; the value of this attribute controls the availability of additional fan control attributes. Note that this attribute is unavailable unless fan control support has been enabled by setting the \"Coolbits\" X config option." }, - { "GPUCurrentFanSpeed", NV_CTRL_THERMAL_COOLER_LEVEL, N, "Returns the GPU fan's current speed." }, + { "GPUCurrentFanSpeed", NV_CTRL_THERMAL_COOLER_LEVEL, N, "Returns the GPU fan's currently programmed speed, as a percentage of the maximum speed." }, { "GPUResetFanSpeed", NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT, N, "Resets the GPU fan's speed to its default." }, + { "GPUCurrentFanSpeedRPM", NV_CTRL_THERMAL_COOLER_SPEED, N, "Returns the GPU fan's tachometer-measured speed in rotations per minute (RPM)." }, { "GPUFanControlType", NV_CTRL_THERMAL_COOLER_CONTROL_TYPE, N, "Returns how the GPU fan is controlled. '1' means the fan can only be toggled on and off; '2' means the fan has variable speed. '0' means the fan is restricted and cannot be adjusted under end user control." }, { "GPUFanTarget", NV_CTRL_THERMAL_COOLER_TARGET, N, "Returns the objects the fan cools. '1' means the GPU, '2' means video memory, '4' means the power supply, and '7' means all of the above." }, { "ThermalSensorReading", NV_CTRL_THERMAL_SENSOR_READING, N, "Returns the thermal sensor's current reading." }, @@ -310,6 +314,7 @@ const AttributeTableEntry attributeTable[] = { { "RandROutputID", NV_CTRL_DISPLAY_RANDR_OUTPUT_ID, N, "The RandR Output ID that corresponds to the display device." }, { "FrameLockDisplayConfig", NV_CTRL_FRAMELOCK_DISPLAY_CONFIG, N, "Controls the FrameLock mode of operation for the display device." }, { "Hdmi3D", NV_CTRL_DPY_HDMI_3D, N, "Returns whether the specified display device is currently using HDMI 3D Frame Packed Stereo mode. If so, the result of refresh rate queries will be doubled." }, + { "BacklightBrightness", NV_CTRL_BACKLIGHT_BRIGHTNESS, N, "Controls the backlight brightness of an internal panel." }, /* TV */ { "TVOverScan", NV_CTRL_TV_OVERSCAN, 0, "Adjusts the amount of overscan on the specified display device." }, @@ -320,7 +325,8 @@ const AttributeTableEntry attributeTable[] = { { "TVSaturation", NV_CTRL_TV_SATURATION, 0, "Adjusts the amount of saturation on the specified display device." }, /* X Video */ - { "XVideoSyncToDisplay", NV_CTRL_XV_SYNC_TO_DISPLAY, D|Z, "Controls which display device is synced to by the texture and blitter adaptors when they are set to synchronize to the vertical blanking." }, + { "XVideoSyncToDisplay", NV_CTRL_XV_SYNC_TO_DISPLAY, D|Z|N, "Controls which display device is synced to by the texture and blitter adaptors when they are set to synchronize to the vertical blanking." }, + { "XVideoSyncToDisplayID", NV_CTRL_XV_SYNC_TO_DISPLAY_ID, V, "Controls which display device is synced to by the texture and blitter adaptors when they are set to synchronize to the vertical blanking." }, /* 3D Vision Pro */ {"3DVisionProResetTransceiverToFactorySettings", NV_CTRL_3D_VISION_PRO_RESET_TRANSCEIVER_TO_FACTORY_SETTINGS, N, "Resets the 3D Vision Pro transceiver to its factory settings."}, @@ -346,6 +352,7 @@ const AttributeTableEntry attributeTable[] = { {"3DVisionProGlassesFirmwareDateA", NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_DATE_A, S|N|T, "Returns the date of the firmware of chip A of the glasses."}, {"3DVisionProGlassesAddress", NV_CTRL_STRING_3D_VISION_PRO_GLASSES_ADDRESS, S|N|T, "Returns the RF address of the glasses."}, {"3DVisionProGlassesName", NV_CTRL_STRING_3D_VISION_PRO_GLASSES_NAME, S|N|T, "Controls the name the glasses should use."}, + {"GPUUtilization", NV_CTRL_STRING_GPU_UTILIZATION, S|N, "Returns the current percentage utilization of the GPU components." }, { NULL, 0, 0, NULL } }; @@ -354,7 +361,6 @@ const AttributeTableEntry attributeTable[] = { #undef C #undef N #undef G -#undef V #undef P #undef D #undef A @@ -364,6 +370,9 @@ const AttributeTableEntry attributeTable[] = { #undef S #undef I #undef W +#undef M +#undef T +#undef V /* * When new integer attributes are added to NVCtrl.h, an entry should @@ -372,7 +381,7 @@ const AttributeTableEntry attributeTable[] = { * about. */ -#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE +#if NV_CTRL_LAST_ATTRIBUTE != NV_CTRL_THERMAL_COOLER_SPEED #warning "Have you forgotten to add a new integer attribute to attributeTable?" #endif @@ -845,7 +854,8 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a) if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) { /* color attributes are floating point */ a->val.f = strtod(s, &tmp); - } else if (a->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { + } else if ((a->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) || + (a->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID)) { a->val.str = strdup(s); tmp = s + strlen(s); } else if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) { @@ -999,7 +1009,7 @@ int nv_strcasecmp(const char *a, const char *b) */ -uint32 display_device_name_to_display_device_mask(const char *str) +static uint32 display_device_name_to_display_device_mask(const char *str) { uint32 mask = 0; char *s, **toks, *endptr; @@ -1179,17 +1189,16 @@ char *display_device_mask_to_display_device_name(const uint32 mask) * mask. */ -uint32 expand_display_device_mask_wildcards(const uint32 d, const uint32 e) +uint32 expand_display_device_mask_wildcards(const uint32 d) { uint32 mask = d & VALID_DISPLAY_DEVICES_MASK; - if (d & DISPLAY_DEVICES_WILDCARD_CRT) mask |= (e & BITMASK_ALL_CRT); - if (d & DISPLAY_DEVICES_WILDCARD_TV) mask |= (e & BITMASK_ALL_TV); - if (d & DISPLAY_DEVICES_WILDCARD_DFP) mask |= (e & BITMASK_ALL_DFP); - - return mask; + if (d & DISPLAY_DEVICES_WILDCARD_CRT) mask |= BITMASK_ALL_CRT; + if (d & DISPLAY_DEVICES_WILDCARD_TV) mask |= BITMASK_ALL_TV; + if (d & DISPLAY_DEVICES_WILDCARD_DFP) mask |= BITMASK_ALL_DFP; -} /* expand_display_device_mask_wildcards() */ + return mask; +} diff --git a/src/parse.h b/src/parse.h index d83cf2c..5ae7baa 100644 --- a/src/parse.h +++ b/src/parse.h @@ -54,6 +54,7 @@ #define NV_PARSER_TYPE_1000Hz (1<<28) #define NV_PARSER_TYPE_SDI (1<<29) #define NV_PARSER_TYPE_SDI_CSC (1<<30) +#define NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID (1<<31) #define NV_PARSER_ASSIGNMENT 0 #define NV_PARSER_QUERY 1 @@ -328,9 +329,8 @@ char *replace_characters(const char *o, const char c, const char r); char *display_device_mask_to_display_device_name(const uint32); -uint32 display_device_name_to_display_device_mask(const char *); -uint32 expand_display_device_mask_wildcards(const uint32, const uint32); +uint32 expand_display_device_mask_wildcards(const uint32); ParsedAttribute *nv_parsed_attribute_init(void); diff --git a/src/query-assign.c b/src/query-assign.c index 95ae6c4..4bee53f 100644 --- a/src/query-assign.c +++ b/src/query-assign.c @@ -40,9 +40,12 @@ extern int __verbosity; extern int __terse; extern int __display_device_string; +extern int __list_targets; /* local prototypes */ +#define PRODUCT_NAME_LEN 64 + static int process_attribute_queries(int, char**, const char *, CtrlHandlesArray *); @@ -252,7 +255,7 @@ static CtrlHandleTarget *nv_get_target(const CtrlHandles *handles, const CtrlHandleTargets *targets; int i; - if (target_type < 0 || target_type >= MAX_TARGET_TYPES) { + if (!handles || target_type < 0 || target_type >= MAX_TARGET_TYPES) { return NULL; } @@ -268,6 +271,34 @@ static CtrlHandleTarget *nv_get_target(const CtrlHandles *handles, } +/*! + * Returns the RandR name of the matching display target from the given + * target ID and the list of target handles. + * + * \param[in] handles Container for all the CtrlHandleTargets to search. + * \param[in] target_id The target id of the display CtrlHandleTarget to + * search. + * + * \return Returns the NV_DPY_PROTO_NAME_RANDR name string from the matching + * (display) CtrlHandleTarget from CtrlHandles on success; else, + * returns NULL. + * + */ +const char *nv_get_display_target_config_name(const CtrlHandles *handles, + int target_id) +{ + CtrlHandleTarget *t = nv_get_target(handles, + NV_CTRL_TARGET_TYPE_DISPLAY, + target_id); + + if (!t) { + return NULL; + } + + return t->protoNames[NV_DPY_PROTO_NAME_RANDR]; +} + + /*! * Returns the NvCtrlAttributeHandle from CtrlHandles with the given target @@ -862,6 +893,126 @@ static int nv_infer_targets_from_specification(ParsedAttribute *a, } +/* + * nv_init_target() - Given the Display pointer, create an attribute + * handle and initialize the handle target. + */ + +static void nv_init_target(Display *dpy, CtrlHandleTarget *t, + int target, int targetId) +{ + NvCtrlAttributeHandle *handle; + ReturnStatus status; + char *tmp; + int len, d, c; + + /* allocate the handle */ + + handle = NvCtrlAttributeInit(dpy, + targetTypeTable[target].nvctrl, targetId, + NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS); + + t->h = handle; + + /* + * silently fail: this might happen if not all X screens + * are NVIDIA X screens + */ + + if (!handle) { + return; + } + + /* + * get a name for this target; in the case of + * X_SCREEN_TARGET targets, just use the string returned + * from NvCtrlGetDisplayName(); for other target types, + * append a target specification. + */ + + tmp = NvCtrlGetDisplayName(t->h); + + if (target == X_SCREEN_TARGET) { + t->name = tmp; + } else { + len = strlen(tmp) + strlen(targetTypeTable[target].parsed_name) + 16; + t->name = nvalloc(len); + + if (t->name) { + snprintf(t->name, len, "%s[%s:%d]", + tmp, targetTypeTable[target].parsed_name, targetId); + free(tmp); + } else { + t->name = tmp; + } + } + + load_target_proto_names(t); + t->relations = nv_target_list_init(); + + /* + * get the enabled display device mask; for X screens and + * GPUs we query NV-CONTROL; for anything else + * (framelock), we just assign this to 0. + */ + + if (targetTypeTable[target].uses_display_devices) { + + status = NvCtrlGetAttribute(t->h, + NV_CTRL_ENABLED_DISPLAYS, &d); + + if (status != NvCtrlSuccess) { + nv_error_msg("Error querying enabled displays on " + "%s %d (%s).", targetTypeTable[target].name, targetId, + NvCtrlAttributesStrError(status)); + d = 0; + } + + status = NvCtrlGetAttribute(t->h, + NV_CTRL_CONNECTED_DISPLAYS, &c); + + if (status != NvCtrlSuccess) { + nv_error_msg("Error querying connected displays on " + "%s %d (%s).", targetTypeTable[target].name, targetId, + NvCtrlAttributesStrError(status)); + c = 0; + } + } else { + d = 0; + c = 0; + } + + t->d = d; + t->c = c; + +} + + +/* + * nv_add_ctrl_handle_target() - add a CtrlHandleTarget to the array + * of Targets for the given target_index. This is used for dynamically + * created targets that don't exist when the CtrlHandles are initialized. + */ + +NvCtrlAttributeHandle *nv_add_target(CtrlHandles *handles, Display *dpy, + int target_index, int display_id) +{ + CtrlHandleTargets *dt; + CtrlHandleTarget *t; + + if (!handles) { + return NULL; + } + + dt = &handles->targets[target_index]; + + dt->t = nvrealloc(dt->t, (dt->n+1) * sizeof(CtrlHandleTarget)); + t = &dt->t[dt->n]; + dt->n++; + + nv_init_target(dpy, t, target_index, display_id); + return t->h; +} /* * nv_alloc_ctrl_handles() - allocate a new CtrlHandles structure, @@ -874,9 +1025,7 @@ CtrlHandles *nv_alloc_ctrl_handles(const char *display) { ReturnStatus status; CtrlHandles *h, *pQueryHandle = NULL; - NvCtrlAttributeHandle *handle; - int i, j, val, d, c, len; - char *tmp; + int i, j, val, len; int *pData = NULL; /* allocate the CtrlHandles struct */ @@ -1023,92 +1172,16 @@ CtrlHandles *nv_alloc_ctrl_handles(const char *display) targetId = i; } - /* allocate the handle */ - - handle = NvCtrlAttributeInit(h->dpy, - targetTypeEntry->nvctrl, targetId, - NV_CTRL_ATTRIBUTES_ALL_SUBSYSTEMS); - - t->h = handle; - - /* - * silently fail: this might happen if not all X screens - * are NVIDIA X screens - */ - - if (!handle) { - continue; - } - - /* - * get a name for this target; in the case of - * X_SCREEN_TARGET targets, just use the string returned - * from NvCtrlGetDisplayName(); for other target types, - * append a target specification. - */ - - tmp = NvCtrlGetDisplayName(handle); - - if (target == X_SCREEN_TARGET) { - t->name = tmp; - } else { - len = strlen(tmp) + strlen(targetTypeEntry->parsed_name) +16; - t->name = nvalloc(len); - - if (t->name) { - snprintf(t->name, len, "%s[%s:%d]", - tmp, targetTypeEntry->parsed_name, targetId); - free(tmp); - } else { - t->name = tmp; - } - } - - load_target_proto_names(t); - t->relations = nv_target_list_init(); - + nv_init_target(h->dpy, t, target, targetId); /* - * get the enabled display device mask; for X screens and - * GPUs we query NV-CONTROL; for anything else - * (framelock), we just assign this to 0. + * store this handle, if it exists, so that we can use it to + * query other target counts later */ - if (targetTypeEntry->uses_display_devices) { - - status = NvCtrlGetAttribute(handle, - NV_CTRL_ENABLED_DISPLAYS, &d); - - if (status != NvCtrlSuccess) { - nv_error_msg("Error querying enabled displays on " - "%s %d (%s).", targetTypeEntry->name, i, - 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).", targetTypeEntry->name, i, - NvCtrlAttributesStrError(status)); - c = 0; - } - } else { - d = 0; - c = 0; + if (!pQueryHandle && t->h) { + pQueryHandle = t->h; } - - t->d = d; - t->c = c; - - /* - * store this handle so that we can use it to query other - * target counts later - */ - - if (!pQueryHandle) pQueryHandle = handle; } next_target_type: @@ -1281,19 +1354,21 @@ static void include_target_idx_targets(ParsedAttribute *a, const CtrlHandles *h, /*! * Queries the permissions for the given attribute. - * \param[in] a The attribute to query permissions for. + * * \param[in] h CtrlHandles used to communicate with the X server. + * \param[in] attr The attribute to query permissions for. + * \param[in] flags The attribute flags to query permissions for. * \param[out] perms The permissions of the attribute. * * \return Returns TRUE if the permissions were queried successfully; else, * returns FALSE. */ -static Bool query_attribute_perms(ParsedAttribute *a, CtrlHandles *h, - NVCTRLAttributePermissionsRec *perms) +Bool nv_get_attribute_perms(CtrlHandles *h, int attr, uint32 flags, + NVCTRLAttributePermissionsRec *perms) { memset(perms, 0, sizeof(*perms)); - if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) { + if (flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) { /* Allow non NV-CONTROL attributes to be read/written on X screen * targets */ @@ -1306,11 +1381,11 @@ static Bool query_attribute_perms(ParsedAttribute *a, CtrlHandles *h, return NV_TRUE; } - if (a->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { - return XNVCTRLQueryStringAttributePermissions(h->dpy, a->attr, perms); + if (flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { + return XNVCTRLQueryStringAttributePermissions(h->dpy, attr, perms); } - return XNVCTRLQueryAttributePermissions(h->dpy, a->attr, perms); + return XNVCTRLQueryAttributePermissions(h->dpy, attr, perms); } @@ -1322,6 +1397,10 @@ static Bool query_attribute_perms(ParsedAttribute *a, CtrlHandles *h, * the target type and target id are used. If nothing is specified, all the * valid targets for the attribute are included. * + * If this is a display attribute, and a (legacy) display mask string is given, + * all non-display targets are further resolved into the corresponding display + * targets that match the names represented by the display mask string. + * * \param[in/out] a ParsedAttribute to resolve. * \param[in] h CtrlHandles to resolve the target specification against. * @@ -1344,9 +1423,16 @@ static int resolve_attribute_targets(ParsedAttribute *a, CtrlHandles *h) return NV_PARSER_STATUS_BAD_ARGUMENT; } - a->targets = nv_target_list_init(); + + status = nv_get_attribute_perms(h, a->attr, a->flags, &perms); + if (!status) { + // XXX Throw other error here...? + return NV_PARSER_STATUS_TARGET_SPEC_NO_TARGETS; + } + a->targets = nv_target_list_init(); + /* If a target specification string was given, use that to determine the * list of targets to include. @@ -1390,12 +1476,6 @@ static int resolve_attribute_targets(ParsedAttribute *a, CtrlHandles *h) /* If no target type was given, assume all the appropriate targets for the * attribute by querying its permissions. */ - status = query_attribute_perms(a, h, &perms); - if (!status) { - // XXX Throw other error here...? - return NV_PARSER_STATUS_TARGET_SPEC_NO_TARGETS; - } - for (i = 0; i < MAX_TARGET_TYPES; i++) { int permBit = targetTypeTable[i].permission_bit; @@ -1407,8 +1487,100 @@ static int resolve_attribute_targets(ParsedAttribute *a, CtrlHandles *h) include_target_idx_targets(a, h, i); } - done: + + /* If this attribute is a display attribute, include the related display + * targets of the (resolved) non display targets. If a display mask is + * specified via either name string or value, use that to limit the + * displays added, otherwise include all related display targets. + */ + if (!(a->flags & NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE) && + (perms.permissions & ATTRIBUTE_TYPE_DISPLAY)) { + CtrlHandleTargetNode *head = nv_target_list_init(); + CtrlHandleTargetNode *n; + + uint32 display_mask; + int bit, i; + + char *name_list[32]; + int num_names = 0; + + + /* Convert user string into display device mask */ + if (a->flags & NV_PARSER_HAS_DISPLAY_DEVICE) { + display_mask = + expand_display_device_mask_wildcards(a->display_device_mask); + } else { + display_mask = VALID_DISPLAY_DEVICES_MASK; + } + + /* Convert the bitmask into a list of names */ + for (bit = 0; bit < 24; bit++) { + uint32 mask = (1 << bit); + + if (!(mask & display_mask)) { + continue; + } + + name_list[num_names] = display_device_mask_to_display_device_name(mask); + if (name_list[num_names]) { + num_names++; + } + } + + /* Look at attribute's target list... */ + for (n = a->targets; n->next; n = n->next) { + CtrlHandleTarget *t = n->t; + CtrlHandleTargetNode *n_other; + int target_type; + + if (!t->h) { + continue; + } + + target_type = NvCtrlGetTargetType(t->h); + + /* Include display targets */ + if (target_type == NV_CTRL_TARGET_TYPE_DISPLAY) { + /* Make sure to include display targets in final list */ + nv_target_list_add(head, t); + continue; + } + + /* Include non-display target's related display targets, if any */ + for (n_other = t->relations; + n_other->next; + n_other = n_other->next) { + CtrlHandleTarget *t_other = n_other->t; + + if (!t_other->h) { + continue; + } + target_type = NvCtrlGetTargetType(t_other->h); + if (target_type != NV_CTRL_TARGET_TYPE_DISPLAY) { + continue; + } + + for (i = 0; i < num_names; i++) { + if (nv_strcasecmp(name_list[i], + t_other->protoNames[NV_DPY_PROTO_NAME_TYPE_ID])) { + nv_target_list_add(head, t_other); + break; + } + } + } + } + + /* Cleanup */ + for (i = 0; i < num_names; i++) { + nvfree(name_list[i]); + } + + /* Apply the new targets list */ + nv_target_list_free(a->targets); + a->targets = head; + } + /* Make sure at least one target was resolved */ if (ret == NV_PARSER_STATUS_SUCCESS) { if (!(a->flags & NV_PARSER_HAS_TARGET)) { @@ -1885,7 +2057,8 @@ typedef enum { VerboseLevelVerbose, } VerboseLevel; -static void print_queried_value(CtrlHandleTarget *t, +static void print_queried_value(const CtrlHandles *handles, + CtrlHandleTarget *t, NVCTRLAttributeValidValuesRec *v, int val, uint32 flags, @@ -1898,7 +2071,15 @@ static void print_queried_value(CtrlHandleTarget *t, /* assign val_str */ - if ((flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY) && + if ((flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID) && + (__display_device_string)) { + const char *name = nv_get_display_target_config_name(handles, val); + if (name) { + snprintf(val_str, 64, "%s", name); + } else { + snprintf(val_str, 64, "%d", val); + } + } else if ((flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY) && (__display_device_string)) { tmp_d_str = display_device_mask_to_display_device_name(val); snprintf(val_str, 64, "%s", tmp_d_str); @@ -2141,8 +2322,8 @@ static int query_all(const char *display_name, CtrlHandlesArray *handles_array) goto exit_bit_loop; } - print_queried_value(t, &valid, val, a->flags, a->name, - mask, INDENT, __terse ? + print_queried_value(h, t, &valid, val, a->flags, + a->name, mask, INDENT, __terse ? VerboseLevelAbbreviated : VerboseLevelVerbose); @@ -2178,68 +2359,54 @@ exit_bit_loop: /* - * print_target_display_connections() - Print a list of all the - * display devices connected to the given target (GPU/X Screen) + * get_product_name() Returns the (GPU, X screen, display device or VCS) + * product name of the given target. */ -static int print_target_display_connections(CtrlHandleTarget *t) +static char * get_product_name(NvCtrlAttributeHandle *h, int attr) { - unsigned int bit; - char *tmp_d_str, *name; + char *product_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%.8X)", name, tmp_d_str, bit); - - free(name); - free(tmp_d_str); - } - nv_msg(NULL, ""); + status = NvCtrlGetStringAttribute(h, attr, &product_name); - return NV_TRUE; + if (status != NvCtrlSuccess) return strdup("Unknown"); -} /* print_target_display_connections() */ + return product_name; +} /* - * get_product_name() Returns the (GPU, X screen, display device or VCS) - * product name of the given target. + * Returns the (RandR) display device name to use for printing the given + * display target. If 'show_connected_state' is true, "connected" will be + * appended to the name. */ -static char * get_product_name(NvCtrlAttributeHandle *h, int attr) +static void get_display_product_name(CtrlHandleTarget *t, char *buf, int len, + Bool show_connect_state) { - char *product_name; - ReturnStatus status; + const CtrlHandleTargetNode *n; + const char *connected_str = ""; - status = NvCtrlGetStringAttribute(h, attr, &product_name); + /* Check to see if display is connected (has a GPU relation) */ + if (show_connect_state) { + for (n = t->relations; + n->next; + n = n->next) { + int target_type = NvCtrlGetTargetType(n->t->h); - if (status != NvCtrlSuccess) return strdup("Unknown"); - - return product_name; + if (target_type == NV_CTRL_TARGET_TYPE_GPU) { + connected_str = ") (connected"; + break; + } + } + } -} /* get_product_name() */ + snprintf(buf, len, "%s%s", + t->protoNames[NV_DPY_PROTO_NAME_RANDR], + connected_str); +} @@ -2251,6 +2418,7 @@ static char * get_product_name(NvCtrlAttributeHandle *h, int attr) static int print_target_connections(CtrlHandles *h, CtrlHandleTarget *t, + const char *relation_str, unsigned int attrib, unsigned int target_index) { @@ -2259,6 +2427,12 @@ static int print_target_connections(CtrlHandles *h, ReturnStatus status; char *product_name; char *target_name; + const TargetTypeEntry *targetTypeEntry; + Bool show_dpy_connection_state = + (attrib == NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN) ? + NV_TRUE : NV_FALSE; + + targetTypeEntry = &(targetTypeTable[target_index]); /* Query the connected targets */ @@ -2270,45 +2444,45 @@ static int print_target_connections(CtrlHandles *h, if (status != NvCtrlSuccess) return NV_FALSE; if (pData[0] == 0) { - nv_msg(" ", "Is not connected to any %s.", - targetTypeTable[target_index].name); + nv_msg(" ", "Is not %s any %s.", + relation_str, + targetTypeEntry->name); nv_msg(NULL, ""); XFree(pData); return NV_TRUE; } - nv_msg(" ", "Is connected to the following %s%s:", - targetTypeTable[target_index].name, + nv_msg(" ", "Is %s the following %s%s:", + relation_str, + targetTypeEntry->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) { + CtrlHandleTarget *target = + nv_get_target(h, targetTypeEntry->nvctrl, pData[i]); - target_name = h->targets[target_index].t[ pData[i] ].name; + if (target) { + target_name = target->name; switch (target_index) { case GPU_TARGET: product_name = - get_product_name(h->targets[target_index].t[ pData[i] ].h, - NV_CTRL_STRING_PRODUCT_NAME); + get_product_name(target->h, NV_CTRL_STRING_PRODUCT_NAME); break; - + case VCS_TARGET: product_name = - get_product_name(h->targets[target_index].t[ pData[i] ].h, + get_product_name(target->h, NV_CTRL_STRING_VCSC_PRODUCT_NAME); break; case DISPLAY_TARGET: - product_name = - get_product_name(h->targets[target_index].t[ pData[i] ].h, - NV_CTRL_STRING_DISPLAY_DEVICE_NAME); + product_name = nvalloc(PRODUCT_NAME_LEN); + get_display_product_name(target, product_name, PRODUCT_NAME_LEN, + show_dpy_connection_state); break; case NVIDIA_3D_VISION_PRO_TRANSCEIVER_TARGET: @@ -2328,17 +2502,17 @@ static int print_target_connections(CtrlHandles *h, } if (!target_name) { - nv_msg(" ", "[?] Unknown %s", - targetTypeTable[target_index].name); + nv_msg(" ", "Unknown %s", + targetTypeEntry->name); } else if (product_name) { - nv_msg(" ", "[%d] %s (%s)", - pData[i], target_name, product_name); + nv_msg(" ", "%s (%s)", + target_name, product_name); } else { - nv_msg(" ", "[%d] %s (%s %d)", - pData[i], target_name, - targetTypeTable[target_index].name, + nv_msg(" ", "%s (%s %d)", + target_name, + targetTypeEntry->name, pData[i]); } @@ -2402,7 +2576,7 @@ static int query_all_targets(const char *display_name, const int target_index, /* print information per target */ for (i = 0; i < h->targets[target_index].n; i++) { - char product_name[32]; + char product_name[PRODUCT_NAME_LEN]; Bool is_x_name = NV_FALSE; char *x_name = NULL; @@ -2410,21 +2584,26 @@ static int query_all_targets(const char *display_name, const int target_index, str = NULL; if (target_index == NVIDIA_3D_VISION_PRO_TRANSCEIVER_TARGET) { - snprintf(product_name, 32, "3D Vision Pro Transceiver %d", i); + snprintf(product_name, PRODUCT_NAME_LEN, + "3D Vision Pro Transceiver %d", i); } else if (target_index == THERMAL_SENSOR_TARGET) { - snprintf(product_name, 32, "Thermal Sensor %d", i); + snprintf(product_name, PRODUCT_NAME_LEN, + "Thermal Sensor %d", i); } else if (target_index == COOLER_TARGET) { - snprintf(product_name, 32, "Fan %d", i); + snprintf(product_name, PRODUCT_NAME_LEN, + "Fan %d", i); } else if (target_index == FRAMELOCK_TARGET) { - snprintf(product_name, 32, "Quadro Sync %d", i); + snprintf(product_name, PRODUCT_NAME_LEN, + "Quadro Sync %d", i); } else if (target_index == VCS_TARGET) { x_name = get_product_name(t->h, NV_CTRL_STRING_VCSC_PRODUCT_NAME); is_x_name = NV_TRUE; } else if (target_index == GVI_TARGET) { - snprintf(product_name, 32, "SDI Input %d", i); + snprintf(product_name, PRODUCT_NAME_LEN, + "SDI Input %d", i); } else if (target_index == DISPLAY_TARGET) { - x_name = get_product_name(t->h, NV_CTRL_STRING_DISPLAY_DEVICE_NAME); - is_x_name = NV_TRUE; + get_display_product_name(t, product_name, PRODUCT_NAME_LEN, + NV_FALSE); } else { x_name = get_product_name(t->h, NV_CTRL_STRING_PRODUCT_NAME); is_x_name = NV_TRUE; @@ -2452,59 +2631,82 @@ static int query_all_targets(const char *display_name, const int target_index, /* Print connectivity information */ if (__verbosity >= VERBOSITY_ALL) { - if (targetTypeEntry->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, + (h, t, + "driving", + NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU, X_SCREEN_TARGET); print_target_connections - (h, t, NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, + DISPLAY_TARGET); + print_target_connections + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU, FRAMELOCK_TARGET); print_target_connections - (h, t, NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU, VCS_TARGET); print_target_connections - (h, t, NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU, COOLER_TARGET); print_target_connections - (h, t, NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU, THERMAL_SENSOR_TARGET); - print_target_connections - (h, t, NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, - GPU_TARGET); break; case X_SCREEN_TARGET: print_target_connections - (h, t, NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, + (h, t, + "driven by", + NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, GPU_TARGET); + print_target_connections + (h, t, + "assigned", + NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN, + DISPLAY_TARGET); break; case FRAMELOCK_TARGET: print_target_connections - (h, t, NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK, GPU_TARGET); break; case VCS_TARGET: print_target_connections - (h, t, NV_CTRL_BINARY_DATA_GPUS_USING_VCSC, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_GPUS_USING_VCSC, GPU_TARGET); break; case COOLER_TARGET: print_target_connections - (h, t, NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU, COOLER_TARGET); break; case THERMAL_SENSOR_TARGET: print_target_connections - (h, t, NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU, + (h, t, + "connected to", + NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU, THERMAL_SENSOR_TARGET); break; @@ -2528,7 +2730,8 @@ static int query_all_targets(const char *display_name, const int target_index, * returned; if successful, NV_TRUE is returned. */ -static int process_parsed_attribute_internal(CtrlHandleTarget *t, +static int process_parsed_attribute_internal(const CtrlHandles *handles, + CtrlHandleTarget *t, ParsedAttribute *a, uint32 d, int target_type, int assign, int verbose, char *whence, @@ -2620,8 +2823,8 @@ static int process_parsed_attribute_internal(CtrlHandleTarget *t, NvCtrlAttributesStrError(status)); return NV_FALSE; } else { - print_queried_value(t, &valid, a->val.i, a->flags, a->name, d, - " ", __terse ? + print_queried_value(handles, t, &valid, a->val.i, a->flags, + a->name, d, " ", __terse ? VerboseLevelTerse : VerboseLevelVerbose); print_valid_values(a->name, a->attr, a->flags, valid); } @@ -2688,11 +2891,12 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, int assign, int verbose, char *whence_fmt, ...) { - int bit, ret, val; + int ret, val; char *whence, *tmp_d_str0, *tmp_d_str1; - uint32 display_devices; ReturnStatus status; CtrlHandleTargetNode *n; + NVCTRLAttributeValidValuesRec valid; + val = NV_FALSE; @@ -2731,61 +2935,36 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, CtrlHandleTarget *t = n->t; int target_type; - const TargetTypeEntry *targetTypeEntry; + uint32 mask; if (!t->h) continue; /* no handle on this target; silently skip */ target_type = NvCtrlGetTargetType(t->h); - targetTypeEntry = nv_get_target_type_entry_by_nvctrl(target_type); - /* validate any specified display device mask */ - if ((a->flags & NV_PARSER_HAS_DISPLAY_DEVICE) && - !(a->flags & NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE)) { + if (__list_targets) { + const char *name = t->protoNames[0]; + const char *randr_name = NULL; - /* Expand any wildcards in the display device mask */ - - display_devices = expand_display_device_mask_wildcards - (a->display_device_mask, t->d); - - if ((display_devices == 0) || (display_devices & ~t->d)) { - - /* - * use a->display_device_mask rather than - * display_devices when building the string (so that - * display_device_mask_to_display_device_name() can - * use wildcards if present). - */ + if (target_type == NV_CTRL_TARGET_TYPE_DISPLAY) { + name = t->protoNames[NV_DPY_PROTO_NAME_TARGET_INDEX]; + randr_name =t->protoNames[NV_DPY_PROTO_NAME_RANDR]; + } - tmp_d_str0 = display_device_mask_to_display_device_name - (a->display_device_mask); - tmp_d_str1 = display_device_mask_to_display_device_name(t->d); + nv_msg(TAB, "%s '%s' on %s%s%s%s\n", + assign ? "Assign" : "Query", + a->name, + name, + randr_name ? " (" : "", + randr_name ? randr_name : "", + randr_name ? ")" : "" + ); + continue; + } - if (tmp_d_str1 && (*tmp_d_str1 != '\0')) { - nv_error_msg("Invalid display device %s specified " - "%s (the currently enabled display devices " - "are %s on %s).", - tmp_d_str0, whence, tmp_d_str1, t->name); - } else { - nv_error_msg("Invalid display device %s specified " - "%s (there are currently no enabled display " - "devices on %s).", - tmp_d_str0, whence, t->name); - } - free(tmp_d_str0); - free(tmp_d_str1); - - goto done; - } - - } else { - /* Just use the display device mask for this target */ - display_devices = t->d; - } - /* special case the color attributes */ - + if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) { float v[3]; if (!assign) { @@ -2816,7 +2995,7 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, /* * If we are assigning, and the value for this attribute is a - * display device, then we need to validate the value against + * display device mask, then we need to validate the value against * either the mask of enabled display devices or the mask of * connected display devices. */ @@ -2871,6 +3050,79 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, } } + + /* + * If we are assigning, and the value for this attribute is a display + * device id/name string, then we need to validate and convert the + * given string against list of available display devices. The resulting + * id, if any, is then fed back into the ParsedAttrinute's value as an + * int which is ultimately written out to NV-CONTROL. + */ + if (assign && (a->flags & NV_PARSER_TYPE_VALUE_IS_DISPLAY_ID)) { + CtrlHandleTargets *dpy_targets = &(h->targets[DISPLAY_TARGET]); + int i; + int found = NV_FALSE; + int multi_match = NV_FALSE; + int is_id; + char *tmp = NULL; + int id; + + + /* See if value is a simple number */ + id = strtol(a->val.str, &tmp, 0); + is_id = (tmp && + (tmp != a->val.str) && + (*tmp == '\0')); + + for (i = 0; i < dpy_targets->n; i++) { + CtrlHandleTarget *dpy_target = dpy_targets->t + i; + + if (is_id) { + /* Value given as display device (target) ID */ + if (id == NvCtrlGetTargetId(dpy_target->h)) { + found = NV_TRUE; + break; + } + } else { + /* Value given as display device name */ + if (nv_target_has_name(dpy_target, a->val.str)) { + if (found) { + multi_match = TRUE; + break; + } + id = NvCtrlGetTargetId(dpy_target->h); + found = NV_TRUE; + + /* Keep looking to make sure the name doesn't alias to + * another display device. + */ + continue; + } + } + } + + if (multi_match) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned the value of '%s' (This name matches " + "multiple display devices, please use a non-" + "ambiguous name.", + a->name, whence, a->val.str); + continue; + } + + if (!found) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned the value of '%s' (This does not " + "name an available display device).", + a->name, whence, a->val.str); + continue; + } + + /* Put converted id back into a->val */ + a->val.i = id; + } + + /* * If we are assigning, and the value for this attribute is * not allowed to be zero, check that the value is not zero. @@ -3070,84 +3322,63 @@ int nv_process_parsed_attribute(ParsedAttribute *a, CtrlHandles *h, } - /* loop over the display devices */ - - for (bit = 0; bit < 24; bit++) { - uint32 mask; - NVCTRLAttributeValidValuesRec valid; - - - mask = (1 << bit); - - if (((mask & display_devices) == 0x0) && - (targetTypeEntry->uses_display_devices) && - (t->d)) { - continue; - } + /* + * special case the display device mask in the case that it + * was "hijacked" for something other than a display device: + * assign mask here so that it will be passed through to + * process_parsed_attribute_internal() unfiltered + */ - /* - * special case the display device mask in the case that it - * was "hijacked" for something other than a display device: - * assign mask here so that it will be passed through to - * process_parsed_attribute_internal() unfiltered - */ + if (a->flags & NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE) { + mask = a->display_device_mask; + } else { + mask = 0; + } - if (a->flags & NV_PARSER_TYPE_HIJACK_DISPLAY_DEVICE) { - mask = a->display_device_mask; - } + if (a->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { + status = NvCtrlGetValidStringDisplayAttributeValues(t->h, + mask, + a->attr, + &valid); + } else { + status = NvCtrlGetValidDisplayAttributeValues(t->h, + mask, + a->attr, + &valid); + } - if (a->flags & NV_PARSER_TYPE_STRING_ATTRIBUTE) { - status = NvCtrlGetValidStringDisplayAttributeValues(t->h, mask, a->attr, &valid); + if (status != NvCtrlSuccess) { + if (status == NvCtrlAttributeNotAvailable) { + nv_warning_msg("Attribute '%s' specified %s is not " + "available on %s.", + a->name, whence, t->name); } else { - status = NvCtrlGetValidDisplayAttributeValues(t->h, mask, a->attr, &valid); - } - - if (status != NvCtrlSuccess) { - if (status == NvCtrlAttributeNotAvailable) { - nv_warning_msg("Attribute '%s' specified %s is not " - "available on %s.", - a->name, whence, t->name); - } else { - nv_error_msg("Error querying valid values for attribute " - "'%s' on %s specified %s (%s).", - a->name, t->name, whence, - NvCtrlAttributesStrError(status)); - } - goto done; - } - - /* - * if this attribute is going to be assigned, then check - * that the attribute is writable; if it's not, give up - */ - - if ((assign) && (!(valid.permissions & ATTRIBUTE_TYPE_WRITE))) { - nv_error_msg("The attribute '%s' specified %s cannot be " - "assigned (it is a read-only attribute).", - a->name, whence); - goto done; + nv_error_msg("Error querying valid values for attribute " + "'%s' on %s specified %s (%s).", + a->name, t->name, whence, + NvCtrlAttributesStrError(status)); } + continue; + } - ret = process_parsed_attribute_internal(t, a, mask, target_type, - assign, verbose, whence, - valid); - if (ret == NV_FALSE) goto done; - - /* - * if this attribute is not per-display device, or this - * target does not know about display devices, or this target - * does not have display devices, then once through this loop - * is enough. - */ - - if ((!(valid.permissions & ATTRIBUTE_TYPE_DISPLAY)) || - (!(targetTypeEntry->uses_display_devices)) || - (!(t->d))) { - break; - } + /* + * if this attribute is going to be assigned, then check + * that the attribute is writable; if it's not, give up + */ - } /* bit */ + if (assign && !(valid.permissions & ATTRIBUTE_TYPE_WRITE)) { + nv_error_msg("The attribute '%s' specified %s cannot be " + "assigned (it is a read-only attribute).", + a->name, whence); + continue; + } + ret = process_parsed_attribute_internal(h, t, a, mask, target_type, + assign, verbose, whence, + valid); + if (ret == NV_FALSE) { + continue; + } } /* done looping over requested targets */ val = NV_TRUE; diff --git a/src/query-assign.h b/src/query-assign.h index 28e210c..6cc1538 100644 --- a/src/query-assign.h +++ b/src/query-assign.h @@ -105,8 +105,18 @@ NvCtrlAttributeHandle *nv_get_target_handle(const CtrlHandles *handles, int target_type, int target_id); +Bool nv_get_attribute_perms(CtrlHandles *h, int attr, uint32 flags, + NVCTRLAttributePermissionsRec *perms); + int nv_process_parsed_attribute(ParsedAttribute*, CtrlHandles *h, int, int, char*, ...) NV_ATTRIBUTE_PRINTF(5, 6); void nv_target_list_free(CtrlHandleTargetNode *head); + +NvCtrlAttributeHandle *nv_add_target(CtrlHandles *handles, Display *dpy, + int target_index, int display_id); + +const char *nv_get_display_target_config_name(const CtrlHandles *handles, + int target_id); + #endif /* __QUERY_ASSIGN_H__ */ diff --git a/src/version.mk b/src/version.mk index 8a89afe..2abb57a 100644 --- a/src/version.mk +++ b/src/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 325.15 +NVIDIA_VERSION = 331.13 @@ -31,7 +31,7 @@ LD ?= ld # only set these warnings and optimizations if CFLAGS is unset CFLAGS ?= -Wall -O2 # always set these -f CFLAGS -CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer +CFLAGS += -fno-strict-aliasing -fno-omit-frame-pointer -Wformat=2 CC_ONLY_CFLAGS ?= LDFLAGS ?= BIN_LDFLAGS ?= @@ -1 +1 @@ -NVIDIA_VERSION = 325.15 +NVIDIA_VERSION = 331.13 |