2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * Rickard E. (Rik) Faith <faith@redhat.com>
35 * Provides interface for reading DMX configuration files and for
36 * combining that information with command-line configuration parameters. */
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
44 #include "dmxconfig.h"
51 extern int yyparse(void);
54 static char *dmxXkbRules
;
55 static char *dmxXkbModel
;
56 static char *dmxXkbLayout
;
57 static char *dmxXkbVariant
;
58 static char *dmxXkbOptions
;
60 /** Stores lists of configuration information. */
61 typedef struct DMXConfigListStruct
{
63 struct DMXConfigListStruct
*next
;
64 } DMXConfigList
, *DMXConfigListPtr
;
66 /** This stucture stores the parsed configuration information. */
67 typedef struct DMXConfigCmdStruct
{
70 DMXConfigList
*displays
;
71 DMXConfigList
*inputs
;
72 DMXConfigList
*xinputs
;
73 } DMXConfigCmd
, *DMXConfigCmdPtr
;
75 DMXConfigEntryPtr dmxConfigEntry
;
76 static DMXConfigCmd dmxConfigCmd
;
78 static int dmxDisplaysFromCommandLine
;
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. */
84 dmxConfigStoreDisplay(const char *display
)
86 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
88 entry
->name
= strdup(display
);
90 if (!dmxConfigCmd
.displays
)
91 dmxConfigCmd
.displays
= entry
;
95 for (pt
= dmxConfigCmd
.displays
; pt
->next
; pt
= pt
->next
);
97 dmxLog(dmxFatal
, "dmxConfigStoreDisplay: end of list non-NULL\n");
100 ++dmxDisplaysFromCommandLine
;
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). */
106 dmxConfigStoreInput(const char *input
)
108 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
110 entry
->name
= strdup(input
);
112 if (!dmxConfigCmd
.inputs
)
113 dmxConfigCmd
.inputs
= entry
;
117 for (pt
= dmxConfigCmd
.inputs
; pt
->next
; pt
= pt
->next
);
119 dmxLog(dmxFatal
, "dmxConfigStoreInput: end of list non-NULL\n");
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. */
127 dmxConfigStoreXInput(const char *input
)
129 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
131 entry
->name
= strdup(input
);
133 if (!dmxConfigCmd
.xinputs
)
134 dmxConfigCmd
.xinputs
= entry
;
138 for (pt
= dmxConfigCmd
.xinputs
; pt
->next
; pt
= pt
->next
);
140 dmxLog(dmxFatal
, "dmxConfigStoreXInput: end of list non-NULL\n");
145 /** Make a note that \a file is the configuration file. */
147 dmxConfigStoreFile(const char *file
)
149 if (dmxConfigCmd
.filename
)
150 dmxLog(dmxFatal
, "Only one -configfile allowed\n");
151 dmxConfigCmd
.filename
= strdup(file
);
154 /** Make a note that \a config should be used as the configuration for
155 * current instantiation of the DMX server. */
157 dmxConfigStoreConfig(const char *config
)
159 if (dmxConfigCmd
.config
)
160 dmxLog(dmxFatal
, "Only one -config allowed\n");
161 dmxConfigCmd
.config
= strdup(config
);
165 dmxConfigReadFile(const char *filename
, int debug
)
169 if (!(str
= fopen(filename
, "r")))
171 dmxLog(dmxInfo
, "Reading configuration file \"%s\"\n", filename
);
180 dmxConfigMatch(const char *target
, DMXConfigEntryPtr entry
)
182 DMXConfigVirtualPtr v
= entry
->virtual;
183 const char *name
= NULL
;
188 if (v
&& !dmxConfigCmd
.config
)
189 return v
->name
? v
->name
: "<noname>";
192 if (!strcmp(name
, target
))
197 static DMXScreenInfo
*
198 dmxConfigAddDisplay(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
)
205 DMXScreenInfo
*dmxScreen
;
207 if (!(dmxScreens
= realloc(dmxScreens
,
208 (dmxNumScreens
+ 1) * sizeof(*dmxScreens
))))
210 "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
211 dmxNumScreens
, name
);
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();
233 dmxConfigAddInput(const char *name
, int core
)
235 DMXInputInfo
*dmxInput
;
237 if (!(dmxInputs
= realloc(dmxInputs
,
238 (dmxNumInputs
+ 1) * sizeof(*dmxInputs
))))
240 "dmxConfigAddInput: realloc failed for input %d (%s)\n",
243 dmxInput
= &dmxInputs
[dmxNumInputs
];
245 memset(dmxInput
, 0, sizeof(*dmxInput
));
246 dmxInput
->name
= name
;
247 dmxInput
->inputIdx
= dmxNumInputs
;
248 dmxInput
->scrnIdx
= -1;
249 dmxInput
->core
= core
;
255 dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d
)
257 DMXScreenInfo
*dmxScreen
;
259 dmxScreen
= dmxConfigAddDisplay(d
->name
,
260 d
->scrnWidth
, d
->scrnHeight
,
262 d
->scrnXSign
, d
->scrnYSign
,
263 d
->rootWidth
, d
->rootHeight
,
265 d
->rootXSign
, d
->rootXSign
);
266 dmxScreen
->where
= PosAbsolute
;
267 dmxScreen
->whereX
= d
->rootXOrigin
;
268 dmxScreen
->whereY
= d
->rootYOrigin
;
272 dmxConfigCopyFromWall(DMXConfigWallPtr w
)
274 DMXConfigStringPtr pt
;
275 DMXScreenInfo
*dmxScreen
;
276 int edge
= dmxNumScreens
;
277 int last
= dmxNumScreens
;
279 if (!w
->xwall
&& !w
->ywall
) { /* Try to make it square */
282 for (pt
= w
->nameList
, count
= 0; pt
; pt
= pt
->next
)
284 w
->xwall
= sqrt(count
) + .5;
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;
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;
302 dmxScreen
->where
= PosRightOf
;
303 dmxScreen
->whereRefScreen
= last
;
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;
313 dmxScreen
->where
= PosBelow
;
314 dmxScreen
->whereRefScreen
= last
;
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
);
323 dmxLog(dmxInfo
, "Added %s %s %s\n",
325 dmxScreen
->where
== PosBelow
? "below" : "right of",
326 dmxScreens
[dmxScreen
->whereRefScreen
].name
);
331 dmxConfigCopyFromOption(DMXConfigOptionPtr o
)
333 DMXConfigStringPtr pt
;
337 if (serverGeneration
!= 1)
338 return; /* FIXME: only do once, for now */
339 if (!o
|| !o
->string
)
341 for (pt
= o
->option
; pt
; pt
= pt
->next
) {
344 argv
= realloc(argv
, (argc
+ 1) * sizeof(*argv
));
345 argv
[argc
] = (char *) pt
->string
;
349 ProcessCommandLine(argc
+ 1, argv
);
354 dmxConfigCopyFromParam(DMXConfigParamPtr p
)
359 if ((argv
= dmxConfigLookupParam(p
, "xkbrules", &argc
)) && argc
== 2) {
360 dmxConfigSetXkbRules(argv
[1]);
362 else if ((argv
= dmxConfigLookupParam(p
, "xkbmodel", &argc
))
364 dmxConfigSetXkbModel(argv
[1]);
366 else if ((argv
= dmxConfigLookupParam(p
, "xkblayout", &argc
))
368 dmxConfigSetXkbLayout(argv
[1]);
370 else if ((argv
= dmxConfigLookupParam(p
, "xkbvariant", &argc
))
372 dmxConfigSetXkbVariant(argv
[1]);
374 else if ((argv
= dmxConfigLookupParam(p
, "xkboptions", &argc
))
376 dmxConfigSetXkbOptions(argv
[1]);
381 dmxConfigCopyData(DMXConfigVirtualPtr v
)
386 dmxSetWidthHeight(v
->dim
->x
, v
->dim
->y
);
388 dmxSetWidthHeight(0, 0);
389 for (sub
= v
->subentry
; sub
; sub
= sub
->next
) {
391 case dmxConfigDisplay
:
392 dmxConfigCopyFromDisplay(sub
->display
);
395 dmxConfigCopyFromWall(sub
->wall
);
397 case dmxConfigOption
:
398 dmxConfigCopyFromOption(sub
->option
);
401 dmxConfigCopyFromParam(sub
->param
);
405 "dmxConfigCopyData: not a display, wall, or value\n");
411 dmxConfigFromCommandLine(void)
415 dmxLog(dmxInfo
, "Using configuration from command line\n");
416 for (pt
= dmxConfigCmd
.displays
; pt
; pt
= pt
->next
) {
417 DMXScreenInfo
*dmxScreen
= dmxConfigAddDisplay(pt
->name
,
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
);
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",
435 dmxScreen
->where
== PosBelow
? "below" : "right of",
436 dmxScreens
[dmxScreen
->whereRefScreen
].name
);
442 dmxConfigFromConfigFile(void)
444 DMXConfigEntryPtr pt
;
447 for (pt
= dmxConfigEntry
; pt
; pt
= pt
->next
) {
448 /* FIXME -- if an input is specified, use it */
449 if (pt
->type
!= dmxConfigVirtual
)
451 if ((name
= dmxConfigMatch(dmxConfigCmd
.config
, pt
))) {
452 dmxLog(dmxInfo
, "Using configuration \"%s\"\n", name
);
453 dmxConfigCopyData(pt
->virtual);
457 dmxLog(dmxFatal
, "Could not find configuration \"%s\" in \"%s\"\n",
458 dmxConfigCmd
.config
, dmxConfigCmd
.filename
);
462 dmxConfigConfigInputs(void)
469 if (dmxConfigCmd
.inputs
) { /* Use command line */
470 for (pt
= dmxConfigCmd
.inputs
; pt
; pt
= pt
->next
)
471 dmxConfigAddInput(pt
->name
, TRUE
);
473 else if (dmxNumScreens
) { /* Use first display */
474 dmxConfigAddInput(dmxScreens
[0].name
, TRUE
);
476 else { /* Use dummy */
477 dmxConfigAddInput("dummy", TRUE
);
480 if (dmxConfigCmd
.xinputs
) { /* Non-core devices from command line */
481 for (pt
= dmxConfigCmd
.xinputs
; pt
; pt
= pt
->next
)
482 dmxConfigAddInput(pt
->name
, FALSE
);
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. */
490 dmxConfigConfigure(void)
492 if (dmxConfigEntry
) {
493 dmxConfigFreeEntry(dmxConfigEntry
);
494 dmxConfigEntry
= NULL
;
496 if (dmxConfigCmd
.filename
) {
497 if (dmxConfigCmd
.displays
)
499 "Using configuration file \"%s\" instead of command line\n",
500 dmxConfigCmd
.filename
);
501 dmxConfigReadFile(dmxConfigCmd
.filename
, 0);
502 dmxConfigFromConfigFile();
505 if (dmxConfigCmd
.config
)
507 "Configuration name (%s) without configuration file\n",
508 dmxConfigCmd
.config
);
509 dmxConfigFromCommandLine();
511 dmxConfigConfigInputs();
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. */
519 dmxConfigSetMaxScreens(void)
521 static int processing
= 0;
524 return; /* Prevent reentry via ProcessCommandLine */
526 if (dmxConfigCmd
.filename
) {
528 dmxConfigConfigure();
530 SetMaxScreens(dmxNumScreens
);
535 SetMaxScreens(dmxDisplaysFromCommandLine
);
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. */
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); \
553 char *dmxConfigGet##glob(void) { \
554 return (char *)(dmx##glob ? dmx##glob : def); \
557 GEN(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
)