summaryrefslogtreecommitdiff
path: root/src/nvidia-settings.c
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2014-11-13 08:51:31 -0800
committerAaron Plattner <aplattner@nvidia.com>2014-11-13 08:51:31 -0800
commit0b72534304615d6171d3111b2e9b1999a5c1b2df (patch)
tree27c92abb8a2ae1c3c1d711eeeed4234a0053a889 /src/nvidia-settings.c
parent6101dbee74c1a2997e8ca0f24ea59dd38ab79b46 (diff)
346.16346.16
Diffstat (limited to 'src/nvidia-settings.c')
-rw-r--r--src/nvidia-settings.c306
1 files changed, 265 insertions, 41 deletions
diff --git a/src/nvidia-settings.c b/src/nvidia-settings.c
index 5f2438b..417fc36 100644
--- a/src/nvidia-settings.c
+++ b/src/nvidia-settings.c
@@ -23,48 +23,269 @@
#include "config-file.h"
#include "query-assign.h"
#include "msg.h"
+#include "version.h"
-#include "ctkui.h"
-
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <string.h>
#include <stdlib.h>
+static const char* library_names[] = {
+ "libnvidia-gtk3.so." NVIDIA_VERSION,
+ "libnvidia-gtk3.so",
+ "libnvidia-gtk2.so." NVIDIA_VERSION,
+ "libnvidia-gtk2.so",
+};
+
+typedef struct {
+ void *gui_lib_handle;
+ char *error_msg;
+
+ int (*fn_ctk_init_check)(int *, char **[]);
+ char *(*fn_ctk_get_display)(void);
+ void (*fn_ctk_main)(ParsedAttribute *, ConfigProperties *,
+ CtrlSystem *, const char *);
+} GtkLibraryData;
+
+
+/*
+ * get_full_library_name() - build the library name to use by selecting the
+ * library name based on the index along with a possible path prefix.
+ */
+
+static char *get_full_library_name(const char *prefix, int index)
+{
+ int length = strlen(prefix);
+ return nvstrcat(prefix,
+ (length > 0 && prefix[length-1] != '/') ? "/" : "",
+ library_names[index],
+ NULL);
+}
+
+
+/*
+ * check_and_save_dlerror() - If an error occurs related to our dynamic loading,
+ * save the error message. Since we can check for more than one library and will
+ * fallback to another library name if the first is not found, we don't want to
+ * print an error message unless we abort execution because of it.
+ */
+
+static int check_and_save_dlerror(char **error_msg)
+{
+ const char *e;
+ char *new_error_msg;
+
+ e = dlerror();
+ if (e) {
+ if (*error_msg) {
+ new_error_msg = nvstrcat(*error_msg, "\n", e, NULL);
+ free(*error_msg);
+ *error_msg = new_error_msg;
+ } else {
+ *error_msg = nvstrdup(e);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * load_and_resolve_libdata() - Load the given shared object name and check that
+ * it loads and all function pointers are resolved. If any error is detected,
+ * close the object handle and save the resulting error messages.
+ */
+
+static void load_and_resolve_libdata(const char *gui_lib_name,
+ GtkLibraryData *libdata)
+{
+ int symbol_error = 0;
+
+ libdata->gui_lib_handle = dlopen(gui_lib_name, RTLD_NOW);
+
+ if (libdata->gui_lib_handle) {
+ dlerror(); // clear error msg
+
+ libdata->fn_ctk_init_check = dlsym(libdata->gui_lib_handle,
+ "ctk_init_check");
+ symbol_error += check_and_save_dlerror(&libdata->error_msg);
+
+ libdata->fn_ctk_get_display = dlsym(libdata->gui_lib_handle,
+ "ctk_get_display");
+ symbol_error += check_and_save_dlerror(&libdata->error_msg);
+
+ libdata->fn_ctk_main = dlsym(libdata->gui_lib_handle, "ctk_main");
+ symbol_error += check_and_save_dlerror(&libdata->error_msg);
+
+ if (symbol_error > 0 ||
+ libdata->fn_ctk_init_check == NULL ||
+ libdata->fn_ctk_get_display == NULL ||
+ libdata->fn_ctk_main == NULL) {
+
+ dlclose(libdata->gui_lib_handle);
+ libdata->gui_lib_handle = NULL;
+ }
+ } else {
+ check_and_save_dlerror(&libdata->error_msg);
+ }
+}
+
+
+/*
+ * remove_flag_from_command_line() - Remove the "--" option and reindexes argv
+ * and reindex the command line options so that gtk_init_check() can process its
+ * options. If that flag is not found, no change to argv or argc is made.
+ */
+
+static void remove_flag_from_command_line(int *argc, char ***argv)
+{
+ int i, j;
+
+ for (i=0, j=0; i<(*argc); i++) {
+ if (i > j) {
+ (*argv)[j] = (*argv)[i];
+ j++;
+ } else if (strcmp("--", (*argv)[i]) != 0) {
+ j++;
+ }
+ }
+
+ (*argc) = j;
+ (*argv)[(*argc)] = NULL;
+}
+
+
+/*
+ * load_ui_library() - Decide whether we need to build a library name or use one
+ * already specified. If we build the name, iterate over our possible name
+ * options and either open the library or return a NULL pointer on failure.
+ */
+
+static void *load_ui_library(GtkLibraryData *libdata, Options *op)
+{
+ struct stat buf;
+ char *gui_lib_name;
+ int index = 0;
+ int max_index = ARRAY_LEN(library_names);
+
+ /*
+ * If the user did not specify a path or the path specified is a directory,
+ * we must attempt to open our default library names.
+ */
+
+ if (op->gtk_lib_path != NULL &&
+ (stat(op->gtk_lib_path, &buf) == 0 && !S_ISDIR(buf.st_mode))) {
+
+ /* user specified a non-directory file, try to dlopen it and return */
+
+ gui_lib_name = op->gtk_lib_path;
+
+ load_and_resolve_libdata(gui_lib_name, libdata);
+
+ } else {
+
+ while (!libdata->gui_lib_handle && index < max_index) {
+
+ /*
+ * If we fail to open the default library, work down the list of
+ * known library names and versions.
+ */
+
+ gui_lib_name =
+ get_full_library_name(op->gtk_lib_path ?
+ op->gtk_lib_path : "", index);
+
+ index++;
+
+ if (op->use_gtk2 && strstr(gui_lib_name, "gtk2") == NULL) {
+ continue;
+ }
+
+ load_and_resolve_libdata(gui_lib_name, libdata);
+ nvfree(gui_lib_name);
+ }
+ }
+
+ return libdata->gui_lib_handle;
+
+}
+
+
+
+/*
+ * main() - nvidia-settings application start
+ */
int main(int argc, char **argv)
{
ConfigProperties conf;
ParsedAttribute *p;
- CtrlHandles *h;
- CtrlHandlesArray handles_array;
+ CtrlSystem *system;
+ CtrlSystemList systems;
Options *op;
int ret;
- char *dpy = NULL;
int gui = 0;
- handles_array.n = 0;
- handles_array.array = NULL;
+ GtkLibraryData libdata;
+
+ libdata.gui_lib_handle = NULL;
+ libdata.error_msg = NULL;
+
+ systems.n = 0;
+ systems.array = NULL;
nv_set_verbosity(NV_VERBOSITY_DEPRECATED);
+ /* parse the commandline */
+
+ op = parse_command_line(argc, argv, &systems);
+
/*
- * initialize the ui
- *
- * XXX it would be nice if we didn't do this up front, since we
- * may not even use the gui, but we want the toolkit to have a
- * chance to parse the commandline before we do...
- *
- * gui flag used to decide if ctk should be used or not, as
- * the user might just use control the display from a remote console
- * but for some reason cannot initialize the gtk gui. - TY 2005-05-27
+ * Using the default library names, along with a possible path or name
+ * specified by the user, attempt to dlopen the appropriate user interface
+ * shared object.
*/
- if (ctk_init_check(&argc, &argv)) {
- dpy = ctk_get_display();
- gui = 1;
+ load_ui_library(&libdata, op);
+
+ if (libdata.gui_lib_handle) {
+ /*
+ * initialize the ui
+ *
+ * gui flag used to decide if ctk should be used or not, as
+ * the user might just use control the display from a remote console
+ * but for some reason cannot initialize the gtk gui. - TY 2005-05-27
+ *
+ * All options intented for gtk must come after the "--" option flag.
+ * Since gtk will also stop parsing options when encountering this
+ * flag, we must remove it from argv before calling ctk_init_check.
+ */
+
+ remove_flag_from_command_line(&argc, &argv);
+
+ if (libdata.fn_ctk_init_check(&argc, &argv)) {
+ if (!op->ctrl_display) {
+ op->ctrl_display = libdata.fn_ctk_get_display();
+ }
+ gui = 1;
+ }
+ }
+
+ /*
+ * Quit here if the dynamic load above fails.
+ */
+
+ if (!libdata.gui_lib_handle) {
+ nv_error_msg("%s", libdata.error_msg);
+ nv_error_msg("A problem occured when loading the GUI library. Please "
+ "check your installation and library path. You may need "
+ "to specify this library when calling nvidia-settings. "
+ "Please run `%s --help` for usage information.\n",
+ argv[0]);
+ return 1;
}
-
- /* parse the commandline */
-
- op = parse_command_line(argc, argv, dpy, &handles_array);
/* quit here if we don't have a ctrl_display - TY 2005-05-27 */
@@ -76,13 +297,13 @@ int main(int argc, char **argv)
/* Allocate handle for ctrl_display */
- nv_alloc_ctrl_handles_and_add_to_array(op->ctrl_display, &handles_array);
+ NvCtrlConnectToSystem(op->ctrl_display, &systems);
/* process any query or assignment commandline options */
if (op->num_assignments || op->num_queries) {
- ret = nv_process_assignments_and_queries(op, &handles_array);
- nv_free_ctrl_handles_array(&handles_array);
+ ret = nv_process_assignments_and_queries(op, &systems);
+ NvCtrlFreeAllSystems(&systems);
return ret ? 0 : 1;
}
@@ -101,10 +322,12 @@ int main(int argc, char **argv)
if (op->rewrite) {
nv_parsed_attribute_clean(p);
- h = nv_get_ctrl_handles(op->ctrl_display, &handles_array);
- if(!h || !h->dpy) return 1;
- ret = nv_write_config_file(op->config, h, p, &conf);
- nv_free_ctrl_handles_array(&handles_array);
+ system = NvCtrlGetSystem(op->ctrl_display, &systems);
+ if (!system || !system->dpy) {
+ return 1;
+ }
+ ret = nv_write_config_file(op->config, system, p, &conf);
+ NvCtrlFreeAllSystems(&systems);
nv_parsed_attribute_free(p);
free(op);
op = NULL;
@@ -114,8 +337,8 @@ int main(int argc, char **argv)
/* upload the data from the config file */
if (!op->no_load) {
- ret = nv_read_config_file(op, op->config, op->ctrl_display,
- p, &conf, &handles_array);
+ ret = nv_read_config_file(op, op->config, op->ctrl_display,
+ p, &conf, &systems);
} else {
ret = 1;
}
@@ -140,29 +363,30 @@ int main(int argc, char **argv)
return 1;
}
- /* Get the CtrlHandles for this X screen */
+ /* Get the CtrlSystem for this X screen */
- h = nv_get_ctrl_handles(op->ctrl_display, &handles_array);
-
- if (!h || !h->dpy) {
+ system = NvCtrlGetSystem(op->ctrl_display, &systems);
+
+ if (!system || !system->dpy) {
return 1;
}
/* pass control to the gui */
- ctk_main(p, &conf, h, op->page);
-
+ libdata.fn_ctk_main(p, &conf, system, op->page);
+
/* write the configuration file */
if (op->write_config) {
- nv_write_config_file(op->config, h, p, &conf);
+ nv_write_config_file(op->config, system, p, &conf);
}
/* cleanup */
- nv_free_ctrl_handles_array(&handles_array);
+ NvCtrlFreeAllSystems(&systems);
nv_parsed_attribute_free(p);
+ dlclose(libdata.gui_lib_handle);
return 0;
-
+
} /* main() */