/* * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Conectiva Linux shall * not be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from * Conectiva Linux. * * Author: Paulo César Pereira de Andrade * * $XFree86: xc/programs/Xserver/hw/xfree86/xf86cfg/options.c,v 1.11 2001/10/28 03:34:08 tsi Exp $ */ #include "options.h" #include "xf86config.h" #include #include #include #include #include #include #include #include #include #include #include /* * Prototypes */ static void PopdownCallback(Widget, XtPointer, XtPointer); static void SelectOptionCallback(Widget, XtPointer, XtPointer); static void AddOption(Widget, XtPointer, XtPointer); static void RemoveOption(Widget, XtPointer, XtPointer); static void UpdateOption(Widget, XtPointer, XtPointer); static void UpdateOptionList(void); #ifdef USE_MODULES static void AddDriverOption(Widget, XtPointer, XtPointer); static void SelectModuleCallback(Widget, XtPointer, XtPointer); static void SelectModuleOptionCallback(Widget, XtPointer, XtPointer); static void ModuleOptionsPopdown(Widget, XtPointer, XtPointer); #endif static Bool EnumDatabase(XrmDatabase*, XrmBindingList, XrmQuarkList, XrmRepresentation*, XrmValue*, XPointer); /* * Initialization */ Widget optionsShell; static XF86OptionPtr *options; static Widget add, remov, update, list, name, value; static char *option_str; static int option_index, popped = False; static char *Options = "lib/X11/Options"; XrmDatabase options_xrm; struct { char *string; int offset; } rebuild_xrm; #ifdef USE_MODULES static Widget modList, optList, desc, modOptionsShell, labelType; static char *module_sel; static char *types[] = { "none", "integer", "(non null) string", "string", "real", "boolean", "frequency", }; #endif /* * Implementation */ #ifdef USE_MODULES static int qcmp_str(_Xconst void *a, _Xconst void *b) { return (strcmp(*(char**)a, *(char**)b)); } void ModuleOptionsPopup(Widget w, XtPointer user_data, XtPointer call_data) { xf86cfgModuleOptions *info = module_options; if (modOptionsShell == NULL) { char **ops; int nops; Widget pane, form, viewport, bottom, popdown; modOptionsShell = XtCreatePopupShell("moduleOptions", transientShellWidgetClass, optionsShell, NULL, 0); pane = XtCreateManagedWidget("pane", panedWidgetClass, modOptionsShell, NULL, 0); form = XtCreateManagedWidget("descriptions", formWidgetClass, pane, NULL, 0); labelType = XtCreateManagedWidget("labelType", labelWidgetClass, form, NULL, 0); XtCreateManagedWidget("module", labelWidgetClass, form, NULL, 0); viewport = XtCreateManagedWidget("viewM", viewportWidgetClass, form, NULL, 0); ops = NULL; nops = 0; while (info) { ++nops; ops = (char**)XtRealloc((XtPointer)ops, sizeof(char*) * nops); ops[nops - 1] = XtNewString(info->name); info = info->next; } if (nops == 0) { ops = (char**)XtMalloc(sizeof(char*)); ops[0] = XtNewString(""); nops = 1; } else qsort(ops, nops, sizeof(char*), qcmp_str); modList = XtVaCreateManagedWidget("modL", listWidgetClass, viewport, XtNlist, ops, XtNnumberStrings, nops, NULL, 0); XtAddCallback(modList, XtNcallback, SelectModuleCallback, NULL); XtCreateManagedWidget("option", labelWidgetClass, form, NULL, 0); viewport = XtCreateManagedWidget("viewO", viewportWidgetClass, form, NULL, 0); ops = (char**)XtMalloc(sizeof(char*)); ops[0] = XtNewString(""); optList = XtVaCreateManagedWidget("optL", listWidgetClass, viewport, XtNlist, ops, XtNnumberStrings, 1, NULL, 0); XtAddCallback(optList, XtNcallback, SelectModuleOptionCallback, NULL); desc = XtVaCreateManagedWidget("desc", asciiTextWidgetClass, form, XtNeditType, XawtextRead, NULL, 0); bottom = XtCreateManagedWidget("bottom", formWidgetClass, pane, NULL, 0); popdown = XtVaCreateManagedWidget("popdown", commandWidgetClass, bottom, NULL, 0); XtAddCallback(popdown, XtNcallback, ModuleOptionsPopdown, NULL); XtRealizeWidget(modOptionsShell); XSetWMProtocols(DPY, XtWindow(modOptionsShell), &wm_delete_window, 1); info = module_options; } if (module_sel && *module_sel) { XawListReturnStruct list; /* hack to call ballbacks */ char **strs; int nstrs, idx = 0; XtVaGetValues(modList, XtNlist, &strs, XtNnumberStrings, &nstrs, NULL); for (idx = nstrs - 1; idx > 0; idx--) if (strcmp(module_sel, strs[idx]) == 0) break; while (info) { if (strcmp(module_sel, info->name) == 0) break; info = info->next; } if (info) { list.string = info->name; list.list_index = idx; XawListHighlight(modList, idx); SelectModuleCallback(modList, NULL, (XtPointer)&list); } if (option_str && *option_str) { OptionInfoPtr opts = info->option; idx = 0; while (opts && opts->name) { if (strcmp(opts->name, option_str) == 0) break; ++idx; ++opts; } if (opts && opts->name) { list.string = (char *)opts->name; list.list_index = idx; XawListHighlight(optList, idx); SelectModuleOptionCallback(optList, NULL, (XtPointer)&list); } } } XtPopup(modOptionsShell, XtGrabNone); } /*ARGSUSED*/ static void ModuleOptionsPopdown(Widget w, XtPointer user_data, XtPointer call_data) { XtPopdown(modOptionsShell); } /*ARGSUSED*/ void ModuleOptionsCancelAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { ModuleOptionsPopdown(w, NULL, NULL); } #endif void CreateOptionsShell(void) { optionsShell = XtCreatePopupShell("options", transientShellWidgetClass, toplevel, NULL, 0); } #ifdef USE_MODULES void OptionsPopup(XF86OptionPtr *opts, char *driver, OptionInfoPtr drv_opts) #else void OptionsPopup(XF86OptionPtr *opts) #endif { static int first = 1; #ifdef USE_MODULES static Widget button, menu; static char label[256], menuName[16]; Widget sme; char buf[256]; int i = 0; Arg args[1]; static int menuN; #endif option_str = NULL; options = opts; if (first) { Widget pane, form, viewport, bottom, popdown; first = 0; if (optionsShell == NULL) CreateOptionsShell(); pane = XtCreateManagedWidget("pane", panedWidgetClass, optionsShell, NULL, 0); form = XtCreateManagedWidget("commands", formWidgetClass, pane, NULL, 0); add = XtCreateManagedWidget("add", commandWidgetClass, form, NULL, 0); XtAddCallback(add, XtNcallback, AddOption, NULL); remov = XtCreateManagedWidget("remove", commandWidgetClass, form, NULL, 0); XtAddCallback(remov, XtNcallback, RemoveOption, NULL); update = XtCreateManagedWidget("update", commandWidgetClass, form, NULL, 0); XtAddCallback(update, XtNcallback, UpdateOption, NULL); #ifdef USE_MODULES if (!nomodules) { Widget command; command = XtCreateManagedWidget("help", commandWidgetClass, form, NULL, 0); XtAddCallback(command, XtNcallback, ModuleOptionsPopup, NULL); } #endif form = XtCreateManagedWidget("form", formWidgetClass, pane, NULL, 0); XtVaCreateManagedWidget("label1", labelWidgetClass, form, XtNlabel, " Option \"", NULL, 0); name = XtVaCreateManagedWidget("name", asciiTextWidgetClass, form, XtNeditType, XawtextEdit, NULL, 0); XtVaCreateManagedWidget("label2", labelWidgetClass, form, XtNlabel, "\" \"", NULL, 0); value = XtVaCreateManagedWidget("value", asciiTextWidgetClass, form, XtNeditType, XawtextEdit, NULL, 0); XtVaCreateManagedWidget("label3", labelWidgetClass, form, XtNlabel, "\" ", NULL, 0); viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, form, NULL, 0); list = XtCreateManagedWidget("list", listWidgetClass, viewport, NULL, 0); XtAddCallback(list, XtNcallback, SelectOptionCallback, NULL); bottom = XtCreateManagedWidget("bottom", formWidgetClass, pane, NULL, 0); #ifdef USE_MODULES if (!nomodules) button = XtCreateManagedWidget("driverOpts", menuButtonWidgetClass, bottom, NULL, 0); #endif popdown = XtVaCreateManagedWidget("popdown", commandWidgetClass, bottom, NULL, 0); #ifdef USE_MODULES if (!nomodules) XtVaSetValues(popdown, XtNfromHoriz, button, NULL, 0); #endif XtAddCallback(popdown, XtNcallback, PopdownCallback, NULL); XtRealizeWidget(optionsShell); XSetWMProtocols(DPY, XtWindow(optionsShell), &wm_delete_window, 1); #ifdef USE_MODULES if (!nomodules) { char *str; XtSetArg(args[0], XtNlabel, &str); XtGetValues(button, args, 1); XmuSnprintf(label, sizeof(label), "%s", str); } #endif } #ifdef USE_MODULES if (!nomodules) { if (menu) XtDestroyWidget(menu); XmuSnprintf(menuName, sizeof(buf), "optionM%d", menuN); menuN = !menuN; menu = XtCreatePopupShell(menuName, simpleMenuWidgetClass, button, NULL, 0); XtVaSetValues(button, XtNmenuName, menuName, NULL, 0); if (drv_opts) { int len, longest = 0; char fmt[32]; for (i = 0; drv_opts[i].name != NULL; i++) { len = strlen(drv_opts[i].name); if (len > longest) longest = len; } XmuSnprintf(fmt, sizeof(fmt), "%c-%ds %%s", '%', longest); for (; drv_opts->name != NULL; drv_opts++) { char *type; if (drv_opts->type >= OPTV_NONE && drv_opts->type <= OPTV_FREQ) type = types[drv_opts->type]; else type = "UNKNOWN"; XmuSnprintf(buf, sizeof(buf), fmt, drv_opts->name, type); sme = XtVaCreateManagedWidget(drv_opts->name, smeBSBObjectClass, menu, XtNlabel, buf, NULL, 0); XtAddCallback(sme, XtNcallback, AddDriverOption, (XtPointer)drv_opts); } } if (i) { xf86cfgModuleOptions *mod = module_options; while (mod) { if (strcmp(mod->name, driver) == 0) { /* don't assign to driver, as it may be a temp string */ module_sel = mod->name; break; } mod = mod->next; } XmuSnprintf(buf, sizeof(buf), "%s%s", label, driver); XtSetArg(args[0], XtNlabel, buf); XtSetValues(button, args, 1); XtMapWidget(button); } else XtUnmapWidget(button); } #endif UpdateOptionList(); popped = True; XtPopup(optionsShell, XtGrabExclusive); while (popped) XtAppProcessEvent(XtWidgetToApplicationContext(optionsShell), XtIMAll); } static void UpdateOptionList(void) { Arg args[2]; char **ops, **oldops; int nops, oldnops; XF86OptionPtr opt; ops = NULL; nops = 0; XawListUnhighlight(list); XtSetArg(args[0], XtNlist, &oldops); XtSetArg(args[1], XtNnumberStrings, &oldnops); XtGetValues(list, args, 2); opt = *options; while (opt != NULL) { if (nops % 16 == 0) ops = (char**)XtRealloc((XtPointer)ops, (nops + 16) * sizeof(char*)); ops[nops++] = XtNewString(opt->opt_name); opt = (XF86OptionPtr)(opt->list.next); } if (nops == 0) { ops = (char**)XtMalloc(sizeof(char*)); ops[0] = XtNewString(""); nops = 1; } XtSetArg(args[0], XtNlist, ops); XtSetArg(args[1], XtNnumberStrings, nops); XtSetValues(list, args, 2); if (oldnops > 0 && (oldnops != 1 || XtName(list) != oldops[0])) { while (--oldnops >= 0) XtFree(oldops[oldnops]); XtFree((XtPointer)oldops); } XtSetArg(args[0], XtNstring, ""); XtSetValues(name, args, 1); XtSetValues(value, args, 1); /* force relayout */ XtUnmanageChild(list); XtManageChild(list); XtSetSensitive(remov, False); XtSetSensitive(update, False); } /*ARGSUSED*/ static void PopdownCallback(Widget w, XtPointer user_data, XtPointer call_data) { XtPopdown(optionsShell); popped = False; } /*ARGSUSED*/ void OptionsCancelAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { PopdownCallback(w, NULL, NULL); } /*ARGSUSED*/ static void SelectOptionCallback(Widget w, XtPointer user_data, XtPointer call_data) { Arg args[1]; XF86OptionPtr option; XawListReturnStruct *info = (XawListReturnStruct *)call_data; option_str = info->string; option_index = info->list_index; if ((option = xf86findOption(*options, info->string)) != NULL) { XtSetArg(args[0], XtNstring, option->opt_name); XtSetValues(name, args, 1); XtSetArg(args[0], XtNstring, option->opt_val != NULL ? option->opt_val : ""); XtSetValues(value, args, 1); } XtSetSensitive(remov, True); XtSetSensitive(update, True); } /*ARGSUSED*/ static void AddOption(Widget w, XtPointer user_data, XtPointer call_data) { Arg args[1]; char *nam, *val; XtSetArg(args[0], XtNstring, &nam); XtGetValues(name, args, 1); XtSetArg(args[0], XtNstring, &val); XtGetValues(value, args, 1); if (xf86findOption(*options, nam) != NULL || strlen(nam) == 0) /* XXX xf86addNewOption will trash the option linked list if * the options being added already exists. */ return; *options = xf86addNewOption(*options, XtNewString(nam), val && strlen(val) ? XtNewString(val) : NULL); UpdateOptionList(); } #ifdef USE_MODULES /*ARGSUSED*/ static void AddDriverOption(Widget w, XtPointer user_data, XtPointer call_data) { Arg args[1]; OptionInfoPtr opt = (OptionInfoPtr)user_data; XF86OptionPtr option; option_str = (char *)opt->name; XtSetArg(args[0], XtNstring, opt->name); XtSetValues(name, args, 1); if ((option = xf86findOption(*options, opt->name)) == NULL) XtSetArg(args[0], XtNstring, ""); else XtSetArg(args[0], XtNstring, option->opt_val); XtSetValues(value, args, 1); } /*ARGSUSED*/ static void SelectModuleCallback(Widget w, XtPointer user_data, XtPointer call_data) { xf86cfgModuleOptions *mod = module_options; XawListReturnStruct *info = (XawListReturnStruct *)call_data; while (mod) { if (strcmp(mod->name, info->string) == 0) break; mod = mod->next; } if (mod) { Arg args[2]; char **list = NULL, **old; OptionInfoPtr opts = mod->option; int num = 0, oldnum; module_sel = mod->name; XtSetArg(args[0], XtNlist, &old); XtSetArg(args[1], XtNnumberStrings, &oldnum); XtGetValues(optList, args, 2); while (opts && opts->name) { ++num; list = (char**)XtRealloc((XtPointer)list, sizeof(char*) * num); list[num - 1] = XtNewString(opts->name); ++opts; } if (num == 0) { list = (char**)XtMalloc(sizeof(char*)); list[0] = XtNewString(""); num = 1; } XtSetArg(args[0], XtNlist, list); XtSetArg(args[1], XtNnumberStrings, num); XtSetValues(optList, args, 2); while (--oldnum >= 0) XtFree(old[oldnum]); XtFree((XtPointer)old); XtVaSetValues(desc, XtNstring, "", NULL); XawListUnhighlight(optList); /* force relayout */ XtUnmanageChild(optList); XtManageChild(optList); } } static void SelectModuleOptionCallback(Widget w, XtPointer user_data, XtPointer call_data) { xf86cfgModuleOptions *mod = module_options; XawListReturnStruct *info = (XawListReturnStruct *)call_data; char *description = NULL, *type = "undefined"; char label[256]; if (module_sel && info->string) description = GetOptionDescription(module_sel, info->string); if (description == NULL) description = "** NO DESCRIPTION AVAILABLE **"; XtVaSetValues(desc, XtNstring, description, NULL); while (mod) { if (strcmp(module_sel, mod->name) == 0) break; mod = mod->next; } if (mod) { OptionInfoPtr opts = mod->option; while (opts && opts->name) { if (strcasecmp(opts->name, info->string) == 0) break; ++opts; } if (opts && opts->name && opts->type >= OPTV_NONE && opts->type <= OPTV_FREQ) type = types[opts->type]; } XmuSnprintf(label, sizeof(label), "%s.%s (%s)", module_sel, info->string, type); XtVaSetValues(labelType, XtNlabel, label, NULL); } #endif /*ARGSUSED*/ static void RemoveOption(Widget w, XtPointer user_data, XtPointer call_data) { Arg args[1]; char *str; XtSetArg(args[0], XtNstring, &str); XtGetValues(name, args, 1); xf86removeOption(options, str); UpdateOptionList(); } /*ARGSUSED*/ static void UpdateOption(Widget w, XtPointer user_data, XtPointer call_data) { /* xf86removeOption(options, option_str); AddOption(w, user_data, call_data); UpdateOptionList();*/ Arg args[1]; char *nam, *val; XF86OptionPtr option; XtSetArg(args[0], XtNstring, &nam); XtGetValues(name, args, 1); XtSetArg(args[0], XtNstring, &val); XtGetValues(value, args, 1); if ((option = xf86findOption(*options, option_str)) == NULL) return; XtFree(option->opt_name); option->opt_name = option_str = XtNewString(nam); XtFree(option->opt_val); if (val && strlen(val)) option->opt_val = XtNewString(val); else option->opt_val = NULL; UpdateOptionList(); XawListHighlight(list, option_index); XtSetArg(args[0], XtNstring, option->opt_name); XtSetValues(name, args, 1); XtSetArg(args[0], XtNstring, option->opt_val); XtSetValues(value, args, 1); XtSetSensitive(remov, True); XtSetSensitive(update, True); } /*ARGUSED*/ static Bool EnumDatabase(XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, XrmRepresentation *type, XrmValue *value, XPointer closure) { char *module = XrmQuarkToString(quarks[0]), *option = XrmQuarkToString(quarks[1]); /* handle *.Option: value */ if (module && option == NULL) { option = module; module = "*"; } /* * NOTE: If the Options file is changed to support any other format than * * Module.Option: description text * * this code will also need to be updated. */ if (module) { XrmValue xrm; char *type, *value, query[256]; XmuSnprintf(query, sizeof(query), "%s.%s", module, option); if (XrmGetResource(options_xrm, query, "Module.Option", &type, &xrm)) value = (char*)xrm.addr; else value = NULL; if (value) { char *norm; unsigned char *ptr; int position; int length = strlen(module) + strlen(option) + strlen(value) + 4; rebuild_xrm.string = XtRealloc(rebuild_xrm.string, rebuild_xrm.offset + length); position = rebuild_xrm.offset + sprintf(rebuild_xrm.string + rebuild_xrm.offset, "%s.%s:", module, option); /* removes underlines and spaces */ norm = strchr(rebuild_xrm.string + rebuild_xrm.offset, '.') + 1; for (; *norm; norm++) { if (*norm == '_' || *norm == ' ' || *norm == '\t') { memmove(norm, norm + 1, strlen(norm) + 1); --position; --length; } } for (ptr = (unsigned char*)rebuild_xrm.string + rebuild_xrm.offset; *ptr; ptr++) *ptr = tolower(*ptr); sprintf(rebuild_xrm.string + position, "%s\n", value); rebuild_xrm.offset += length - 1; } } return (False); } Bool InitializeOptionsDatabase(void) { static int first = 1; static Bool result = True; if (first) { XrmQuark names[2]; XrmQuark classes[2]; first = 0; XrmInitialize(); if ((options_xrm = XrmGetFileDatabase(Options)) == (XrmDatabase)0) { fprintf(stderr, "Cannot open '%s' database.\n", Options); return (False); } /* rebuild database, using only lowercase characters */ names[0] = classes[0] = names[1] = classes[1] = NULLQUARK; (void)XrmEnumerateDatabase(options_xrm, (XrmNameList)&names, (XrmClassList)&classes, XrmEnumAllLevels, EnumDatabase, NULL); /* free previous database, as it is not guaranteed to be * "case insensitive" */ XrmDestroyDatabase(options_xrm); /* create case insensitive database by making everything lowercase */ if (rebuild_xrm.string == NULL || (options_xrm = XrmGetStringDatabase(rebuild_xrm.string)) == (XrmDatabase)0) { fprintf(stderr, "Cannot rebuild '%s' database.\n", Options); XtFree(rebuild_xrm.string); return (False); } XtFree(rebuild_xrm.string); } return (result); } char * GetOptionDescription(char *module, char *option) { char *type; XrmValue value; char query[256]; unsigned char *ptr; InitializeOptionsDatabase(); XmuSnprintf(query, sizeof(query), "%s.%s", module, option); ptr = (unsigned char*)strchr(query, '.') + 1; for (; *ptr; ptr++) { if (*ptr == '_' || *ptr == ' ' || *ptr == '\t') memmove(ptr, ptr + 1, strlen((char*)ptr) + 1); } for (ptr = (unsigned char*)query; *ptr; ptr++) *ptr = tolower(*ptr); if (XrmGetResource(options_xrm, query, "Module.Option", &type, &value)) return ((char*)value.addr); return (NULL); }