summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2009-09-04 13:33:22 -0700
committerAaron Plattner <aplattner@nvidia.com>2009-09-04 13:33:22 -0700
commit29bde128727f8b9d5cf9415265ba8b20ffc89944 (patch)
treeed3ab6685af05ff0f96590e780516af956b7d944
parentca8258fe8fa1947dc08a17cdb631767a08ae7222 (diff)
190.32190.32
-rw-r--r--doc/nvidia-settings.1.m423
-rw-r--r--src/command-line.c16
-rw-r--r--src/gtk+-2.x/ctkclocks.c11
-rw-r--r--src/gtk+-2.x/ctkevent.c6
-rw-r--r--src/gtk+-2.x/ctklicense.c9
-rw-r--r--src/gtk+-2.x/ctklicense.h2
-rw-r--r--src/gtk+-2.x/ctkthermal.c1014
-rw-r--r--src/gtk+-2.x/ctkthermal.h35
-rw-r--r--src/gtk+-2.x/ctkwindow.c4
-rw-r--r--src/libXNVCtrl/NVCtrl.h81
-rw-r--r--src/libXNVCtrl/nv_control.h3
-rw-r--r--src/parse.c13
-rw-r--r--src/parse.h3
-rw-r--r--src/query-assign.c27
14 files changed, 1201 insertions, 46 deletions
diff --git a/doc/nvidia-settings.1.m4 b/doc/nvidia-settings.1.m4
index ad86902..91c43fc 100644
--- a/doc/nvidia-settings.1.m4
+++ b/doc/nvidia-settings.1.m4
@@ -134,8 +134,11 @@ A target specification is contained within brackets and consists of a target typ
The target type name can be one of
.B screen,
.B gpu,
+.B framelock,
+.B vcs,
+.B gvi,
or
-.B framelock;
+.B fan;
the target id is the index into the list of targets (for that target type).
The target specification can be used in {DISPLAY} wherever an X screen can be used, following the syntax {host}:{display}[{target_type}:{target_id}].
See the output of
@@ -148,7 +151,7 @@ for information on which target types can be used with which attributes.
See the output of
.nf
- nvidia-settings -q screens -q gpus -q framelocks
+ nvidia-settings -q screens -q gpus -q framelocks -q vcs -q gvis -q fans
.fi
for lists of targets for each target type.
@@ -186,9 +189,12 @@ option, without
Specify
.B \-q screens,
.B \-q gpus,
+.B \-q framelocks,
+.B \-q vcs,
+.B \-q gvis,
or
-.B \-q framelocks
-to query a list of X screens, GPUs, or Frame Lock devices, respectively, that are present on the X Display {DISPLAY}.
+.B \-q fans
+to query a list of X screens, GPUs, Frame Lock devices, Visual Computing Systems, SDI Input Devices, or fans, respectively, that are present on the X Display {DISPLAY}.
Specify
.B \-q all
to query all attributes.
@@ -395,7 +401,7 @@ If no X screen is specified, then the attribute value will be queried for all X
.PP
Attributes can be addressed through "target types".
A target type indicates the object that is queried when you query an attribute.
-The default target type is an X screen, but other possible target types are GPUs and Frame Lock devices.
+The default target type is an X screen, but other possible target types are GPUs, Frame Lock devices, Visual Computing Systems, SDI Input Devices, and fans.
.PP
Target types give you different granularities with which to perform queries and assignments.
Since X screens can span multiple GPUs (in the case of Xinerama, or SLI), and multiple X screens can exist on the same GPU, it is sometimes useful to address attributes by GPU rather than X screen.
@@ -404,8 +410,11 @@ A target specification is contained within brackets and consists of a target typ
The target type name can be one of
.B screen,
.B gpu,
+.B framelock,
+.B vcs,
+.B gvi,
or
-.B framelock;
+.B fan;
the target id is the index into the list of targets (for that target type).
Target specifications can be used wherever an X screen is used in query and assignment commands; the target specification can be used either by itself on the left side of the forward slash, or as part of an X Display name.
.PP
@@ -435,7 +444,7 @@ for what targets types can be used with each attribute.
See the output of
.nf
- nvidia-settings --query screens --query gpus --query framelocks
+ nvidia-settings --query screens --query gpus --query framelocks --query vcs --query gvis --query fans
.fi
for lists of targets for each target type.
diff --git a/src/command-line.c b/src/command-line.c
index 326092f..37ba1de 100644
--- a/src/command-line.c
+++ b/src/command-line.c
@@ -194,15 +194,16 @@ static void print_assign_help(void)
"an X screen. A target specification is contained within brackets "
"and consists of a target type name, a colon, and the "
"target id. The target type name can be one of \"screen\", "
- "\"gpu\", or \"framelock\"; the target id is the index into the "
+ "\"gpu\", \"framelock\", \"vcs\", \"gvi\", or \"fan\"; the target "
+ "id is the index into the "
"list of targets (for that target type). The target specification "
"can be used in {DISPLAY} wherever an X screen can be used, "
"following the syntax {host}:{display}[{target_type}:"
"{target_id}]. See the output of `nvidia-settings -q all` for "
"information on which target types can be used with which "
"attributes. See the output of `nvidia-settings -q screens "
- "-q gpus -q framelocks` for lists of targets for each "
- "target type.");
+ "-q gpus -q framelocks -q vcs -q gvis -q fans` for lists of targets "
+ "for each target type.");
nv_msg(NULL, "");
@@ -243,10 +244,11 @@ static void print_query_help(void)
nv_msg(BIGTAB, "This queries the current value of the attribute "
"{attribute name} on the X Display {DISPLAY}. The format is "
"the same as that for the '--assign' option, without "
- "'={value}'. Specify '-q screens', '-q gpus', or '-q framelocks' "
- "to query a list of X screens, GPUs, or Frame Lock devices, "
- "respectively, that are present on the X Display {DISPLAY}. "
- "Specify '-q all' to query all attributes.");
+ "'={value}'. Specify '-q screens', '-q gpus', '-q framelocks', "
+ "'-q vcs', '-q gvis', or '-q fans' to query a list of X screens, "
+ "GPUs, Frame Lock devices, Visual Computing Systems, SDI Input "
+ "Devices, or Fans, respectively, that are present on the X Display "
+ "{DISPLAY}. Specify '-q all' to query all attributes.");
} /* print_query_help() */
diff --git a/src/gtk+-2.x/ctkclocks.c b/src/gtk+-2.x/ctkclocks.c
index efa7048..55c9650 100644
--- a/src/gtk+-2.x/ctkclocks.c
+++ b/src/gtk+-2.x/ctkclocks.c
@@ -87,7 +87,7 @@ static void clocks_received(GtkObject *object, gpointer arg1,
/**** GLOBALS ****************************************************************/
-static gboolean license_accepted = FALSE;
+static gboolean __license_accepted = FALSE;
/* Tooltips */
@@ -293,7 +293,7 @@ GtkWidget* ctk_clocks_new(NvCtrlAttributeHandle *handle,
ctk_object->probing_optimal = probing_optimal;
if ( overclocking_enabled ) {
- license_accepted = TRUE;
+ __license_accepted = TRUE;
}
/* Create the Clock menu widget */
@@ -459,7 +459,8 @@ GtkWidget* ctk_clocks_new(NvCtrlAttributeHandle *handle,
/* Create the enable dialog */
- ctk_object->license_dialog = ctk_license_dialog_new(GTK_WIDGET(ctk_object));
+ ctk_object->license_dialog = ctk_license_dialog_new(GTK_WIDGET(ctk_object),
+ "Clock Frequencies");
/* Create the auto detect dialog */
@@ -809,7 +810,7 @@ static void overclocking_state_toggled(GtkWidget *widget, gpointer user_data)
/* Verify user knows the risks involved */
- if ( enabled && !license_accepted ) {
+ if ( enabled && !__license_accepted ) {
result =
ctk_license_run_dialog(CTK_LICENSE_DIALOG(ctk_object->license_dialog));
@@ -817,7 +818,7 @@ static void overclocking_state_toggled(GtkWidget *widget, gpointer user_data)
switch (result)
{
case GTK_RESPONSE_ACCEPT:
- license_accepted = TRUE;
+ __license_accepted = TRUE;
break;
case GTK_RESPONSE_REJECT:
diff --git a/src/gtk+-2.x/ctkevent.c b/src/gtk+-2.x/ctkevent.c
index bea446e..ee80605 100644
--- a/src/gtk+-2.x/ctkevent.c
+++ b/src/gtk+-2.x/ctkevent.c
@@ -282,6 +282,11 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class)
MAKE_SIGNAL(NV_CTRL_GVI_DETECTED_CHANNEL_SMPTE352_IDENTIFIER);
MAKE_SIGNAL(NV_CTRL_GVI_GLOBAL_IDENTIFIER);
MAKE_SIGNAL(NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION);
+ MAKE_SIGNAL(NV_CTRL_GPU_COOLER_MANUAL_CONTROL);
+ MAKE_SIGNAL(NV_CTRL_THERMAL_COOLER_LEVEL);
+ MAKE_SIGNAL(NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT);
+ MAKE_SIGNAL(NV_CTRL_THERMAL_COOLER_CONTROL_TYPE);
+ MAKE_SIGNAL(NV_CTRL_THERMAL_COOLER_TARGET);
MAKE_SIGNAL(NV_CTRL_GPU_POWER_MIZER_MODE);
MAKE_SIGNAL(NV_CTRL_GVI_SYNC_OUTPUT_FORMAT);
MAKE_SIGNAL(NV_CTRL_GVI_MAX_CHANNELS_PER_JACK);
@@ -364,6 +369,7 @@ static void ctk_event_class_init(CtkEventClass *ctk_event_class)
MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU);
MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_GPUS_USING_VCSC);
MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU);
+ MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU);
MAKE_BINARY_SIGNAL(NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN);
#undef MAKE_BINARY_SIGNAL
diff --git a/src/gtk+-2.x/ctklicense.c b/src/gtk+-2.x/ctklicense.c
index 06846e7..c0b3f8b 100644
--- a/src/gtk+-2.x/ctklicense.c
+++ b/src/gtk+-2.x/ctklicense.c
@@ -34,7 +34,7 @@
#include "ctkbanner.h"
static const char * __enable_confirm_msg =
-"To use the features on the Clock Frequencies panel you\n"
+"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?";
@@ -219,12 +219,13 @@ gint ctk_license_run_dialog(CtkLicenseDialog *ctk_license_dialog)
-GtkWidget* ctk_license_dialog_new(GtkWidget *parent)
+GtkWidget* ctk_license_dialog_new(GtkWidget *parent, gchar *panel_name)
{
GObject *object;
CtkLicenseDialog *ctk_license_dialog;
GtkWidget *hbox, *label, *scrollWin, *event;
+ gchar *enable_message;
object = g_object_new(CTK_TYPE_LICENSE_DIALOG, NULL);
ctk_license_dialog = CTK_LICENSE_DIALOG(object);
@@ -280,7 +281,9 @@ GtkWidget* ctk_license_dialog_new(GtkWidget *parent)
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ctk_license_dialog->dialog)->vbox),
hbox, TRUE, TRUE, 10);
hbox = gtk_hbox_new(FALSE, 10);
- label = gtk_label_new(__enable_confirm_msg);
+ enable_message = g_strdup_printf(__enable_confirm_msg, panel_name);
+ label = gtk_label_new(enable_message);
+ g_free(enable_message);
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 15);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ctk_license_dialog->dialog)->vbox),
diff --git a/src/gtk+-2.x/ctklicense.h b/src/gtk+-2.x/ctklicense.h
index aa53a6f..0d29aaf 100644
--- a/src/gtk+-2.x/ctklicense.h
+++ b/src/gtk+-2.x/ctklicense.h
@@ -67,7 +67,7 @@ struct _CtkLicenseDialogClass
};
GType ctk_license_dialog_get_type (void) G_GNUC_CONST;
-GtkWidget* ctk_license_dialog_new (GtkWidget *object);
+GtkWidget* ctk_license_dialog_new (GtkWidget *object, gchar *panel_name);
gint ctk_license_run_dialog(CtkLicenseDialog *ctk_license_dialog);
G_END_DECLS
diff --git a/src/gtk+-2.x/ctkthermal.c b/src/gtk+-2.x/ctkthermal.c
index 1bab13b..fd4c4bd 100644
--- a/src/gtk+-2.x/ctkthermal.c
+++ b/src/gtk+-2.x/ctkthermal.c
@@ -24,16 +24,34 @@
#include <gtk/gtk.h>
#include <NvCtrlAttributes.h>
+#include <stdlib.h>
+#include "ctkutils.h"
+#include "ctkscale.h"
#include "ctkhelp.h"
#include "ctkthermal.h"
+#include "ctklicense.h"
#include "ctkgauge.h"
#include "ctkbanner.h"
#define FRAME_PADDING 10
#define DEFAULT_UPDATE_THERMAL_INFO_TIME_INTERVAL 1000
+static gboolean __license_accepted = FALSE;
+
static gboolean update_thermal_info(gpointer);
+static gboolean update_cooler_info(gpointer);
+static void sync_gui_sensitivity(CtkThermal *ctk_thermal);
+static void sync_gui_to_modify_cooler_level(CtkThermal *ctk_thermal);
+static gboolean sync_gui_to_update_cooler_event(gpointer user_data);
+static void cooler_control_checkbox_toggled(GtkWidget *widget, gpointer user_data);
+static void cooler_operating_level_changed(GtkObject *object, gpointer arg1,
+ gpointer user_data);
+static void apply_button_clicked(GtkWidget *widget, gpointer user_data);
+static void reset_button_clicked(GtkWidget *widget, gpointer user_data);
+static void adjustment_value_changed(GtkAdjustment *adjustment,
+ gpointer user_data);
+
static const char *__core_threshold_help =
"The Core Slowdown Threshold Temperature is the temperature "
@@ -56,6 +74,39 @@ static const char *__temp_level_help =
"temperature relative to the maximum GPU Core Slowdown "
"Threshold temperature.";
+static const char * __enable_button_help =
+"The Enable GPU Fan Settings checkbox enables access to control GPU Fan "
+"Speed. This option is available after enabling coolbits for GPU Fan control."
+"Note that controlling your GPU Fan Speed is not recommended and "
+"is done at your own risk. You should never have to enable this.";
+
+static const char * __fan_id_help =
+"This shows the GPU Fan's index.";
+
+static const char * __fan_speed_help =
+"This shows the current GPU Fan Speed.";
+
+static const char * __fan_control_type_help =
+"Fan Type indicates if and how this fan may be controlled. Possible "
+"types are Variable, Toggle or Restricted. Variable fans can be "
+"freely adjusted within a given range, while Toggle fans can "
+"be turned either ON or OFF. Restricted fans are not adjustable "
+"under end user control.";
+
+static const char * __fan_cooling_target_help =
+"Fan target shows which graphics device component is being cooled by "
+"a given fan. The target may be GPU, Memory, Power Supply or "
+"All.";
+
+static const char * __apply_button_help =
+"The Apply button allows you to set the desired speed for the "
+"GPU Fans. Slider positions are only applied "
+"after clicking this button.";
+
+static const char * __reset_button_help =
+"The Reset Hardware Defaults button lets you restore the original GPU "
+"Fan Speed and Fan control policy.";
+
GType ctk_thermal_get_type(void)
{
static GType ctk_thermal_type = 0;
@@ -82,12 +133,170 @@ GType ctk_thermal_get_type(void)
} /* ctk_thermal_get_type() */
+
+
+/*
+ * update_cooler_info() - Update all cooler information
+ */
+static gboolean update_cooler_info(gpointer user_data)
+{
+ int i, level, cooler_type, cooler_target;
+ gchar *tmp_str;
+ CtkThermal *ctk_thermal;
+ GtkWidget *table, *label, *eventbox;
+ gint ret;
+ gint row_idx; /* Where to insert into the cooler info table */
+
+ ctk_thermal = CTK_THERMAL(user_data);
+
+ /* Since table cell management in GTK lacks, just remove and rebuild
+ * the table from scratch.
+ */
+
+ /* Dump out the old table */
+
+ ctk_empty_container(ctk_thermal->cooler_table_hbox);
+
+ /* Generate a new table */
+
+ table = gtk_table_new(1, 5, FALSE);
+ 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);
+
+ gtk_box_pack_start(GTK_BOX(ctk_thermal->cooler_table_hbox),
+ table, FALSE, FALSE, 0);
+
+ label = gtk_label_new("ID");
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
+ eventbox = gtk_event_box_new();
+ gtk_table_attach(GTK_TABLE(table), eventbox, 0, 1, 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_id_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, 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_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_FILL, GTK_FILL | GTK_EXPAND, 5, 0);
+ gtk_container_add(GTK_CONTAINER(eventbox), label);
+ ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox,
+ __fan_control_type_help);
+
+ 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_FILL, GTK_FILL | GTK_EXPAND, 5, 0);
+ gtk_container_add(GTK_CONTAINER(eventbox), label);
+ ctk_config_set_tooltip(ctk_thermal->ctk_config, eventbox,
+ __fan_cooling_target_help);
+
+ /* Fill the cooler info */
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ row_idx = i+1;
+
+ gtk_table_resize(GTK_TABLE(table), row_idx+1, 4);
+
+ tmp_str = g_strdup_printf("%d", i);
+ label = gtk_label_new(tmp_str);
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 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) {
+ /* cooler information no longer available */
+ return FALSE;
+ }
+ 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_FILL, GTK_FILL | GTK_EXPAND, 5, 0);
+ free(tmp_str);
+
+ ret = NvCtrlGetAttribute(ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_CONTROL_TYPE,
+ &cooler_type);
+ if (ret != NvCtrlSuccess) {
+ /* cooler information no longer available */
+ return FALSE;
+ }
+ if (cooler_type == NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_VARIABLE) {
+ tmp_str = g_strdup_printf("Variable");
+ } else if (cooler_type == NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_TOGGLE) {
+ tmp_str = g_strdup_printf("Toggle");
+ } else if (cooler_type == NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_NONE) {
+ tmp_str = g_strdup_printf("Restricted");
+ }
+ 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_FILL, GTK_FILL | GTK_EXPAND, 5, 0);
+ free(tmp_str);
+
+ ret = NvCtrlGetAttribute(ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_TARGET,
+ &cooler_target);
+ if (ret != NvCtrlSuccess) {
+ /* cooler information no longer available */
+ return FALSE;
+ }
+ switch(cooler_target) {
+ case NV_CTRL_THERMAL_COOLER_TARGET_GPU:
+ tmp_str = g_strdup_printf("GPU");
+ break;
+ case NV_CTRL_THERMAL_COOLER_TARGET_MEMORY:
+ tmp_str = g_strdup_printf("Memory");
+ break;
+ case NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY:
+ tmp_str = g_strdup_printf("Power Supply");
+ break;
+ case NV_CTRL_THERMAL_COOLER_TARGET_GPU_RELATED:
+ tmp_str = g_strdup_printf("GPU, Memory, and Power Supply");
+ break;
+ default:
+ break;
+ }
+ 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_FILL, GTK_FILL | GTK_EXPAND, 5, 0);
+ free(tmp_str);
+ }
+ gtk_widget_show_all(table);
+
+ /* X driver takes fraction of second to refresh newly set value */
+
+ if (!ctk_thermal->cooler_control_enabled) {
+ sync_gui_to_modify_cooler_level(ctk_thermal);
+ }
+
+ return TRUE;
+} /* update_cooler_info() */
+
+
+
static gboolean update_thermal_info(gpointer user_data)
{
gint core, ambient;
CtkThermal *ctk_thermal;
NvCtrlAttributeHandle *handle;
- gint ret; gchar *s;
+ gint ret;
+ gchar *s;
ctk_thermal = CTK_THERMAL(user_data);
handle = ctk_thermal->attribute_handle;
@@ -115,25 +324,530 @@ static gboolean update_thermal_info(gpointer user_data)
gtk_label_set_text(GTK_LABEL(ctk_thermal->ambient_label), s);
g_free(s);
}
-
+ if ( ctk_thermal->cooler_count ) {
+ update_cooler_info(ctk_thermal);
+ }
+
return TRUE;
-}
+} /* update_thermal_info() */
+
+
+
+/****
+ *
+ * Updates widgets in relation to current cooler control state.
+ *
+ */
+static void cooler_control_state_update_gui(CtkThermal *ctk_thermal)
+{
+ ReturnStatus ret;
+ int value;
+ gboolean enabled;
+
+
+ /* We need to check the cooler control state status with
+ * the server everytime someone tries to change the state
+ * because the set might have failed.
+ */
+
+ ret = NvCtrlGetAttribute(ctk_thermal->attribute_handle,
+ NV_CTRL_GPU_COOLER_MANUAL_CONTROL,
+ &value);
+ if (ret != NvCtrlSuccess) {
+ enabled = FALSE;
+ } else {
+ enabled = (value==NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE);
+ }
+
+ ctk_thermal->cooler_control_enabled = enabled;
+
+ /* Sync the gui to be able to modify the fan speed */
+
+ sync_gui_to_modify_cooler_level(ctk_thermal);
+
+ /* Update the status bar */
+
+ ctk_config_statusbar_message(ctk_thermal->ctk_config,
+ "GPU Fan control %sabled.",
+ enabled?"en":"dis");
+
+} /* cooler_control_state_update_gui() */
+
+
+
+/*****
+ *
+ * Signal handler - Called when the user toggles the "Enable Cooler control"
+ * button.
+ *
+ */
+static void cooler_control_state_toggled(GtkWidget *widget, gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+ gboolean enabled;
+ ReturnStatus ret;
+ int value;
+ gint result;
+
+ /* Get enabled state */
+
+ enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ value = (enabled==1) ? NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE :
+ NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE;
+
+ /* Verify user knows the risks involved */
+
+ if ( enabled && !__license_accepted ) {
+
+ result =
+ ctk_license_run_dialog(CTK_LICENSE_DIALOG(ctk_thermal->enable_dialog));
+
+ switch (result) {
+ case GTK_RESPONSE_ACCEPT:
+ __license_accepted = TRUE;
+ break;
+
+ case GTK_RESPONSE_REJECT:
+ default:
+ /* Cancel */
+ g_signal_handlers_block_by_func(G_OBJECT(
+ ctk_thermal->enable_checkbox),
+ G_CALLBACK(cooler_control_state_toggled),
+ (gpointer) ctk_thermal);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
+ FALSE);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(
+ ctk_thermal->enable_checkbox),
+ G_CALLBACK(cooler_control_state_toggled),
+ (gpointer) ctk_thermal);
+ return;
+ }
+ }
+
+
+ /* Update the server */
+
+ ret = NvCtrlSetAttribute(ctk_thermal->attribute_handle,
+ NV_CTRL_GPU_COOLER_MANUAL_CONTROL, value);
+
+ /* Update the GUI */
+
+ cooler_control_state_update_gui(ctk_thermal);
+
+} /* cooler_control_state_toggled() */
+
+
+
+/*****
+ *
+ * Signal handler - Called when another NV-CONTROL client has set the
+ * cooler control state.
+ *
+ */
+static void cooler_control_state_received(GtkObject *object,
+ gpointer arg1, gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+
+ /* Update GUI with enable status */
+
+ cooler_control_state_update_gui(ctk_thermal);
+
+} /* cooler_control_state_update_received() */
+
+
+
+/****
+ *
+ * Updates sensitivity of widgets in relation to the state
+ * of cooler control.
+ *
+ */
+static void sync_gui_sensitivity(CtkThermal *ctk_thermal)
+{
+ gboolean enabled = ctk_thermal->cooler_control_enabled;
+ gboolean settings_changed = ctk_thermal->settings_changed;
+ gint i;
+
+ if ( ctk_thermal->cooler_count && ctk_thermal->show_fan_control_frame ) {
+ /* Update the enable checkbox */
+
+ g_signal_handlers_block_by_func(G_OBJECT(ctk_thermal->enable_checkbox),
+ G_CALLBACK(cooler_control_state_toggled),
+ (gpointer) ctk_thermal);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctk_thermal->enable_checkbox),
+ enabled);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(ctk_thermal->enable_checkbox),
+ G_CALLBACK(cooler_control_state_toggled),
+ (gpointer) ctk_thermal);
+
+ /* Update the cooler control widgets */
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ gtk_widget_set_sensitive(ctk_thermal->cooler_control[i].widget,
+ enabled);
+ }
+
+ /* Update the Apply button */
+
+ gtk_widget_set_sensitive(ctk_thermal->apply_button,
+ enabled && settings_changed);
+
+ /* Update the Reset button */
+
+ gtk_widget_set_sensitive(ctk_thermal->reset_button,
+ enabled && ctk_thermal->enable_reset_button);
+ }
+} /* sync_gui_sensitivity() */
+
+
+
+/*****
+ *
+ * Signal handler - User clicked the "apply" button.
+ *
+ */
+static void apply_button_clicked(GtkWidget *widget, gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+
+ ReturnStatus ret;
+ gint cooler_level;
+ gint i;
+
+
+ /* Set cooler's level on server */
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ if ( ctk_thermal->cooler_control[i].changed ) {
+ if ( ctk_thermal->cooler_control[i].adjustment ) {
+ cooler_level = gtk_adjustment_get_value(
+ ctk_thermal->cooler_control[i].adjustment);
+ } else {
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ ctk_thermal->cooler_control[i].widget))) {
+ cooler_level =
+ ctk_thermal->cooler_control[i].range.u.range.max;
+ } else {
+ cooler_level =
+ ctk_thermal->cooler_control[i].range.u.range.min;
+ }
+ }
+
+ ret = NvCtrlSetAttribute(ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL,
+ cooler_level);
+
+ if ( ret != NvCtrlSuccess ) {
+ ctk_config_statusbar_message(ctk_thermal->ctk_config,
+ "Failed to set new Fan Speed!");
+ return;
+ }
+ }
+ }
+ ctk_thermal->cooler_control[i].changed = FALSE;
+ ctk_thermal->settings_changed = FALSE;
+ ctk_thermal->enable_reset_button = TRUE;
+
+ /* Sync up with the server current fan speed */
+
+ sync_gui_to_modify_cooler_level(ctk_thermal);
+
+ /* Update the gui sensitivity */
+
+ sync_gui_sensitivity(ctk_thermal);
+
+ /* Enable the reset button */
+
+ gtk_widget_set_sensitive(ctk_thermal->reset_button, TRUE);
+
+ ctk_config_statusbar_message(ctk_thermal->ctk_config,
+ "Set new Fan Speed.");
+} /* apply_button_clicked() */
+
+
+
+/*****
+ *
+ * Signal handler - User clicked the 'reset hardware defaults' button.
+ *
+ */
+static void reset_button_clicked(GtkWidget *widget, gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+ ReturnStatus ret;
+ gboolean reset_failed = FALSE;
+ gint i;
+
+ /* Set cooler related values to default */
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ ret = NvCtrlSetAttribute(ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT,
+ NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT);
+ if ( ret != NvCtrlSuccess ) {
+ reset_failed = TRUE;
+ }
+ }
+ ctk_thermal->enable_reset_button = FALSE;
+
+ /* Update GUI to reflect current values */
+
+ cooler_control_state_update_gui(ctk_thermal);
+
+ /* Disable the apply button */
+
+ gtk_widget_set_sensitive(ctk_thermal->apply_button, FALSE);
+
+ /* Disable the reset button */
+
+ gtk_widget_set_sensitive(ctk_thermal->reset_button,
+ ctk_thermal->enable_reset_button);
+
+ /* Set statusbar messages */
+
+ if ( reset_failed ) {
+ ctk_config_statusbar_message(ctk_thermal->ctk_config,
+ "Failed to reset fan speed default value!");
+ } else {
+ ctk_config_statusbar_message(ctk_thermal->ctk_config,
+ "Reset to fan speed default value.");
+ }
+ return;
+
+} /* reset_button_clicked() */
+
+
+
+/*****
+ *
+ * Signal handler - Handles slider adjustments by the user.
+ *
+ */
+static void adjustment_value_changed(GtkAdjustment *adjustment,
+ gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+ gint i;
+
+ /* Set flag for cooler whose operating level value changed */
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ if (ctk_thermal->cooler_control[i].adjustment ==
+ adjustment) {
+ ctk_thermal->cooler_control[i].changed = TRUE;
+ }
+ }
+ ctk_thermal->settings_changed = TRUE;
+ /* Enable the apply button */
+
+ gtk_widget_set_sensitive(ctk_thermal->apply_button, TRUE);
+
+ /* Disable the reset button */
+
+ gtk_widget_set_sensitive(ctk_thermal->reset_button, FALSE);
+
+} /* adjustment_value_changed() */
+
+
+
+/*****
+ *
+ * Syncs the gui to properly display the correct cooler level the user wants to
+ * modify, or has modified with another NV_CONTROL client.
+ *
+ */
+static void sync_gui_to_modify_cooler_level(CtkThermal *ctk_thermal)
+{
+ GtkRange *gtk_range;
+ GtkAdjustment *gtk_adjustment_fan;
+ NVCTRLAttributeValidValuesRec cooler_range;
+ gboolean can_access_cooler_level = TRUE;
+ ReturnStatus ret;
+ gint val, i, enabled;
+ gint cooler_level;
+
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ /* Obtain the current value and range of the fan speed */
+
+ ret = NvCtrlGetAttribute(ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL,
+ &cooler_level);
+ if ( ret != NvCtrlSuccess ) {
+ can_access_cooler_level = FALSE;
+ }
+ ctk_thermal->cooler_control[i].level = cooler_level;
+ if ( can_access_cooler_level && ctk_thermal->show_fan_control_frame ) {
+ /* Make cooler control slider reflect the right range/values */
+
+ if ( ctk_thermal->cooler_control[i].adjustment ) {
+
+ ret = NvCtrlGetValidAttributeValues
+ (ctk_thermal->cooler_control[i].handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL,
+ &cooler_range);
+ if ( ret != NvCtrlSuccess ) {
+ can_access_cooler_level = FALSE;
+ }
+ ctk_thermal->cooler_control[i].range = cooler_range;
+ if ( can_access_cooler_level ) {
+ gtk_adjustment_fan = ctk_thermal->cooler_control[i].adjustment;
+ gtk_range = GTK_RANGE(CTK_SCALE(
+ ctk_thermal->cooler_control[i].widget)->
+ gtk_scale);
+
+ g_signal_handlers_block_by_func(G_OBJECT(gtk_adjustment_fan),
+ G_CALLBACK(adjustment_value_changed),
+ (gpointer) ctk_thermal);
+ gtk_range_set_range(gtk_range,
+ ctk_thermal->cooler_control[i].range.u.range.min,
+ ctk_thermal->cooler_control[i].range.u.range.max);
+
+ val = gtk_adjustment_get_value(gtk_adjustment_fan);
+ if (val != ctk_thermal->cooler_control[i].level) {
+ gtk_adjustment_set_value(gtk_adjustment_fan,
+ ctk_thermal->cooler_control[i].level);
+ }
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(
+ gtk_adjustment_fan),
+ G_CALLBACK(
+ adjustment_value_changed),
+ (gpointer) ctk_thermal);
+ }
+ } else {
+ /* Make cooler control checkbox reflect the right value */
+
+ g_signal_handlers_block_by_func(G_OBJECT(
+ ctk_thermal->cooler_control[i].widget),
+ G_CALLBACK(
+ cooler_control_checkbox_toggled),
+ (gpointer) ctk_thermal);
+
+ enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ ctk_thermal->cooler_control[i].widget));
+
+ if (enabled && ctk_thermal->cooler_control[i].level) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
+ ctk_thermal->cooler_control[i].widget),
+ !enabled);
+ }
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(
+ ctk_thermal->cooler_control[i].widget),
+ G_CALLBACK(cooler_control_checkbox_toggled),
+ (gpointer) ctk_thermal);
+ }
+ }
+ }
+ /* Update the gui sensitivity */
+
+ sync_gui_sensitivity(ctk_thermal);
+
+} /* sync_gui_to_modify_cooler_level() */
+
+
+
+/*****
+ *
+ * Helper function - calls sync_gui_to_modify_cooler_level()
+ *
+ */
+static gboolean sync_gui_to_update_cooler_event(gpointer user_data)
+{
+ CtkThermal *ctk_thermal = (CtkThermal *) user_data;
+
+ sync_gui_to_modify_cooler_level(ctk_thermal);
+
+ return FALSE;
+
+} /* sync_gui_to_update_cooler_event() */
+
+
+
+/*****
+ *
+ * Callback function when another NV_CONTROL client changed cooler level.
+ *
+ */
+static void cooler_operating_level_changed(GtkObject *object, gpointer arg1,
+ gpointer user_data)
+{
+ /* sync_gui_to_modify_cooler_level() to be called once when all other
+ * pending events are consumed.
+ */
+
+ g_idle_add(sync_gui_to_update_cooler_event, (gpointer) user_data);
+
+} /* cooler_operating_level_changed() */
+
+
+
+/*****
+ *
+ * Signal handler - Handles checkbox toggling by the user.
+ *
+ */
+static void cooler_control_checkbox_toggled(GtkWidget *widget,
+ gpointer user_data)
+{
+ CtkThermal *ctk_thermal = CTK_THERMAL(user_data);
+ gint i;
+
+ /* Set bit for cooler whose value want to change */
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ if ((ctk_thermal->cooler_control[i].widget) == widget) {
+ ctk_thermal->cooler_control[i].changed = TRUE;
+ ctk_thermal->settings_changed = TRUE;
+ }
+ }
+
+ /* Enable the apply button */
+
+ gtk_widget_set_sensitive(ctk_thermal->apply_button, TRUE);
+
+} /* cooler_control_checkbox_toggled() */
+
+
GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle,
- CtkConfig *ctk_config)
+ CtkConfig *ctk_config,
+ CtkEvent *ctk_event)
{
GObject *object;
CtkThermal *ctk_thermal;
+ CtrlHandles *h;
+ GtkObject *adjustment;
GtkWidget *gauge;
GtkWidget *hbox, *hbox2, *vbox, *table;
GtkWidget *frame, *banner, *label;
+ GtkWidget *vbox1;
GtkWidget *eventbox, *entry;
+ GtkWidget *fan_control_frame;
+ GtkWidget *hsep;
+ GtkWidget *scale;
+ GtkWidget *alignment;
ReturnStatus ret;
-
+ NvCtrlAttributeHandle *cooler_handle;
+ NVCTRLAttributeValidValuesRec cooler_range;
gint trigger, ambient;
gint core, upper;
gchar *s;
-
+ gint i, j;
+ gint cooler_level;
+ gint cooler_control_type;
+ gchar *name = NULL;
+ int *pData;
+ int len, value;
+ Bool can_access_cooler_level;
+ Bool cooler_control_enabled;
+ int cur_cooler_idx = 0;
/* make sure we have a handle */
@@ -166,7 +880,10 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle,
ctk_thermal = CTK_THERMAL(object);
ctk_thermal->attribute_handle = handle;
ctk_thermal->ctk_config = ctk_config;
-
+ ctk_thermal->settings_changed = FALSE;
+ ctk_thermal->show_fan_control_frame = TRUE;
+ ctk_thermal->cooler_count = 0;
+
/* set container properties for the CtkThermal widget */
gtk_box_set_spacing(GTK_BOX(ctk_thermal), 10);
@@ -176,6 +893,24 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle,
banner = ctk_banner_image_new(BANNER_ARTWORK_THERMAL);
gtk_box_pack_start(GTK_BOX(object), banner, FALSE, FALSE, 0);
+ /* Check if we can control cooler state */
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GPU_COOLER_MANUAL_CONTROL,
+ &value);
+ if ( ret != NvCtrlSuccess ) {
+ ctk_thermal->show_fan_control_frame = FALSE;
+ }
+
+ cooler_control_enabled =
+ (value==NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE)?TRUE:FALSE;
+
+ can_access_cooler_level = TRUE;
+ ctk_thermal->cooler_control_enabled = cooler_control_enabled;
+ ctk_thermal->enable_reset_button = FALSE;
+
+ if ( cooler_control_enabled ) {
+ __license_accepted = TRUE;
+ }
/* Thermal Information */
@@ -288,6 +1023,241 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle,
ctk_config_set_tooltip(ctk_config, eventbox, __temp_level_help);
+ /* Retrieve CtrlHandles from ctk_config */
+
+ h = ctk_config->pCtrlHandles;
+
+ if ( h->targets[COOLER_TARGET].n == 0 ) {
+ goto end;
+ }
+
+ /* Fan Information Title */
+
+ vbox = gtk_vbox_new(FALSE, 5);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(object), vbox, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new("Fan Information");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+ hsep = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), hsep, TRUE, TRUE, 5);
+
+ ctk_thermal->fan_information_box = vbox;
+
+ /* Fan Information Table */
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+ ctk_thermal->cooler_table_hbox = hbox;
+
+ /* Query the list of coolers attached to this GPU */
+
+ ret = NvCtrlGetBinaryAttribute(handle, 0,
+ NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU,
+ (unsigned char **)(&pData), &len);
+ if ( ret == NvCtrlSuccess ) {
+ ctk_thermal->cooler_count = pData[0];
+ }
+
+ /* Create cooler level control sliders/checkbox */
+
+ ctk_thermal->cooler_control = (CoolerControlPtr)
+ malloc(pData[0] * sizeof(CoolerControlRec));
+
+ for (j = 1; j <= ctk_thermal->cooler_count; j++) {
+ cooler_handle = h->targets[COOLER_TARGET].t[pData[j]].h;
+
+ if ( !cooler_handle ) {
+ continue;
+ }
+
+ /* Get current cooler level and range */
+
+ ret = NvCtrlGetAttribute(cooler_handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL,
+ &cooler_level);
+ if ( ret != NvCtrlSuccess ) {
+ can_access_cooler_level = FALSE;
+ }
+
+ ret = NvCtrlGetValidAttributeValues(cooler_handle,
+ NV_CTRL_THERMAL_COOLER_LEVEL,
+ &cooler_range);
+ if ( ret != NvCtrlSuccess ) {
+ can_access_cooler_level = FALSE;
+ }
+
+ ctk_thermal->cooler_control[cur_cooler_idx].level = cooler_level;
+ ctk_thermal->cooler_control[cur_cooler_idx].range = cooler_range;
+ ctk_thermal->cooler_control[cur_cooler_idx].handle = cooler_handle;
+
+ /* Create the object for receiving NV-CONTROL events */
+
+ ctk_thermal->cooler_control[cur_cooler_idx].event =
+ CTK_EVENT(ctk_event_new(cooler_handle));
+
+ if ( can_access_cooler_level && ctk_thermal->show_fan_control_frame ) {
+ /*
+ * Get NV_CTRL_THERMAL_COOLER_CONTROL_TYPE to decide cooler
+ * control widget should be slider or checkbox.
+ */
+
+ ret = NvCtrlGetAttribute(cooler_handle,
+ NV_CTRL_THERMAL_COOLER_CONTROL_TYPE,
+ &cooler_control_type);
+ if ((ret == NvCtrlSuccess) &&
+ (cooler_control_type ==
+ NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_VARIABLE)) {
+
+ adjustment =
+ gtk_adjustment_new(cooler_level,
+ cooler_range.u.range.min,
+ cooler_range.u.range.max,
+ 1, 5, 0.0);
+ name = g_strdup_printf("Fan %d Speed", cur_cooler_idx);
+ scale = ctk_scale_new(GTK_ADJUSTMENT(adjustment), name,
+ ctk_config, G_TYPE_INT);
+ ctk_thermal->cooler_control[cur_cooler_idx].widget = scale;
+ ctk_thermal->cooler_control[cur_cooler_idx].adjustment =
+ GTK_ADJUSTMENT(adjustment);
+
+ g_signal_connect(adjustment, "value_changed",
+ G_CALLBACK(adjustment_value_changed),
+ (gpointer) ctk_thermal);
+ } else if ((ret == NvCtrlSuccess) &&
+ (cooler_control_type ==
+ NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_TOGGLE)) {
+ name = g_strdup_printf("Fan-%d Speed", cur_cooler_idx);
+
+ ctk_thermal->cooler_control[cur_cooler_idx].widget =
+ gtk_check_button_new_with_label(name);
+
+ g_signal_connect(G_OBJECT(ctk_thermal->cooler_control
+ [cur_cooler_idx].widget),
+ "toggled",
+ G_CALLBACK(cooler_control_checkbox_toggled),
+ (gpointer) ctk_thermal);
+
+ ctk_thermal->cooler_control[cur_cooler_idx].adjustment = NULL;
+ }
+ free(name);
+ gtk_widget_set_sensitive(ctk_thermal->cooler_control
+ [cur_cooler_idx].widget,
+ cooler_control_enabled);
+ cur_cooler_idx++;
+ }
+ }
+
+ XFree(pData);
+
+ if ( ctk_thermal->cooler_count && ctk_thermal->show_fan_control_frame ) {
+ /* Create the enable dialog */
+
+ ctk_thermal->enable_dialog = ctk_license_dialog_new(GTK_WIDGET(ctk_thermal),
+ "Thermal Settings");
+
+ /* Create the Enable Cooler control checkbox widget */
+
+ ctk_thermal->enable_checkbox =
+ gtk_check_button_new_with_label("Enable GPU Fan Settings");
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(ctk_thermal->enable_checkbox),
+ cooler_control_enabled);
+
+ g_signal_connect(G_OBJECT(ctk_thermal->enable_checkbox), "toggled",
+ G_CALLBACK(cooler_control_state_toggled),
+ (gpointer) ctk_thermal);
+
+ ctk_config_set_tooltip(ctk_config, ctk_thermal->enable_checkbox,
+ __enable_button_help);
+
+ /* Create the Apply button widget */
+
+ ctk_thermal->apply_button =
+ gtk_button_new_with_label("Apply");
+
+ g_signal_connect(G_OBJECT(ctk_thermal->apply_button), "clicked",
+ G_CALLBACK(apply_button_clicked),
+ (gpointer) ctk_thermal);
+
+ ctk_config_set_tooltip(ctk_config, ctk_thermal->apply_button,
+ __apply_button_help);
+
+ gtk_widget_set_sensitive(ctk_thermal->apply_button, FALSE);
+
+ /* Create the Reset hardware button widget */
+
+ ctk_thermal->reset_button =
+ gtk_button_new_with_label("Reset Hardware Defaults");
+
+ g_signal_connect(G_OBJECT(ctk_thermal->reset_button), "clicked",
+ G_CALLBACK(reset_button_clicked),
+ (gpointer) ctk_thermal);
+
+ ctk_config_set_tooltip(ctk_config, ctk_thermal->reset_button,
+ __reset_button_help);
+
+ gtk_widget_set_sensitive(ctk_thermal->reset_button, FALSE);
+
+ /* Add Cooler Control frame */
+
+ hbox = gtk_hbox_new(FALSE, 5);
+
+ fan_control_frame = gtk_frame_new(NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
+ gtk_box_pack_start(GTK_BOX(vbox), fan_control_frame, FALSE, FALSE, 5);
+ vbox = gtk_vbox_new(FALSE, 0);
+ vbox1 = gtk_vbox_new(FALSE, 0);
+
+ gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5);
+
+ gtk_container_add(GTK_CONTAINER(fan_control_frame), vbox);
+ gtk_box_pack_start(GTK_BOX(vbox), ctk_thermal->enable_checkbox,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 0);
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ if (ctk_thermal->cooler_control[i].widget) {
+ gtk_box_pack_start(GTK_BOX(vbox1),
+ ctk_thermal->cooler_control[i].widget,
+ FALSE, FALSE, 5);
+ }
+ }
+
+ /* Add the Apply and Reset buttons */
+
+ hbox = gtk_hbox_new(FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(hbox), ctk_thermal->apply_button,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), ctk_thermal->reset_button,
+ FALSE, FALSE, 0);
+
+ alignment = gtk_alignment_new(1, 1, 0, 0);
+ gtk_container_add(GTK_CONTAINER(alignment), hbox);
+ gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 5);
+
+ for (i = 0; i < ctk_thermal->cooler_count; i++) {
+ g_signal_connect(G_OBJECT(ctk_thermal->cooler_control[i].event),
+ CTK_EVENT_NAME(NV_CTRL_THERMAL_COOLER_LEVEL),
+ G_CALLBACK(cooler_operating_level_changed),
+ (gpointer) ctk_thermal);
+ }
+ g_signal_connect(G_OBJECT(ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GPU_COOLER_MANUAL_CONTROL),
+ G_CALLBACK(cooler_control_state_received),
+ (gpointer) ctk_thermal);
+ }
+
+end:
+ /* sync GUI to current server settings */
+
+ sync_gui_to_modify_cooler_level(ctk_thermal);
+ update_thermal_info(ctk_thermal);
+
/* Register a timer callback to update the temperatures */
s = g_strdup_printf("Thermal Monitor (GPU %d)",
@@ -299,10 +1269,9 @@ GtkWidget* ctk_thermal_new(NvCtrlAttributeHandle *handle,
(GSourceFunc) update_thermal_info,
(gpointer) ctk_thermal);
g_free(s);
-
- update_thermal_info(ctk_thermal);
+
gtk_widget_show_all(GTK_WIDGET(ctk_thermal));
-
+
return GTK_WIDGET(ctk_thermal);
}
@@ -329,9 +1298,30 @@ GtkTextBuffer *ctk_thermal_create_help(GtkTextTagTable *table,
ctk_help_para(b, &i, __ambient_temp_help);
}
- ctk_help_heading(b, &i, "Temperature Level");
- ctk_help_para(b, &i, __temp_level_help);
+ ctk_help_title(b, &i, "GPU Fan Settings Help");
+
+ ctk_help_heading(b, &i, "ID");
+ ctk_help_para(b, &i, __fan_id_help);
+
+ ctk_help_heading(b, &i, "Speed (%)");
+ ctk_help_para(b, &i, __fan_speed_help);
+ ctk_help_heading(b, &i, "Type");
+ ctk_help_para(b, &i, __fan_control_type_help);
+
+ ctk_help_heading(b, &i, "Cooling Target");
+ ctk_help_para(b, &i, __fan_cooling_target_help);
+
+ ctk_help_heading(b, &i, "Enable GPU Fan Settings");
+ ctk_help_para(b, &i, __enable_button_help);
+
+ if ( ctk_thermal->show_fan_control_frame ) {
+ ctk_help_heading(b, &i, "Enable GPU Fan Settings");
+ ctk_help_para(b, &i, __apply_button_help);
+
+ ctk_help_heading(b, &i, "Enable GPU Fan Settings");
+ ctk_help_para(b, &i, __reset_button_help);
+ }
ctk_help_finish(b);
return b;
diff --git a/src/gtk+-2.x/ctkthermal.h b/src/gtk+-2.x/ctkthermal.h
index 0cb0bbb..37a27f8 100644
--- a/src/gtk+-2.x/ctkthermal.h
+++ b/src/gtk+-2.x/ctkthermal.h
@@ -27,6 +27,7 @@
#include "NvCtrlAttributes.h"
#include "ctkconfig.h"
+#include "ctkevent.h"
G_BEGIN_DECLS
@@ -51,6 +52,17 @@ G_BEGIN_DECLS
typedef struct _CtkThermal CtkThermal;
typedef struct _CtkThermalClass CtkThermalClass;
+typedef struct _CoolerControl {
+ NVCTRLAttributeValidValuesRec range;
+ NvCtrlAttributeHandle *handle;
+
+ int level;
+ Bool changed; /* Cooler level moved by user */
+ GtkWidget *widget; /* Cooler level control widget */
+ GtkAdjustment *adjustment; /* Track adjustment */
+ CtkEvent *event; /* Receive NV_CONTROL events */
+} CoolerControlRec, *CoolerControlPtr;
+
struct _CtkThermal
{
GtkVBox parent;
@@ -61,6 +73,25 @@ struct _CtkThermal
GtkWidget *core_label;
GtkWidget *core_gauge;
GtkWidget *ambient_label;
+ GtkWidget *apply_button;
+ GtkWidget *reset_button;
+ GtkWidget *enable_checkbox;
+ GtkWidget *enable_dialog;
+ GtkWidget *license_window;
+ GtkWidget *fan_control_frame;
+ GtkWidget *adaptive_clock_status;
+ GtkWidget *fan_target;
+ GtkWidget *fan_signal;
+ GtkWidget *fan_control_policy;
+ GtkWidget *cooler_table_hbox;
+ GtkWidget *fan_information_box;
+
+ gboolean cooler_control_enabled;
+ gboolean settings_changed;
+ gboolean show_fan_control_frame;
+ gboolean enable_reset_button;
+ CoolerControlPtr cooler_control;
+ int cooler_count;
};
struct _CtkThermalClass
@@ -69,7 +100,9 @@ struct _CtkThermalClass
};
GType ctk_thermal_get_type (void) G_GNUC_CONST;
-GtkWidget* ctk_thermal_new (NvCtrlAttributeHandle *, CtkConfig *);
+GtkWidget* ctk_thermal_new (NvCtrlAttributeHandle *,
+ CtkConfig *,
+ CtkEvent *);
GtkTextBuffer* ctk_thermal_create_help (GtkTextTagTable *, CtkThermal *);
void ctk_thermal_start_timer (GtkWidget *);
diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c
index b428d8f..bfb6843 100644
--- a/src/gtk+-2.x/ctkwindow.c
+++ b/src/gtk+-2.x/ctkwindow.c
@@ -815,10 +815,10 @@ GtkWidget *ctk_window_new(ParsedAttribute *p, ConfigProperties *conf,
/* thermal information */
- child = ctk_thermal_new(gpu_handle, ctk_config);
+ child = ctk_thermal_new(gpu_handle, ctk_config, ctk_event);
if (child) {
help = ctk_thermal_create_help(tag_table, CTK_THERMAL(child));
- add_page(child, help, ctk_window, &iter, NULL, "Thermal Monitor",
+ add_page(child, help, ctk_window, &iter, NULL, "Thermal Settings",
NULL, ctk_thermal_start_timer, ctk_thermal_stop_timer);
}
diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h
index 12f33b3..46e2af8 100644
--- a/src/libXNVCtrl/NVCtrl.h
+++ b/src/libXNVCtrl/NVCtrl.h
@@ -43,7 +43,7 @@
#define NV_CTRL_TARGET_TYPE_FRAMELOCK 2
#define NV_CTRL_TARGET_TYPE_VCSC 3 /* Visual Computing System */
#define NV_CTRL_TARGET_TYPE_GVI 4
-
+#define NV_CTRL_TARGET_TYPE_COOLER 5 /* e.g., fan */
/**************************************************************************/
@@ -91,6 +91,9 @@
* I: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GVI target type
* via XNVCTRLQueryTargetAttribute().
*
+ * C: The attribute may be queried using an NV_CTRL_TARGET_TYPE_COOLER target
+ * type via XNVCTRLQueryTargetAttribute().
+ *
* NOTE: Unless mentioned otherwise, all attributes may be queried using
* an NV_CTRL_TARGET_TYPE_X_SCREEN target type via
* XNVCTRLQueryTargetAttribute().
@@ -2554,6 +2557,60 @@
#define NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION 318 /* R-- */
/*
+ * NV_CTRL_GPU_COOLER_MANUAL_CONTROL - Query the current or set a new
+ * cooler control state; the value of this attribute controls the
+ * availability of additional cooler control attributes (see below).
+ *
+ * Note: this attribute is unavailable unless cooler control support
+ * has been enabled in the X server (by the user).
+ */
+
+#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL 319 /* RW-G */
+#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE 0
+#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE 1
+
+/*
+ * NV_CTRL_THERMAL_COOLER_LEVEL - Returns cooler's current operating
+ * level.
+ */
+
+#define NV_CTRL_THERMAL_COOLER_LEVEL 320 /* RW-C */
+
+/* NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT - Sets default values of
+ * cooler.
+ */
+
+#define NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT 321 /* -W-C */
+
+/*
+ * NV_CTRL_THERMAL_COOLER_CONTROL_TYPE -
+ * Returns a cooler's control signal characteristics.
+ * The possible types are restricted, Variable and Toggle.
+ */
+
+#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE 322 /* R--C */
+#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_NONE 0
+#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_TOGGLE 1
+#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_VARIABLE 2
+
+/*
+ * NV_CTRL_THERMAL_COOLER_TARGET - Returns objects that cooler cools.
+ * Targets may be GPU, Memory, Power Supply or All of these.
+ * GPU_RELATED = GPU | MEMORY | POWER_SUPPLY
+ *
+ */
+
+#define NV_CTRL_THERMAL_COOLER_TARGET 323 /* R--C */
+#define NV_CTRL_THERMAL_COOLER_TARGET_NONE 0
+#define NV_CTRL_THERMAL_COOLER_TARGET_GPU 1
+#define NV_CTRL_THERMAL_COOLER_TARGET_MEMORY 2
+#define NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY 4
+#define NV_CTRL_THERMAL_COOLER_TARGET_GPU_RELATED \
+ (NV_CTRL_THERMAL_COOLER_TARGET_GPU | \
+ NV_CTRL_THERMAL_COOLER_TARGET_MEMORY | \
+ NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY)
+
+/*
* NV_CTRL_GPU_POWER_MIZER_MODE - Provides a hint to the driver
* as to how to manage the performance of the GPU.
*
@@ -2608,7 +2665,6 @@
*/
#define NV_CTRL_GVI_NUM_CAPTURE_SURFACES 338 /* RW-I */
-#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_GVI_NUM_CAPTURE_SURFACES
#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_GVI_NUM_CAPTURE_SURFACES
@@ -3350,6 +3406,24 @@
#define NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU 9 /* R-DG */
+
+/*
+ * NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU - Returns the coolers that
+ * are cooling the given GPU.
+ *
+ * The format of the returned data is:
+ *
+ * 4 CARD32 number of COOLER
+ * 4 * n CARD32 COOLER indices
+ *
+ * This attribute can only be queried through XNVCTRLQueryTargetBinaryData()
+ * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be
+ * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN
+ */
+
+#define NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU 10 /* R-DG */
+
+
/*
* NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN - Returns the list of
* GPUs currently driving the given X screen. If Xinerama is enabled, this
@@ -3599,7 +3673,7 @@
* target types.
* ATTRIBUTE_TYPE_GVI - Attribute is valid for Graphics Video In target
* types.
- *
+ * ATTRIBUTE_TYPE_COOLER - Attribute is valid for Cooler target types.
*
* See 'Key to Integer Attribute "Permissions"' at the top of this
* file for a description of what these permission bits mean.
@@ -3621,6 +3695,7 @@
#define ATTRIBUTE_TYPE_XINERAMA 0x040
#define ATTRIBUTE_TYPE_VCSC 0x080
#define ATTRIBUTE_TYPE_GVI 0x100
+#define ATTRIBUTE_TYPE_COOLER 0x200
typedef struct _NVCTRLAttributeValidValues {
int type;
diff --git a/src/libXNVCtrl/nv_control.h b/src/libXNVCtrl/nv_control.h
index 95c850e..baa0b94 100644
--- a/src/libXNVCtrl/nv_control.h
+++ b/src/libXNVCtrl/nv_control.h
@@ -43,6 +43,7 @@
* BadMatch, if an unknown TargetType is specified
* 1.19 Added TargetType support for SetAttributeAndGetStatus and
* SetStringAttribute requests
+ * 1.20 Added COOLER TargetType.
*/
#ifndef __NVCONTROL_H
@@ -53,7 +54,7 @@
#define NV_CONTROL_NAME "NV-CONTROL"
#define NV_CONTROL_MAJOR 1
-#define NV_CONTROL_MINOR 19
+#define NV_CONTROL_MINOR 20
#define X_nvCtrlQueryExtension 0
#define X_nvCtrlIsNv 1
diff --git a/src/parse.c b/src/parse.c
index 5c32460..c1a5fba 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -157,6 +157,11 @@ AttributeTableEntry attributeTable[] = {
{ "GPUAdaptiveClockState", NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE, N, "Reports if Adaptive Clocking is Enabled on the GPU driving the X screen." },
{ "GPUPerfModes", NV_CTRL_STRING_PERFORMANCE_MODES, S|N, "Returns a string with all the performance modes defined for this GPU along with their associated NV Clock and Memory Clock values." },
{ "GPUPowerMizerMode", NV_CTRL_GPU_POWER_MIZER_MODE, 0, "Allows setting different GPU powermizer modes." },
+ { "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." },
+ { "GPUResetFanSpeed", NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT, N, "Resets the GPU fan's speed to its default." },
+ { "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." },
/* Framelock */
{ "FrameLockAvailable", NV_CTRL_FRAMELOCK, N|F|G, "Returns whether the underlying GPU supports Frame Lock. All of the other frame lock attributes are only applicable if this attribute is enabled (Supported)." },
@@ -363,6 +368,14 @@ TargetTypeEntry targetTypeTable[] = {
NV_FALSE, /* uses_display_devices */
1, 18 }, /* required major,minor protocol rev */
+ { "Fan", /* name */
+ "fan", /* parsed_name */
+ COOLER_TARGET, /* target_index */
+ NV_CTRL_TARGET_TYPE_COOLER, /* nvctrl */
+ ATTRIBUTE_TYPE_COOLER, /* permission_bit */
+ NV_FALSE, /* uses_display_devices */
+ 1, 20 }, /* required major,minor protocol rev */
+
{ NULL, NULL, 0, 0, 0 },
};
diff --git a/src/parse.h b/src/parse.h
index be511ac..2ae9ff6 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -147,7 +147,8 @@ extern AttributeTableEntry attributeTable[];
#define FRAMELOCK_TARGET 2
#define VCS_TARGET 3
#define GVI_TARGET 4
-#define MAX_TARGET_TYPES 5
+#define COOLER_TARGET 5
+#define MAX_TARGET_TYPES 6
diff --git a/src/query-assign.c b/src/query-assign.c
index 8fab5e7..53f98a9 100644
--- a/src/query-assign.c
+++ b/src/query-assign.c
@@ -413,7 +413,11 @@ static int process_attribute_queries(int num, char **queries,
continue;
}
-
+ if (nv_strcasecmp(queries[query], "fans")) {
+ query_all_targets(display_name, COOLER_TARGET);
+ continue;
+ }
+
/* call the parser to parse queries[query] */
ret = nv_parse_attribute_string(queries[query], NV_PARSER_QUERY, &a);
@@ -1221,6 +1225,7 @@ static int print_target_connections(CtrlHandles *h,
get_vcs_name(h->targets[target_index].t[ pData[i] ].h);
break;
+ case COOLER_TARGET:
case FRAMELOCK_TARGET:
case GVI_TARGET:
case X_SCREEN_TARGET:
@@ -1324,8 +1329,15 @@ static int query_all_targets(const char *display_name, const int target_index)
t = &h->targets[target_index].t[i];
str = NULL;
-
- if (target_index == FRAMELOCK_TARGET) {
+
+ if (target_index == COOLER_TARGET) {
+
+ /* for cooler, create the product name */
+
+ product_name = malloc(32);
+ snprintf(product_name, 32, "Fan %d", i);
+
+ } else if (target_index == FRAMELOCK_TARGET) {
/* for framelock, create the product name */
@@ -1390,6 +1402,9 @@ static int query_all_targets(const char *display_name, const int target_index)
print_target_connections
(h, t, NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU,
VCS_TARGET);
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU,
+ COOLER_TARGET);
break;
case X_SCREEN_TARGET:
@@ -1410,6 +1425,12 @@ static int query_all_targets(const char *display_name, const int target_index)
GPU_TARGET);
break;
+ case COOLER_TARGET:
+ print_target_connections
+ (h, t, NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU,
+ COOLER_TARGET);
+ break;
+
default:
break;
}