xserver-multidpi/hw/xfree86/utils/xorgcfg/options.c
2006-07-21 17:56:00 -04:00

788 lines
21 KiB
C

/*
* 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 <pcpa@conectiva.com.br>
*
*/
#include "options.h"
#include "xf86config.h"
#include <X11/Xresource.h>
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/SimpleMenP.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Viewport.h>
#include <ctype.h>
/*
* 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);
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);
XtAddCallback(optList, XtNcallback, SelectModuleOptionCallback, NULL);
desc = XtVaCreateManagedWidget("desc", asciiTextWidgetClass,
form, XtNeditType, XawtextRead,
NULL);
bottom = XtCreateManagedWidget("bottom", formWidgetClass,
pane, NULL, 0);
popdown = XtVaCreateManagedWidget("popdown", commandWidgetClass,
bottom, NULL);
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);
name = XtVaCreateManagedWidget("name", asciiTextWidgetClass, form,
XtNeditType, XawtextEdit,
NULL);
XtVaCreateManagedWidget("label2", labelWidgetClass,
form,
XtNlabel, "\" \"",
NULL);
value = XtVaCreateManagedWidget("value", asciiTextWidgetClass, form,
XtNeditType, XawtextEdit,
NULL);
XtVaCreateManagedWidget("label3", labelWidgetClass, form,
XtNlabel, "\" ",
NULL);
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);
#ifdef USE_MODULES
if (!nomodules)
XtVaSetValues(popdown, XtNfromHoriz, button, NULL);
#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(menuName), "optionM%d", menuN);
menuN = !menuN;
menu = XtCreatePopupShell(menuName, simpleMenuWidgetClass, button,
NULL, 0);
XtVaSetValues(button, XtNmenuName, menuName, NULL);
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);
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);
}