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. */
39 #ifdef HAVE_DMX_CONFIG_H
40 #include <dmx-config.h>
45 #include "dmxconfig.h"
52 extern int yyparse(void);
55 static char *dmxXkbRules
;
56 static char *dmxXkbModel
;
57 static char *dmxXkbLayout
;
58 static char *dmxXkbVariant
;
59 static char *dmxXkbOptions
;
61 /** Stores lists of configuration information. */
62 typedef struct DMXConfigListStruct
{
64 struct DMXConfigListStruct
*next
;
65 } DMXConfigList
, *DMXConfigListPtr
;
67 /** This stucture stores the parsed configuration information. */
68 typedef struct DMXConfigCmdStruct
{
71 DMXConfigList
*displays
;
72 DMXConfigList
*inputs
;
73 DMXConfigList
*xinputs
;
74 } DMXConfigCmd
, *DMXConfigCmdPtr
;
76 DMXConfigEntryPtr dmxConfigEntry
;
77 static DMXConfigCmd dmxConfigCmd
;
79 static int dmxDisplaysFromCommandLine
;
81 /** Make a note that \a display is the name of an X11 display that
82 * should be initialized as a backend (output) display. Called from
83 * #ddxProcessArgument. */
84 void dmxConfigStoreDisplay(const char *display
)
86 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
87 entry
->name
= strdup(display
);
89 if (!dmxConfigCmd
.displays
) dmxConfigCmd
.displays
= entry
;
92 for (pt
= dmxConfigCmd
.displays
; pt
->next
; pt
= pt
->next
);
94 dmxLog(dmxFatal
, "dmxConfigStoreDisplay: end of list non-NULL\n");
97 ++dmxDisplaysFromCommandLine
;
100 /** Make a note that \a input is the name of an X11 display that should
101 * be used for input (either a backend or a console input device). */
102 void dmxConfigStoreInput(const char *input
)
104 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
105 entry
->name
= strdup(input
);
107 if (!dmxConfigCmd
.inputs
) dmxConfigCmd
.inputs
= entry
;
110 for (pt
= dmxConfigCmd
.inputs
; pt
->next
; pt
= pt
->next
);
112 dmxLog(dmxFatal
, "dmxConfigStoreInput: end of list non-NULL\n");
117 /** Make a note that \a input is the name of an X11 display that should
118 * be used for input from XInput extension devices. */
119 void dmxConfigStoreXInput(const char *input
)
121 DMXConfigListPtr entry
= malloc(sizeof(*entry
));
122 entry
->name
= strdup(input
);
124 if (!dmxConfigCmd
.xinputs
) dmxConfigCmd
.xinputs
= entry
;
127 for (pt
= dmxConfigCmd
.xinputs
; pt
->next
; pt
= pt
->next
);
129 dmxLog(dmxFatal
, "dmxConfigStoreXInput: end of list non-NULL\n");
134 /** Make a note that \a file is the configuration file. */
135 void dmxConfigStoreFile(const char *file
)
137 if (dmxConfigCmd
.filename
)
138 dmxLog(dmxFatal
, "Only one -configfile allowed\n");
139 dmxConfigCmd
.filename
= strdup(file
);
142 /** Make a note that \a config should be used as the configuration for
143 * current instantiation of the DMX server. */
144 void dmxConfigStoreConfig(const char *config
)
146 if (dmxConfigCmd
.config
) dmxLog(dmxFatal
, "Only one -config allowed\n");
147 dmxConfigCmd
.config
= strdup(config
);
150 static int dmxConfigReadFile(const char *filename
, int debug
)
154 if (!(str
= fopen(filename
, "r"))) return -1;
155 dmxLog(dmxInfo
, "Reading configuration file \"%s\"\n", filename
);
163 static const char *dmxConfigMatch(const char *target
, DMXConfigEntryPtr entry
)
165 DMXConfigVirtualPtr v
= entry
->virtual;
166 const char *name
= NULL
;
168 if (v
&& v
->name
) name
= v
->name
;
170 if (v
&& !dmxConfigCmd
.config
) return v
->name
? v
->name
: "<noname>";
171 if (!name
) return NULL
;
172 if (!strcmp(name
, target
)) return name
;
176 static DMXScreenInfo
*dmxConfigAddDisplay(const char *name
,
177 int scrnWidth
, int scrnHeight
,
178 int scrnX
, int scrnY
,
179 int scrnXSign
, int scrnYSign
,
180 int rootWidth
, int rootHeight
,
181 int rootX
, int rootY
,
182 int rootXSign
, int rootYSign
)
184 DMXScreenInfo
*dmxScreen
;
186 if (!(dmxScreens
= realloc(dmxScreens
,
187 (dmxNumScreens
+1) * sizeof(*dmxScreens
))))
189 "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
190 dmxNumScreens
, name
);
192 dmxScreen
= &dmxScreens
[dmxNumScreens
];
193 memset(dmxScreen
, 0, sizeof(*dmxScreen
));
194 dmxScreen
->name
= name
;
195 dmxScreen
->index
= dmxNumScreens
;
196 dmxScreen
->scrnWidth
= scrnWidth
;
197 dmxScreen
->scrnHeight
= scrnHeight
;
198 dmxScreen
->scrnX
= scrnX
;
199 dmxScreen
->scrnY
= scrnY
;
200 dmxScreen
->scrnXSign
= scrnXSign
;
201 dmxScreen
->scrnYSign
= scrnYSign
;
202 dmxScreen
->rootWidth
= rootWidth
;
203 dmxScreen
->rootHeight
= rootHeight
;
204 dmxScreen
->rootX
= rootX
;
205 dmxScreen
->rootY
= rootY
;
206 dmxScreen
->stat
= dmxStatAlloc();
211 DMXInputInfo
*dmxConfigAddInput(const char *name
, int core
)
213 DMXInputInfo
*dmxInput
;
215 if (!(dmxInputs
= realloc(dmxInputs
,
216 (dmxNumInputs
+1) * sizeof(*dmxInputs
))))
218 "dmxConfigAddInput: realloc failed for input %d (%s)\n",
221 dmxInput
= &dmxInputs
[dmxNumInputs
];
223 memset(dmxInput
, 0, sizeof(*dmxInput
));
224 dmxInput
->name
= name
;
225 dmxInput
->inputIdx
= dmxNumInputs
;
226 dmxInput
->scrnIdx
= -1;
227 dmxInput
->core
= core
;
232 static void dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d
)
234 DMXScreenInfo
*dmxScreen
;
236 dmxScreen
= dmxConfigAddDisplay(d
->name
,
237 d
->scrnWidth
, d
->scrnHeight
,
239 d
->scrnXSign
, d
->scrnYSign
,
240 d
->rootWidth
, d
->rootHeight
,
242 d
->rootXSign
, d
->rootXSign
);
243 dmxScreen
->where
= PosAbsolute
;
244 dmxScreen
->whereX
= d
->rootXOrigin
;
245 dmxScreen
->whereY
= d
->rootYOrigin
;
248 static void dmxConfigCopyFromWall(DMXConfigWallPtr w
)
250 DMXConfigStringPtr pt
;
251 DMXScreenInfo
*dmxScreen
;
252 int edge
= dmxNumScreens
;
253 int last
= dmxNumScreens
;
255 if (!w
->xwall
&& !w
->ywall
) { /* Try to make it square */
257 for (pt
= w
->nameList
, count
= 0; pt
; pt
= pt
->next
) ++count
;
258 w
->xwall
= sqrt(count
) + .5;
261 for (pt
= w
->nameList
; pt
; pt
= pt
->next
) {
262 dmxScreen
= dmxConfigAddDisplay(pt
->string
, w
->width
, w
->height
,
263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
264 if (pt
== w
->nameList
) { /* Upper left */
265 dmxScreen
->where
= PosAbsolute
;
266 dmxScreen
->whereX
= 0;
267 dmxScreen
->whereY
= 0;
268 } else if (w
->xwall
) { /* Tile left to right, then top to bottom */
269 if (!((dmxNumScreens
-1) % w
->xwall
)) {
270 dmxScreen
->where
= PosBelow
;
271 dmxScreen
->whereRefScreen
= edge
;
272 edge
= dmxNumScreens
-1;
274 dmxScreen
->where
= PosRightOf
;
275 dmxScreen
->whereRefScreen
= last
;
277 } else { /* Tile top to bottom, then left to right */
278 if (!((dmxNumScreens
-1) % w
->ywall
)) {
279 dmxScreen
->where
= PosRightOf
;
280 dmxScreen
->whereRefScreen
= edge
;
281 edge
= dmxNumScreens
-1;
283 dmxScreen
->where
= PosBelow
;
284 dmxScreen
->whereRefScreen
= last
;
288 last
= dmxNumScreens
-1;
289 if (dmxScreen
->where
== PosAbsolute
)
290 dmxLog(dmxInfo
, "Added %s at %d %d\n",
291 pt
->string
, dmxScreen
->whereX
, dmxScreen
->whereY
);
293 dmxLog(dmxInfo
, "Added %s %s %s\n",
295 dmxScreen
->where
== PosBelow
? "below" : "right of",
296 dmxScreens
[dmxScreen
->whereRefScreen
].name
);
300 static void dmxConfigCopyFromOption(DMXConfigOptionPtr o
)
302 DMXConfigStringPtr pt
;
306 if (serverGeneration
!= 1) return; /* FIXME: only do once, for now */
307 if (!o
|| !o
->string
) return;
308 for (pt
= o
->option
; pt
; pt
= pt
->next
) {
311 argv
= realloc(argv
, (argc
+1) * sizeof(*argv
));
312 argv
[argc
] = (char *)pt
->string
;
316 ProcessCommandLine(argc
+1, argv
);
320 static void dmxConfigCopyFromParam(DMXConfigParamPtr p
)
325 if ((argv
= dmxConfigLookupParam(p
, "xkbrules", &argc
)) && argc
== 2) {
326 dmxConfigSetXkbRules(argv
[1]);
327 } else if ((argv
= dmxConfigLookupParam(p
, "xkbmodel", &argc
))
329 dmxConfigSetXkbModel(argv
[1]);
330 } else if ((argv
= dmxConfigLookupParam(p
, "xkblayout", &argc
))
332 dmxConfigSetXkbLayout(argv
[1]);
333 } else if ((argv
= dmxConfigLookupParam(p
, "xkbvariant", &argc
))
335 dmxConfigSetXkbVariant(argv
[1]);
336 } else if ((argv
= dmxConfigLookupParam(p
, "xkboptions", &argc
))
338 dmxConfigSetXkbOptions(argv
[1]);
342 static void dmxConfigCopyData(DMXConfigVirtualPtr v
)
346 if (v
->dim
) dmxSetWidthHeight(v
->dim
->x
, v
->dim
->y
);
347 else dmxSetWidthHeight(0, 0);
348 for (sub
= v
->subentry
; sub
; sub
= sub
->next
) {
350 case dmxConfigDisplay
: dmxConfigCopyFromDisplay(sub
->display
); break;
351 case dmxConfigWall
: dmxConfigCopyFromWall(sub
->wall
); break;
352 case dmxConfigOption
: dmxConfigCopyFromOption(sub
->option
); break;
353 case dmxConfigParam
: dmxConfigCopyFromParam(sub
->param
); break;
356 "dmxConfigCopyData: not a display, wall, or value\n");
361 static void dmxConfigFromCommandLine(void)
365 dmxLog(dmxInfo
, "Using configuration from command line\n");
366 for (pt
= dmxConfigCmd
.displays
; pt
; pt
= pt
->next
) {
367 DMXScreenInfo
*dmxScreen
= dmxConfigAddDisplay(pt
->name
,
370 if (dmxNumScreens
== 1) {
371 dmxScreen
->where
= PosAbsolute
;
372 dmxScreen
->whereX
= 0;
373 dmxScreen
->whereY
= 0;
374 dmxLog(dmxInfo
, "Added %s at %d %d\n",
375 dmxScreen
->name
, dmxScreen
->whereX
, dmxScreen
->whereY
);
377 dmxScreen
->where
= PosRightOf
;
378 dmxScreen
->whereRefScreen
= dmxNumScreens
- 2;
379 if (dmxScreen
->whereRefScreen
< 0) dmxScreen
->whereRefScreen
= 0;
380 dmxLog(dmxInfo
, "Added %s %s %s\n",
382 dmxScreen
->where
== PosBelow
? "below" : "right of",
383 dmxScreens
[dmxScreen
->whereRefScreen
].name
);
388 static void dmxConfigFromConfigFile(void)
390 DMXConfigEntryPtr pt
;
393 for (pt
= dmxConfigEntry
; pt
; pt
= pt
->next
) {
394 /* FIXME -- if an input is specified, use it */
395 if (pt
->type
!= dmxConfigVirtual
) continue;
396 if ((name
= dmxConfigMatch(dmxConfigCmd
.config
, pt
))) {
397 dmxLog(dmxInfo
, "Using configuration \"%s\"\n", name
);
398 dmxConfigCopyData(pt
->virtual);
402 dmxLog(dmxFatal
, "Could not find configuration \"%s\" in \"%s\"\n",
403 dmxConfigCmd
.config
, dmxConfigCmd
.filename
);
406 static void dmxConfigConfigInputs(void)
410 if (dmxNumInputs
) return;
412 if (dmxConfigCmd
.inputs
) { /* Use command line */
413 for (pt
= dmxConfigCmd
.inputs
; pt
; pt
= pt
->next
)
414 dmxConfigAddInput(pt
->name
, TRUE
);
415 } else if (dmxNumScreens
) { /* Use first display */
416 dmxConfigAddInput(dmxScreens
[0].name
, TRUE
);
417 } else { /* Use dummy */
418 dmxConfigAddInput("dummy", TRUE
);
421 if (dmxConfigCmd
.xinputs
) { /* Non-core devices from command line */
422 for (pt
= dmxConfigCmd
.xinputs
; pt
; pt
= pt
->next
)
423 dmxConfigAddInput(pt
->name
, FALSE
);
427 /** Set up the appropriate global variables so that the DMX server will
428 * be initialized using the configuration specified in the config file
429 * and on the command line. */
430 void dmxConfigConfigure(void)
432 if (dmxConfigEntry
) {
433 dmxConfigFreeEntry(dmxConfigEntry
);
434 dmxConfigEntry
= NULL
;
436 if (dmxConfigCmd
.filename
) {
437 if (dmxConfigCmd
.displays
)
439 "Using configuration file \"%s\" instead of command line\n",
440 dmxConfigCmd
.filename
);
441 dmxConfigReadFile(dmxConfigCmd
.filename
, 0);
442 dmxConfigFromConfigFile();
444 if (dmxConfigCmd
.config
)
446 "Configuration name (%s) without configuration file\n",
447 dmxConfigCmd
.config
);
448 dmxConfigFromCommandLine();
450 dmxConfigConfigInputs();
453 /** This function determines the number of displays we WILL have and
454 * sets MAXSCREENS to that value. This is difficult since the number
455 * depends on the command line (which is easy to count) or on the config
456 * file, which has to be parsed. */
457 void dmxConfigSetMaxScreens(void)
459 static int processing
= 0;
461 if (processing
) return; /* Prevent reentry via ProcessCommandLine */
463 if (dmxConfigCmd
.filename
) {
465 dmxConfigConfigure();
467 SetMaxScreens(dmxNumScreens
);
471 SetMaxScreens(dmxDisplaysFromCommandLine
);
476 /** This macro is used to generate the following access methods:
477 * - dmxConfig{Set,Get}rules
478 * - dmxConfig{Set,Get}model
479 * - dmxConfig{Set,Get}layout
480 * - dmxConfig{Set,Get}variant
481 * - dmxConfig{Set,Get}options
482 * These methods are used to read and write information about the keyboard. */
484 #define GEN(param,glob,def) \
485 void dmxConfigSet##glob(const char *param) { \
486 if (dmx##glob) free((void *)dmx##glob); \
487 dmx##glob = strdup(param); \
489 char *dmxConfigGet##glob(void) { \
490 return (char *)(dmx##glob ? dmx##glob : def); \
493 GEN(rules
, XkbRules
, DMX_DEFAULT_XKB_RULES
)
494 GEN(model
, XkbModel
, DMX_DEFAULT_XKB_MODEL
)
495 GEN(layout
, XkbLayout
, DMX_DEFAULT_XKB_LAYOUT
)
496 GEN(variant
, XkbVariant
, DMX_DEFAULT_XKB_VARIANT
)
497 GEN(options
, XkbOptions
, DMX_DEFAULT_XKB_OPTIONS
)