diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2014-11-13 08:51:31 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2014-11-13 08:51:31 -0800 |
commit | 0b72534304615d6171d3111b2e9b1999a5c1b2df (patch) | |
tree | 27c92abb8a2ae1c3c1d711eeeed4234a0053a889 /src/nvidia-settings.c | |
parent | 6101dbee74c1a2997e8ca0f24ea59dd38ab79b46 (diff) |
346.16346.16
Diffstat (limited to 'src/nvidia-settings.c')
-rw-r--r-- | src/nvidia-settings.c | 306 |
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() */ |