Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / config / dmxconfig.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28/*
29 * Authors:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
31 *
32 */
33
34/** \file
35 * Provides interface for reading DMX configuration files and for
36 * combining that information with command-line configuration parameters. */
37
38#ifdef HAVE_DMX_CONFIG_H
39#include <dmx-config.h>
40#endif
41
42#include "dmx.h"
43#include "dmxinput.h"
44#include "dmxconfig.h"
45#include "dmxparse.h"
46#include "dmxlog.h"
47#include "dmxcb.h"
48#include "dmxstat.h"
49#include "parser.h"
50
51extern int yyparse(void);
52extern FILE *yyin;
53
54static char *dmxXkbRules;
55static char *dmxXkbModel;
56static char *dmxXkbLayout;
57static char *dmxXkbVariant;
58static char *dmxXkbOptions;
59
60/** Stores lists of configuration information. */
61typedef struct DMXConfigListStruct {
62 const char *name;
63 struct DMXConfigListStruct *next;
64} DMXConfigList, *DMXConfigListPtr;
65
66/** This stucture stores the parsed configuration information. */
67typedef struct DMXConfigCmdStruct {
68 const char *filename;
69 const char *config;
70 DMXConfigList *displays;
71 DMXConfigList *inputs;
72 DMXConfigList *xinputs;
73} DMXConfigCmd, *DMXConfigCmdPtr;
74
75DMXConfigEntryPtr dmxConfigEntry;
76static DMXConfigCmd dmxConfigCmd;
77
78static int dmxDisplaysFromCommandLine;
79
80/** Make a note that \a display is the name of an X11 display that
81 * should be initialized as a backend (output) display. Called from
82 * #ddxProcessArgument. */
83void
84dmxConfigStoreDisplay(const char *display)
85{
86 DMXConfigListPtr entry = malloc(sizeof(*entry));
87
88 entry->name = strdup(display);
89 entry->next = NULL;
90 if (!dmxConfigCmd.displays)
91 dmxConfigCmd.displays = entry;
92 else {
93 DMXConfigList *pt;
94
95 for (pt = dmxConfigCmd.displays; pt->next; pt = pt->next);
96 if (!pt)
97 dmxLog(dmxFatal, "dmxConfigStoreDisplay: end of list non-NULL\n");
98 pt->next = entry;
99 }
100 ++dmxDisplaysFromCommandLine;
101}
102
103/** Make a note that \a input is the name of an X11 display that should
104 * be used for input (either a backend or a console input device). */
105void
106dmxConfigStoreInput(const char *input)
107{
108 DMXConfigListPtr entry = malloc(sizeof(*entry));
109
110 entry->name = strdup(input);
111 entry->next = NULL;
112 if (!dmxConfigCmd.inputs)
113 dmxConfigCmd.inputs = entry;
114 else {
115 DMXConfigList *pt;
116
117 for (pt = dmxConfigCmd.inputs; pt->next; pt = pt->next);
118 if (!pt)
119 dmxLog(dmxFatal, "dmxConfigStoreInput: end of list non-NULL\n");
120 pt->next = entry;
121 }
122}
123
124/** Make a note that \a input is the name of an X11 display that should
125 * be used for input from XInput extension devices. */
126void
127dmxConfigStoreXInput(const char *input)
128{
129 DMXConfigListPtr entry = malloc(sizeof(*entry));
130
131 entry->name = strdup(input);
132 entry->next = NULL;
133 if (!dmxConfigCmd.xinputs)
134 dmxConfigCmd.xinputs = entry;
135 else {
136 DMXConfigList *pt;
137
138 for (pt = dmxConfigCmd.xinputs; pt->next; pt = pt->next);
139 if (!pt)
140 dmxLog(dmxFatal, "dmxConfigStoreXInput: end of list non-NULL\n");
141 pt->next = entry;
142 }
143}
144
145/** Make a note that \a file is the configuration file. */
146void
147dmxConfigStoreFile(const char *file)
148{
149 if (dmxConfigCmd.filename)
150 dmxLog(dmxFatal, "Only one -configfile allowed\n");
151 dmxConfigCmd.filename = strdup(file);
152}
153
154/** Make a note that \a config should be used as the configuration for
155 * current instantiation of the DMX server. */
156void
157dmxConfigStoreConfig(const char *config)
158{
159 if (dmxConfigCmd.config)
160 dmxLog(dmxFatal, "Only one -config allowed\n");
161 dmxConfigCmd.config = strdup(config);
162}
163
164static int
165dmxConfigReadFile(const char *filename, int debug)
166{
167 FILE *str;
168
169 if (!(str = fopen(filename, "r")))
170 return -1;
171 dmxLog(dmxInfo, "Reading configuration file \"%s\"\n", filename);
172 yyin = str;
173 yydebug = debug;
174 yyparse();
175 fclose(str);
176 return 0;
177}
178
179static const char *
180dmxConfigMatch(const char *target, DMXConfigEntryPtr entry)
181{
182 DMXConfigVirtualPtr v = entry->virtual;
183 const char *name = NULL;
184
185 if (v && v->name)
186 name = v->name;
187
188 if (v && !dmxConfigCmd.config)
189 return v->name ? v->name : "<noname>";
190 if (!name)
191 return NULL;
192 if (!strcmp(name, target))
193 return name;
194 return NULL;
195}
196
197static DMXScreenInfo *
198dmxConfigAddDisplay(const char *name,
199 int scrnWidth, int scrnHeight,
200 int scrnX, int scrnY,
201 int scrnXSign, int scrnYSign,
202 int rootWidth, int rootHeight,
203 int rootX, int rootY, int rootXSign, int rootYSign)
204{
205 DMXScreenInfo *dmxScreen;
206
207 if (!(dmxScreens = realloc(dmxScreens,
208 (dmxNumScreens + 1) * sizeof(*dmxScreens))))
209 dmxLog(dmxFatal,
210 "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
211 dmxNumScreens, name);
212
213 dmxScreen = &dmxScreens[dmxNumScreens];
214 memset(dmxScreen, 0, sizeof(*dmxScreen));
215 dmxScreen->name = name;
216 dmxScreen->index = dmxNumScreens;
217 dmxScreen->scrnWidth = scrnWidth;
218 dmxScreen->scrnHeight = scrnHeight;
219 dmxScreen->scrnX = scrnX;
220 dmxScreen->scrnY = scrnY;
221 dmxScreen->scrnXSign = scrnXSign;
222 dmxScreen->scrnYSign = scrnYSign;
223 dmxScreen->rootWidth = rootWidth;
224 dmxScreen->rootHeight = rootHeight;
225 dmxScreen->rootX = rootX;
226 dmxScreen->rootY = rootY;
227 dmxScreen->stat = dmxStatAlloc();
228 ++dmxNumScreens;
229 return dmxScreen;
230}
231
232DMXInputInfo *
233dmxConfigAddInput(const char *name, int core)
234{
235 DMXInputInfo *dmxInput;
236
237 if (!(dmxInputs = realloc(dmxInputs,
238 (dmxNumInputs + 1) * sizeof(*dmxInputs))))
239 dmxLog(dmxFatal,
240 "dmxConfigAddInput: realloc failed for input %d (%s)\n",
241 dmxNumInputs, name);
242
243 dmxInput = &dmxInputs[dmxNumInputs];
244
245 memset(dmxInput, 0, sizeof(*dmxInput));
246 dmxInput->name = name;
247 dmxInput->inputIdx = dmxNumInputs;
248 dmxInput->scrnIdx = -1;
249 dmxInput->core = core;
250 ++dmxNumInputs;
251 return dmxInput;
252}
253
254static void
255dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d)
256{
257 DMXScreenInfo *dmxScreen;
258
259 dmxScreen = dmxConfigAddDisplay(d->name,
260 d->scrnWidth, d->scrnHeight,
261 d->scrnX, d->scrnY,
262 d->scrnXSign, d->scrnYSign,
263 d->rootWidth, d->rootHeight,
264 d->rootX, d->rootY,
265 d->rootXSign, d->rootXSign);
266 dmxScreen->where = PosAbsolute;
267 dmxScreen->whereX = d->rootXOrigin;
268 dmxScreen->whereY = d->rootYOrigin;
269}
270
271static void
272dmxConfigCopyFromWall(DMXConfigWallPtr w)
273{
274 DMXConfigStringPtr pt;
275 DMXScreenInfo *dmxScreen;
276 int edge = dmxNumScreens;
277 int last = dmxNumScreens;
278
279 if (!w->xwall && !w->ywall) { /* Try to make it square */
280 int count;
281
282 for (pt = w->nameList, count = 0; pt; pt = pt->next)
283 ++count;
284 w->xwall = sqrt(count) + .5;
285 }
286
287 for (pt = w->nameList; pt; pt = pt->next) {
288 dmxScreen = dmxConfigAddDisplay(pt->string, w->width, w->height,
289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
290 if (pt == w->nameList) { /* Upper left */
291 dmxScreen->where = PosAbsolute;
292 dmxScreen->whereX = 0;
293 dmxScreen->whereY = 0;
294 }
295 else if (w->xwall) { /* Tile left to right, then top to bottom */
296 if (!((dmxNumScreens - 1) % w->xwall)) {
297 dmxScreen->where = PosBelow;
298 dmxScreen->whereRefScreen = edge;
299 edge = dmxNumScreens - 1;
300 }
301 else {
302 dmxScreen->where = PosRightOf;
303 dmxScreen->whereRefScreen = last;
304 }
305 }
306 else { /* Tile top to bottom, then left to right */
307 if (!((dmxNumScreens - 1) % w->ywall)) {
308 dmxScreen->where = PosRightOf;
309 dmxScreen->whereRefScreen = edge;
310 edge = dmxNumScreens - 1;
311 }
312 else {
313 dmxScreen->where = PosBelow;
314 dmxScreen->whereRefScreen = last;
315 }
316
317 }
318 last = dmxNumScreens - 1;
319 if (dmxScreen->where == PosAbsolute)
320 dmxLog(dmxInfo, "Added %s at %d %d\n",
321 pt->string, dmxScreen->whereX, dmxScreen->whereY);
322 else
323 dmxLog(dmxInfo, "Added %s %s %s\n",
324 pt->string,
325 dmxScreen->where == PosBelow ? "below" : "right of",
326 dmxScreens[dmxScreen->whereRefScreen].name);
327 }
328}
329
330static void
331dmxConfigCopyFromOption(DMXConfigOptionPtr o)
332{
333 DMXConfigStringPtr pt;
334 int argc = 0;
335 char **argv = NULL;
336
337 if (serverGeneration != 1)
338 return; /* FIXME: only do once, for now */
339 if (!o || !o->string)
340 return;
341 for (pt = o->option; pt; pt = pt->next) {
342 if (pt->string) {
343 ++argc;
344 argv = realloc(argv, (argc + 1) * sizeof(*argv));
345 argv[argc] = (char *) pt->string;
346 }
347 }
348 argv[0] = NULL;
349 ProcessCommandLine(argc + 1, argv);
350 free(argv);
351}
352
353static void
354dmxConfigCopyFromParam(DMXConfigParamPtr p)
355{
356 const char **argv;
357 int argc;
358
359 if ((argv = dmxConfigLookupParam(p, "xkbrules", &argc)) && argc == 2) {
360 dmxConfigSetXkbRules(argv[1]);
361 }
362 else if ((argv = dmxConfigLookupParam(p, "xkbmodel", &argc))
363 && argc == 2) {
364 dmxConfigSetXkbModel(argv[1]);
365 }
366 else if ((argv = dmxConfigLookupParam(p, "xkblayout", &argc))
367 && argc == 2) {
368 dmxConfigSetXkbLayout(argv[1]);
369 }
370 else if ((argv = dmxConfigLookupParam(p, "xkbvariant", &argc))
371 && argc == 2) {
372 dmxConfigSetXkbVariant(argv[1]);
373 }
374 else if ((argv = dmxConfigLookupParam(p, "xkboptions", &argc))
375 && argc == 2) {
376 dmxConfigSetXkbOptions(argv[1]);
377 }
378}
379
380static void
381dmxConfigCopyData(DMXConfigVirtualPtr v)
382{
383 DMXConfigSubPtr sub;
384
385 if (v->dim)
386 dmxSetWidthHeight(v->dim->x, v->dim->y);
387 else
388 dmxSetWidthHeight(0, 0);
389 for (sub = v->subentry; sub; sub = sub->next) {
390 switch (sub->type) {
391 case dmxConfigDisplay:
392 dmxConfigCopyFromDisplay(sub->display);
393 break;
394 case dmxConfigWall:
395 dmxConfigCopyFromWall(sub->wall);
396 break;
397 case dmxConfigOption:
398 dmxConfigCopyFromOption(sub->option);
399 break;
400 case dmxConfigParam:
401 dmxConfigCopyFromParam(sub->param);
402 break;
403 default:
404 dmxLog(dmxFatal,
405 "dmxConfigCopyData: not a display, wall, or value\n");
406 }
407 }
408}
409
410static void
411dmxConfigFromCommandLine(void)
412{
413 DMXConfigListPtr pt;
414
415 dmxLog(dmxInfo, "Using configuration from command line\n");
416 for (pt = dmxConfigCmd.displays; pt; pt = pt->next) {
417 DMXScreenInfo *dmxScreen = dmxConfigAddDisplay(pt->name,
418 0, 0, 0, 0, 0, 0,
419 0, 0, 0, 0, 0, 0);
420
421 if (dmxNumScreens == 1) {
422 dmxScreen->where = PosAbsolute;
423 dmxScreen->whereX = 0;
424 dmxScreen->whereY = 0;
425 dmxLog(dmxInfo, "Added %s at %d %d\n",
426 dmxScreen->name, dmxScreen->whereX, dmxScreen->whereY);
427 }
428 else {
429 dmxScreen->where = PosRightOf;
430 dmxScreen->whereRefScreen = dmxNumScreens - 2;
431 if (dmxScreen->whereRefScreen < 0)
432 dmxScreen->whereRefScreen = 0;
433 dmxLog(dmxInfo, "Added %s %s %s\n",
434 dmxScreen->name,
435 dmxScreen->where == PosBelow ? "below" : "right of",
436 dmxScreens[dmxScreen->whereRefScreen].name);
437 }
438 }
439}
440
441static void
442dmxConfigFromConfigFile(void)
443{
444 DMXConfigEntryPtr pt;
445 const char *name;
446
447 for (pt = dmxConfigEntry; pt; pt = pt->next) {
448 /* FIXME -- if an input is specified, use it */
449 if (pt->type != dmxConfigVirtual)
450 continue;
451 if ((name = dmxConfigMatch(dmxConfigCmd.config, pt))) {
452 dmxLog(dmxInfo, "Using configuration \"%s\"\n", name);
453 dmxConfigCopyData(pt->virtual);
454 return;
455 }
456 }
457 dmxLog(dmxFatal, "Could not find configuration \"%s\" in \"%s\"\n",
458 dmxConfigCmd.config, dmxConfigCmd.filename);
459}
460
461static void
462dmxConfigConfigInputs(void)
463{
464 DMXConfigListPtr pt;
465
466 if (dmxNumInputs)
467 return;
468
469 if (dmxConfigCmd.inputs) { /* Use command line */
470 for (pt = dmxConfigCmd.inputs; pt; pt = pt->next)
471 dmxConfigAddInput(pt->name, TRUE);
472 }
473 else if (dmxNumScreens) { /* Use first display */
474 dmxConfigAddInput(dmxScreens[0].name, TRUE);
475 }
476 else { /* Use dummy */
477 dmxConfigAddInput("dummy", TRUE);
478 }
479
480 if (dmxConfigCmd.xinputs) { /* Non-core devices from command line */
481 for (pt = dmxConfigCmd.xinputs; pt; pt = pt->next)
482 dmxConfigAddInput(pt->name, FALSE);
483 }
484}
485
486/** Set up the appropriate global variables so that the DMX server will
487 * be initialized using the configuration specified in the config file
488 * and on the command line. */
489void
490dmxConfigConfigure(void)
491{
492 if (dmxConfigEntry) {
493 dmxConfigFreeEntry(dmxConfigEntry);
494 dmxConfigEntry = NULL;
495 }
496 if (dmxConfigCmd.filename) {
497 if (dmxConfigCmd.displays)
498 dmxLog(dmxWarning,
499 "Using configuration file \"%s\" instead of command line\n",
500 dmxConfigCmd.filename);
501 dmxConfigReadFile(dmxConfigCmd.filename, 0);
502 dmxConfigFromConfigFile();
503 }
504 else {
505 if (dmxConfigCmd.config)
506 dmxLog(dmxWarning,
507 "Configuration name (%s) without configuration file\n",
508 dmxConfigCmd.config);
509 dmxConfigFromCommandLine();
510 }
511 dmxConfigConfigInputs();
512}
513
514/** This function determines the number of displays we WILL have and
515 * sets MAXSCREENS to that value. This is difficult since the number
516 * depends on the command line (which is easy to count) or on the config
517 * file, which has to be parsed. */
518void
519dmxConfigSetMaxScreens(void)
520{
521 static int processing = 0;
522
523 if (processing)
524 return; /* Prevent reentry via ProcessCommandLine */
525 processing = 1;
526 if (dmxConfigCmd.filename) {
527 if (!dmxNumScreens)
528 dmxConfigConfigure();
529#ifndef MAXSCREENS
530 SetMaxScreens(dmxNumScreens);
531#endif
532 }
533 else
534#ifndef MAXSCREENS
535 SetMaxScreens(dmxDisplaysFromCommandLine);
536#endif
537 processing = 0;
538}
539
540/** This macro is used to generate the following access methods:
541 * - dmxConfig{Set,Get}rules
542 * - dmxConfig{Set,Get}model
543 * - dmxConfig{Set,Get}layout
544 * - dmxConfig{Set,Get}variant
545 * - dmxConfig{Set,Get}options
546 * These methods are used to read and write information about the keyboard. */
547
548#define GEN(param,glob,def) \
549 void dmxConfigSet##glob(const char *param) { \
550 if (dmx##glob) free((void *)dmx##glob); \
551 dmx##glob = strdup(param); \
552 } \
553 char *dmxConfigGet##glob(void) { \
554 return (char *)(dmx##glob ? dmx##glob : def); \
555 }
556
557GEN(rules, XkbRules, XKB_DFLT_RULES)
558 GEN(model, XkbModel, XKB_DFLT_MODEL)
559 GEN(layout, XkbLayout, XKB_DFLT_LAYOUT)
560 GEN(variant, XkbVariant, XKB_DFLT_VARIANT)
561 GEN(options, XkbOptions, XKB_DFLT_OPTIONS)