summaryrefslogtreecommitdiff
path: root/hw/dmx/config/dmxconfig.c
diff options
context:
space:
mode:
authorKevin E Martin <kem@kem.org>2004-06-30 20:06:56 +0000
committerKevin E Martin <kem@kem.org>2004-06-30 20:06:56 +0000
commit7976ee51afcad41b611e642d2feb31d805dedcf6 (patch)
tree218e5c900399e880dd01458154896d011a2ff238 /hw/dmx/config/dmxconfig.c
parentd5db59bd79f5d8788b99056bf9d969b5b3ad99e1 (diff)
Add Distributed Multihead X (DMX) support
Diffstat (limited to 'hw/dmx/config/dmxconfig.c')
-rw-r--r--hw/dmx/config/dmxconfig.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/hw/dmx/config/dmxconfig.c b/hw/dmx/config/dmxconfig.c
new file mode 100644
index 000000000..f276283a3
--- /dev/null
+++ b/hw/dmx/config/dmxconfig.c
@@ -0,0 +1,495 @@
+/* $XFree86$ */
+/*
+ * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
+ *
+ * All Rights Reserved.
+ *
+ * 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 on 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 (including the
+ * next paragraph) 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * 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.
+ */
+
+/*
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@redhat.com>
+ *
+ */
+
+/** \file
+ * Provides interface for reading DMX configuration files and for
+ * combining that information with command-line configuration parameters. */
+
+
+#include "dmx.h"
+#include "dmxinput.h"
+#include "dmxconfig.h"
+#include "dmxparse.h"
+#include "dmxlog.h"
+#include "dmxcb.h"
+#include "dmxstat.h"
+#include "parser.h"
+
+extern int yyparse(void);
+extern FILE *yyin;
+
+static char *dmxXkbRules;
+static char *dmxXkbModel;
+static char *dmxXkbLayout;
+static char *dmxXkbVariant;
+static char *dmxXkbOptions;
+
+/** Stores lists of configuration information. */
+typedef struct DMXConfigListStruct {
+ const char *name;
+ struct DMXConfigListStruct *next;
+} DMXConfigList, *DMXConfigListPtr;
+
+/** This stucture stores the parsed configuration information. */
+typedef struct DMXConfigCmdStruct {
+ const char *filename;
+ const char *config;
+ DMXConfigList *displays;
+ DMXConfigList *inputs;
+ DMXConfigList *xinputs;
+} DMXConfigCmd, *DMXConfigCmdPtr;
+
+DMXConfigEntryPtr dmxConfigEntry;
+static DMXConfigCmd dmxConfigCmd;
+
+static int dmxDisplaysFromCommandLine;
+
+/** Make a note that \a display is the name of an X11 display that
+ * should be initialized as a backend (output) display. Called from
+ * #ddxProcessArgument. */
+void dmxConfigStoreDisplay(const char *display)
+{
+ DMXConfigListPtr entry = malloc(sizeof(*entry));
+ entry->name = strdup(display);
+ entry->next = NULL;
+ if (!dmxConfigCmd.displays) dmxConfigCmd.displays = entry;
+ else {
+ DMXConfigList *pt;
+ for (pt = dmxConfigCmd.displays; pt->next; pt = pt->next);
+ if (!pt)
+ dmxLog(dmxFatal, "dmxConfigStoreDisplay: end of list non-NULL\n");
+ pt->next = entry;
+ }
+ ++dmxDisplaysFromCommandLine;
+}
+
+/** Make a note that \a input is the name of an X11 display that should
+ * be used for input (either a backend or a console input device). */
+void dmxConfigStoreInput(const char *input)
+{
+ DMXConfigListPtr entry = malloc(sizeof(*entry));
+ entry->name = strdup(input);
+ entry->next = NULL;
+ if (!dmxConfigCmd.inputs) dmxConfigCmd.inputs = entry;
+ else {
+ DMXConfigList *pt;
+ for (pt = dmxConfigCmd.inputs; pt->next; pt = pt->next);
+ if (!pt)
+ dmxLog(dmxFatal, "dmxConfigStoreInput: end of list non-NULL\n");
+ pt->next = entry;
+ }
+}
+
+/** Make a note that \a input is the name of an X11 display that should
+ * be used for input from XInput extension devices. */
+void dmxConfigStoreXInput(const char *input)
+{
+ DMXConfigListPtr entry = malloc(sizeof(*entry));
+ entry->name = strdup(input);
+ entry->next = NULL;
+ if (!dmxConfigCmd.xinputs) dmxConfigCmd.xinputs = entry;
+ else {
+ DMXConfigList *pt;
+ for (pt = dmxConfigCmd.xinputs; pt->next; pt = pt->next);
+ if (!pt)
+ dmxLog(dmxFatal, "dmxConfigStoreXInput: end of list non-NULL\n");
+ pt->next = entry;
+ }
+}
+
+/** Make a note that \a file is the configuration file. */
+void dmxConfigStoreFile(const char *file)
+{
+ if (dmxConfigCmd.filename)
+ dmxLog(dmxFatal, "Only one -configfile allowed\n");
+ dmxConfigCmd.filename = strdup(file);
+}
+
+/** Make a note that \a config should be used as the configuration for
+ * current instantiation of the DMX server. */
+void dmxConfigStoreConfig(const char *config)
+{
+ if (dmxConfigCmd.config) dmxLog(dmxFatal, "Only one -config allowed\n");
+ dmxConfigCmd.config = strdup(config);
+}
+
+static int dmxConfigReadFile(const char *filename, int debug)
+{
+ FILE *str;
+
+ if (!(str = fopen(filename, "r"))) return -1;
+ dmxLog(dmxInfo, "Reading configuration file \"%s\"\n", filename);
+ yyin = str;
+ yydebug = debug;
+ yyparse();
+ fclose(str);
+ return 0;
+}
+
+static const char *dmxConfigMatch(const char *target, DMXConfigEntryPtr entry)
+{
+ DMXConfigVirtualPtr v = entry->virtual;
+ const char *name = NULL;
+
+ if (v && v->name) name = v->name;
+
+ if (v && !dmxConfigCmd.config) return v->name ? v->name : "<noname>";
+ if (!name) return NULL;
+ if (!strcmp(name, target)) return name;
+ return NULL;
+}
+
+static DMXScreenInfo *dmxConfigAddDisplay(const char *name,
+ int scrnWidth, int scrnHeight,
+ int scrnX, int scrnY,
+ int scrnXSign, int scrnYSign,
+ int rootWidth, int rootHeight,
+ int rootX, int rootY,
+ int rootXSign, int rootYSign)
+{
+ DMXScreenInfo *dmxScreen;
+
+ if (!(dmxScreens = realloc(dmxScreens,
+ (dmxNumScreens+1) * sizeof(*dmxScreens))))
+ dmxLog(dmxFatal,
+ "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
+ dmxNumScreens, name);
+
+ dmxScreen = &dmxScreens[dmxNumScreens];
+ memset(dmxScreen, 0, sizeof(*dmxScreen));
+ dmxScreen->name = name;
+ dmxScreen->index = dmxNumScreens;
+ dmxScreen->scrnWidth = scrnWidth;
+ dmxScreen->scrnHeight = scrnHeight;
+ dmxScreen->scrnX = scrnX;
+ dmxScreen->scrnY = scrnY;
+ dmxScreen->scrnXSign = scrnXSign;
+ dmxScreen->scrnYSign = scrnYSign;
+ dmxScreen->rootWidth = rootWidth;
+ dmxScreen->rootHeight = rootHeight;
+ dmxScreen->rootX = rootX;
+ dmxScreen->rootY = rootY;
+ dmxScreen->stat = dmxStatAlloc();
+ ++dmxNumScreens;
+ return dmxScreen;
+}
+
+DMXInputInfo *dmxConfigAddInput(const char *name, int core)
+{
+ DMXInputInfo *dmxInput;
+
+ if (!(dmxInputs = realloc(dmxInputs,
+ (dmxNumInputs+1) * sizeof(*dmxInputs))))
+ dmxLog(dmxFatal,
+ "dmxConfigAddInput: realloc failed for input %d (%s)\n",
+ dmxNumInputs, name);
+
+ dmxInput = &dmxInputs[dmxNumInputs];
+
+ memset(dmxInput, 0, sizeof(*dmxInput));
+ dmxInput->name = name;
+ dmxInput->inputIdx = dmxNumInputs;
+ dmxInput->scrnIdx = -1;
+ dmxInput->core = core;
+ ++dmxNumInputs;
+ return dmxInput;
+}
+
+static void dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d)
+{
+ DMXScreenInfo *dmxScreen;
+
+ dmxScreen = dmxConfigAddDisplay(d->name,
+ d->scrnWidth, d->scrnHeight,
+ d->scrnX, d->scrnY,
+ d->scrnXSign, d->scrnYSign,
+ d->rootWidth, d->rootHeight,
+ d->rootX, d->rootY,
+ d->rootXSign, d->rootXSign);
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = d->rootXOrigin;
+ dmxScreen->whereY = d->rootYOrigin;
+}
+
+static void dmxConfigCopyFromWall(DMXConfigWallPtr w)
+{
+ DMXConfigStringPtr pt;
+ DMXScreenInfo *dmxScreen;
+ int edge = dmxNumScreens;
+ int last = dmxNumScreens;
+
+ if (!w->xwall && !w->ywall) { /* Try to make it square */
+ int count;
+ for (pt = w->nameList, count = 0; pt; pt = pt->next) ++count;
+ w->xwall = sqrt(count) + .5;
+ }
+
+ for (pt = w->nameList; pt; pt = pt->next) {
+ dmxScreen = dmxConfigAddDisplay(pt->string, w->width, w->height,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (pt == w->nameList) { /* Upper left */
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = 0;
+ dmxScreen->whereY = 0;
+ } else if (w->xwall) { /* Tile left to right, then top to bottom */
+ if (!((dmxNumScreens-1) % w->xwall)) {
+ dmxScreen->where = PosBelow;
+ dmxScreen->whereRefScreen = edge;
+ edge = dmxNumScreens-1;
+ } else {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = last;
+ }
+ } else { /* Tile top to bottom, then left to right */
+ if (!((dmxNumScreens-1) % w->ywall)) {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = edge;
+ edge = dmxNumScreens-1;
+ } else {
+ dmxScreen->where = PosBelow;
+ dmxScreen->whereRefScreen = last;
+ }
+
+ }
+ last = dmxNumScreens-1;
+ if (dmxScreen->where == PosAbsolute)
+ dmxLog(dmxInfo, "Added %s at %d %d\n",
+ pt->string, dmxScreen->whereX, dmxScreen->whereY);
+ else
+ dmxLog(dmxInfo, "Added %s %s %s\n",
+ pt->string,
+ dmxScreen->where == PosBelow ? "below" : "right of",
+ dmxScreens[dmxScreen->whereRefScreen].name);
+ }
+}
+
+static void dmxConfigCopyFromOption(DMXConfigOptionPtr o)
+{
+ DMXConfigStringPtr pt;
+ int argc = 0;
+ char **argv = NULL;
+
+ if (serverGeneration != 1) return; /* FIXME: only do once, for now */
+ if (!o || !o->string) return;
+ for (pt = o->option; pt; pt = pt->next) {
+ if (pt->string) {
+ ++argc;
+ argv = realloc(argv, (argc+1) * sizeof(*argv));
+ argv[argc] = (char *)pt->string;
+ }
+ }
+ argv[0] = NULL;
+ ProcessCommandLine(argc+1, argv);
+ free(argv);
+}
+
+static void dmxConfigCopyFromParam(DMXConfigParamPtr p)
+{
+ const char **argv;
+ int argc;
+
+ if ((argv = dmxConfigLookupParam(p, "xkbrules", &argc)) && argc == 2) {
+ dmxConfigSetXkbRules(argv[1]);
+ } else if ((argv = dmxConfigLookupParam(p, "xkbmodel", &argc))
+ && argc == 2) {
+ dmxConfigSetXkbModel(argv[1]);
+ } else if ((argv = dmxConfigLookupParam(p, "xkblayout", &argc))
+ && argc == 2) {
+ dmxConfigSetXkbLayout(argv[1]);
+ } else if ((argv = dmxConfigLookupParam(p, "xkbvariant", &argc))
+ && argc == 2) {
+ dmxConfigSetXkbVariant(argv[1]);
+ } else if ((argv = dmxConfigLookupParam(p, "xkboptions", &argc))
+ && argc == 2) {
+ dmxConfigSetXkbOptions(argv[1]);
+ }
+}
+
+static void dmxConfigCopyData(DMXConfigVirtualPtr v)
+{
+ DMXConfigSubPtr sub;
+
+ if (v->dim) dmxSetWidthHeight(v->dim->x, v->dim->y);
+ else dmxSetWidthHeight(0, 0);
+ for (sub = v->subentry; sub; sub = sub->next) {
+ switch (sub->type) {
+ case dmxConfigDisplay: dmxConfigCopyFromDisplay(sub->display); break;
+ case dmxConfigWall: dmxConfigCopyFromWall(sub->wall); break;
+ case dmxConfigOption: dmxConfigCopyFromOption(sub->option); break;
+ case dmxConfigParam: dmxConfigCopyFromParam(sub->param); break;
+ default:
+ dmxLog(dmxFatal,
+ "dmxConfigCopyData: not a display, wall, or value\n");
+ }
+ }
+}
+
+static void dmxConfigFromCommandLine(void)
+{
+ DMXConfigListPtr pt;
+
+ dmxLog(dmxInfo, "Using configuration from command line\n");
+ for (pt = dmxConfigCmd.displays; pt; pt = pt->next) {
+ DMXScreenInfo *dmxScreen = dmxConfigAddDisplay(pt->name,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0);
+ if (dmxNumScreens == 1) {
+ dmxScreen->where = PosAbsolute;
+ dmxScreen->whereX = 0;
+ dmxScreen->whereY = 0;
+ dmxLog(dmxInfo, "Added %s at %d %d\n",
+ dmxScreen->name, dmxScreen->whereX, dmxScreen->whereY);
+ } else {
+ dmxScreen->where = PosRightOf;
+ dmxScreen->whereRefScreen = dmxNumScreens - 2;
+ if (dmxScreen->whereRefScreen < 0) dmxScreen->whereRefScreen = 0;
+ dmxLog(dmxInfo, "Added %s %s %s\n",
+ dmxScreen->name,
+ dmxScreen->where == PosBelow ? "below" : "right of",
+ dmxScreens[dmxScreen->whereRefScreen].name);
+ }
+ }
+}
+
+static void dmxConfigFromConfigFile(void)
+{
+ DMXConfigEntryPtr pt;
+ const char *name;
+
+ for (pt = dmxConfigEntry; pt; pt = pt->next) {
+ /* FIXME -- if an input is specified, use it */
+ if (pt->type != dmxConfigVirtual) continue;
+ if ((name = dmxConfigMatch(dmxConfigCmd.config, pt))) {
+ dmxLog(dmxInfo, "Using configuration \"%s\"\n", name);
+ dmxConfigCopyData(pt->virtual);
+ return;
+ }
+ }
+ dmxLog(dmxFatal, "Could not find configuration \"%s\" in \"%s\"\n",
+ dmxConfigCmd.config, dmxConfigCmd.filename);
+}
+
+static void dmxConfigConfigInputs(void)
+{
+ DMXConfigListPtr pt;
+
+ if (dmxNumInputs) return;
+
+ if (dmxConfigCmd.inputs) { /* Use command line */
+ for (pt = dmxConfigCmd.inputs; pt; pt = pt->next)
+ dmxConfigAddInput(pt->name, TRUE);
+ } else if (dmxNumScreens) { /* Use first display */
+ dmxConfigAddInput(dmxScreens[0].name, TRUE);
+ } else { /* Use dummy */
+ dmxConfigAddInput("dummy", TRUE);
+ }
+
+ if (dmxConfigCmd.xinputs) { /* Non-core devices from command line */
+ for (pt = dmxConfigCmd.xinputs; pt; pt = pt->next)
+ dmxConfigAddInput(pt->name, FALSE);
+ }
+}
+
+/** Set up the appropriate global variables so that the DMX server will
+ * be initialized using the configuration specified in the config file
+ * and on the command line. */
+void dmxConfigConfigure(void)
+{
+ if (dmxConfigEntry) {
+ dmxConfigFreeEntry(dmxConfigEntry);
+ dmxConfigEntry = NULL;
+ }
+ if (dmxConfigCmd.filename) {
+ if (dmxConfigCmd.displays)
+ dmxLog(dmxWarning,
+ "Using configuration file \"%s\" instead of command line\n",
+ dmxConfigCmd.filename);
+ dmxConfigReadFile(dmxConfigCmd.filename, 0);
+ dmxConfigFromConfigFile();
+ } else {
+ if (dmxConfigCmd.config)
+ dmxLog(dmxWarning,
+ "Configuration name (%s) without configuration file\n",
+ dmxConfigCmd.config);
+ dmxConfigFromCommandLine();
+ }
+ dmxConfigConfigInputs();
+}
+
+/** This function determines the number of displays we WILL have and
+ * sets MAXSCREENS to that value. This is difficult since the number
+ * depends on the command line (which is easy to count) or on the config
+ * file, which has to be parsed. */
+void dmxConfigSetMaxScreens(void)
+{
+ static int processing = 0;
+
+ if (processing) return; /* Prevent reentry via ProcessCommandLine */
+ processing = 1;
+ if (dmxConfigCmd.filename) {
+ if (!dmxNumScreens)
+ dmxConfigConfigure();
+#ifndef MAXSCREENS
+ SetMaxScreens(dmxNumScreens);
+#endif
+ } else
+#ifndef MAXSCREENS
+ SetMaxScreens(dmxDisplaysFromCommandLine);
+#endif
+ processing = 0;
+}
+
+/** This macro is used to generate the following access methods:
+ * - dmxConfig{Set,Get}rules
+ * - dmxConfig{Set,Get}model
+ * - dmxConfig{Set,Get}layout
+ * - dmxConfig{Set,Get}variant
+ * - dmxConfig{Set,Get}options
+ * These methods are used to read and write information about the keyboard. */
+
+#define GEN(param,glob,def) \
+ void dmxConfigSet##glob(const char *param) { \
+ if (dmx##glob) free((void *)dmx##glob); \
+ dmx##glob = strdup(param); \
+ } \
+ char *dmxConfigGet##glob(void) { \
+ return (char *)(dmx##glob ? dmx##glob : def); \
+ }
+
+GEN(rules, XkbRules, DMX_DEFAULT_XKB_RULES)
+GEN(model, XkbModel, DMX_DEFAULT_XKB_MODEL)
+GEN(layout, XkbLayout, DMX_DEFAULT_XKB_LAYOUT)
+GEN(variant, XkbVariant, DMX_DEFAULT_XKB_VARIANT)
+GEN(options, XkbOptions, DMX_DEFAULT_XKB_OPTIONS)
+