parse_be.c revision b18c2d1e
1/*
2 * Parser backend routines.
3 *
4 * Roughly, these are the routines that the lex/yacc output calls to do
5 * its work.
6 *
7 * This is very similar to the meaning of parse_yacc.c; the two may be
8 * merged at some point.
9 */
10
11#include "ctwm.h"
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <strings.h>
17
18#include <X11/Xatom.h>
19
20#include "ctwm_atoms.h"
21#include "screen.h"
22#include "util.h"
23#include "animate.h"
24#include "functions_defs.h"
25#include "image.h"
26#include "list.h"
27#include "occupation.h"
28#include "parse.h"
29#include "parse_be.h"
30#include "parse_yacc.h"
31#include "r_area.h"
32#include "r_area_list.h"
33#include "r_layout.h"
34#ifdef SOUNDS
35#  include "sound.h"
36#endif
37
38#include "gram.tab.h"
39
40
41static int ParseRandomPlacement(const char *s);
42static int ParseButtonStyle(const char *s);
43static int ParseUsePPosition(const char *s);
44static int ParseIconifyStyle(const char *s);
45
46
47
48/**********************************************************************
49 *
50 *  Parsing table and routines
51 *
52 ***********************************************************************/
53
54typedef struct _TwmKeyword {
55	const char *name;
56	int value;
57	int subnum;
58} TwmKeyword;
59
60#define kw0_NoDefaults                  1
61#define kw0_AutoRelativeResize          2
62#define kw0_ForceIcons                  3
63#define kw0_NoIconManagers              4
64#define kw0_InterpolateMenuColors       6
65//#define kw0_NoVersion                 7
66#define kw0_SortIconManager             8
67#define kw0_NoGrabServer                9
68#define kw0_NoMenuShadows               10
69#define kw0_NoRaiseOnMove               11
70#define kw0_NoRaiseOnResize             12
71#define kw0_NoRaiseOnDeiconify          13
72#define kw0_DontMoveOff                 14
73#define kw0_NoBackingStore              15
74#define kw0_NoSaveUnders                16
75#define kw0_RestartPreviousState        17
76#define kw0_ClientBorderWidth           18
77#define kw0_NoTitleFocus                19
78#define kw0_DecorateTransients          21
79#define kw0_ShowIconManager             22
80#define kw0_NoCaseSensitive             23
81#define kw0_NoRaiseOnWarp               24
82#define kw0_WarpUnmapped                25
83#define kw0_ShowWorkspaceManager        27
84#define kw0_StartInMapState             28
85#define kw0_NoShowOccupyAll             29
86#define kw0_AutoOccupy                  30
87#define kw0_TransientHasOccupation      31
88#define kw0_DontPaintRootWindow         32
89#define kw0_Use3DMenus                  33
90#define kw0_Use3DTitles                 34
91#define kw0_Use3DIconManagers           35
92#define kw0_Use3DBorders                36
93#define kw0_SunkFocusWindowTitle        37
94#define kw0_BeNiceToColormap            38
95#define kw0_WarpRingOnScreen            40
96#define kw0_NoIconManagerFocus          41
97#define kw0_StayUpMenus                 42
98#define kw0_ClickToFocus                43
99#define kw0_BorderResizeCursors         44
100#define kw0_ReallyMoveInWorkspaceManager 45
101#define kw0_ShowWinWhenMovingInWmgr     46
102#define kw0_Use3DWMap                   47
103#define kw0_ReverseCurrentWorkspace     48
104#define kw0_DontWarpCursorInWMap        49
105#define kw0_CenterFeedbackWindow        50
106#define kw0_WarpToDefaultMenuEntry      51
107#define kw0_ShrinkIconTitles            52
108#define kw0_AutoRaiseIcons              53
109//#define kw0_use3DIconBorders            54
110#define kw0_UseSunkTitlePixmap          55
111#define kw0_ShortAllWindowsMenus        56
112#define kw0_RaiseWhenAutoUnSqueeze      57
113#define kw0_RaiseOnClick                58
114#define kw0_IgnoreLockModifier          59
115#define kw0_AutoFocusToTransients       60 /* kai */
116#define kw0_PackNewWindows              61
117#define kw0_IgnoreCaseInMenuSelection   62
118#define kw0_SloppyFocus                 63
119#define kw0_NoImagesInWorkSpaceManager  64
120#define kw0_NoWarpToMenuTitle           65
121#define kw0_SaveWorkspaceFocus          66 /* blais */
122#define kw0_RaiseOnWarp                 67
123#define kw0_DontShowWelcomeWindow       68
124#define kw0_AutoPriority                69
125#define kw0_DontToggleWorkspacemanagerState 70
126#define kw0_BackingStore                71
127#define kw0_StartInButtonState          72
128#define kw0_NoSortIconManager           73
129#define kw0_NoRestartPreviousState      74
130#define kw0_NoDecorateTransients        75
131#define kw0_GrabServer                  76
132#define kw0_DontNameDecorations         77
133#define kw0_StrictWinNameEncoding       78
134
135#define kws_UsePPosition                1
136#define kws_IconFont                    2
137#define kws_ResizeFont                  3
138#define kws_MenuFont                    4
139#define kws_TitleFont                   5
140#define kws_IconManagerFont             6
141#define kws_UnknownIcon                 7
142#define kws_IconDirectory               8
143#define kws_MaxWindowSize               9
144#define kws_PixmapDirectory             10
145/* RandomPlacement moved because it's now a string string keyword */
146#define kws_IconJustification           12
147#define kws_TitleJustification          13
148#define kws_IconRegionJustification     14
149#define kws_IconRegionAlignement        15
150#define kws_SoundHost                   16
151#define kws_WMgrButtonStyle             17
152#define kws_WorkSpaceFont               18
153#define kws_IconifyStyle                19
154#define kws_IconSize                    20
155#define kws_RplaySoundHost              21
156
157#define kwss_RandomPlacement            1
158
159#define kwn_ConstrainedMoveTime         1
160#define kwn_MoveDelta                   2
161#define kwn_XorValue                    3
162#define kwn_FramePadding                4
163#define kwn_TitlePadding                5
164#define kwn_ButtonIndent                6
165#define kwn_BorderWidth                 7
166#define kwn_IconBorderWidth             8
167#define kwn_TitleButtonBorderWidth      9
168#define kwn_RaiseDelay                  10
169#define kwn_TransientOnTop              11
170#define kwn_OpaqueMoveThreshold         12
171#define kwn_OpaqueResizeThreshold       13
172#define kwn_WMgrVertButtonIndent        14
173#define kwn_WMgrHorizButtonIndent       15
174#define kwn_ClearShadowContrast         16
175#define kwn_DarkShadowContrast          17
176#define kwn_WMgrButtonShadowDepth       18
177#define kwn_MaxIconTitleWidth           19
178#define kwn_AnimationSpeed              20
179#define kwn_ThreeDBorderWidth           21
180#define kwn_MoveOffResistance           22
181#define kwn_BorderShadowDepth           23
182#define kwn_TitleShadowDepth            24
183#define kwn_TitleButtonShadowDepth      25
184#define kwn_MenuShadowDepth             26
185#define kwn_IconManagerShadowDepth      27
186#define kwn_MovePackResistance          28
187#define kwn_XMoveGrid                   29
188#define kwn_YMoveGrid                   30
189#define kwn_OpenWindowTimeout           31
190#define kwn_RaiseOnClickButton          32
191
192#define kwn_BorderTop                   33
193#define kwn_BorderBottom                34
194#define kwn_BorderLeft                  35
195#define kwn_BorderRight                 36
196
197#define kwcl_BorderColor                1
198#define kwcl_IconManagerHighlight       2
199#define kwcl_BorderTileForeground       3
200#define kwcl_BorderTileBackground       4
201#define kwcl_TitleForeground            5
202#define kwcl_TitleBackground            6
203#define kwcl_IconForeground             7
204#define kwcl_IconBackground             8
205#define kwcl_IconBorderColor            9
206#define kwcl_IconManagerForeground      10
207#define kwcl_IconManagerBackground      11
208#define kwcl_MapWindowBackground        12
209#define kwcl_MapWindowForeground        13
210
211#define kwc_DefaultForeground           1
212#define kwc_DefaultBackground           2
213#define kwc_MenuForeground              3
214#define kwc_MenuBackground              4
215#define kwc_MenuTitleForeground         5
216#define kwc_MenuTitleBackground         6
217#define kwc_MenuShadowColor             7
218
219
220/*
221 * The following is sorted alphabetically according to name (which must be
222 * in lowercase and only contain the letters a-z).  It is fed to a binary
223 * search to parse keywords.
224 */
225static const TwmKeyword keytable[] = {
226	{ "a",                      ALTER, 0 },
227	{ "all",                    ALL, 0 },
228	{ "alter",                  ALTER, 0 },
229	{ "alwaysontop",            ALWAYS_ON_TOP, 0 },
230	{ "alwaysshowwindowwhenmovingfromworkspacemanager", KEYWORD, kw0_ShowWinWhenMovingInWmgr },
231	{ "alwayssqueezetogravity", ALWAYSSQUEEZETOGRAVITY, 0 },
232	{ "animationspeed",         NKEYWORD, kwn_AnimationSpeed },
233	{ "autofocustotransients",  KEYWORD, kw0_AutoFocusToTransients }, /* kai */
234	{ "autolower",              AUTO_LOWER, 0 },
235	{ "autooccupy",             KEYWORD, kw0_AutoOccupy },
236	{ "autopopup",              AUTO_POPUP, 0 },
237	{ "autopriority",           KEYWORD, kw0_AutoPriority },
238	{ "autoraise",              AUTO_RAISE, 0 },
239	{ "autoraiseicons",         KEYWORD, kw0_AutoRaiseIcons },
240	{ "autorelativeresize",     KEYWORD, kw0_AutoRelativeResize },
241	{ "autosqueeze",            AUTOSQUEEZE, 0 },
242	{ "backingstore",           KEYWORD, kw0_BackingStore },
243	{ "benicetocolormap",       KEYWORD, kw0_BeNiceToColormap },
244	{ "borderbottom",           NKEYWORD, kwn_BorderBottom },
245	{ "bordercolor",            CLKEYWORD, kwcl_BorderColor },
246	{ "borderleft",             NKEYWORD, kwn_BorderLeft },
247	{ "borderresizecursors",    KEYWORD, kw0_BorderResizeCursors },
248	{ "borderright",            NKEYWORD, kwn_BorderRight },
249	{ "bordershadowdepth",      NKEYWORD, kwn_BorderShadowDepth },
250	{ "bordertilebackground",   CLKEYWORD, kwcl_BorderTileBackground },
251	{ "bordertileforeground",   CLKEYWORD, kwcl_BorderTileForeground },
252	{ "bordertop",              NKEYWORD, kwn_BorderTop },
253	{ "borderwidth",            NKEYWORD, kwn_BorderWidth },
254	{ "button",                 BUTTON, 0 },
255	{ "buttonindent",           NKEYWORD, kwn_ButtonIndent },
256	{ "c",                      CONTROL, 0 },
257	{ "center",                 SIJENUM, SIJ_CENTER },
258	{ "centerfeedbackwindow",   KEYWORD, kw0_CenterFeedbackWindow },
259	{ "changeworkspacefunction", CHANGE_WORKSPACE_FUNCTION, 0 },
260	{ "clearshadowcontrast",    NKEYWORD, kwn_ClearShadowContrast },
261	{ "clicktofocus",           KEYWORD, kw0_ClickToFocus },
262	{ "clientborderwidth",      KEYWORD, kw0_ClientBorderWidth },
263	{ "color",                  COLOR, 0 },
264	{ "constrainedmovetime",    NKEYWORD, kwn_ConstrainedMoveTime },
265	{ "control",                CONTROL, 0 },
266	{ "cursors",                CURSORS, 0 },
267	{ "darkshadowcontrast",     NKEYWORD, kwn_DarkShadowContrast },
268	{ "decoratetransients",     KEYWORD, kw0_DecorateTransients },
269	{ "defaultbackground",      CKEYWORD, kwc_DefaultBackground },
270	{ "defaultforeground",      CKEYWORD, kwc_DefaultForeground },
271	{ "defaultfunction",        DEFAULT_FUNCTION, 0 },
272	{ "deiconifyfunction",      DEICONIFY_FUNCTION, 0 },
273	{ "destroy",                KILL, 0 },
274	{ "donticonifybyunmapping", DONT_ICONIFY_BY_UNMAPPING, 0 },
275	{ "dontmoveoff",            KEYWORD, kw0_DontMoveOff },
276	{ "dontnamedecorations",    KEYWORD, kw0_DontNameDecorations },
277	{ "dontpaintrootwindow",    KEYWORD, kw0_DontPaintRootWindow },
278	{ "dontsave",               DONT_SAVE, 0 },
279	{ "dontsetinactive",        DONTSETINACTIVE, 0 },
280	{ "dontshowwelcomewindow",  KEYWORD, kw0_DontShowWelcomeWindow },
281	{ "dontsqueezetitle",       DONT_SQUEEZE_TITLE, 0 },
282	{ "donttoggleworkspacemanagerstate", KEYWORD, kw0_DontToggleWorkspacemanagerState},
283	{ "dontwarpcursorinwmap",   KEYWORD, kw0_DontWarpCursorInWMap },
284	{ "east",                   GRAVITY, GRAV_EAST },
285	{ "ewmhignore",             EWMH_IGNORE, 0 },
286	{ "f",                      FRAME, 0 },
287	{ "forcefocus",             FORCE_FOCUS, 0 },
288	{ "forceicons",             KEYWORD, kw0_ForceIcons },
289	{ "frame",                  FRAME, 0 },
290	{ "framepadding",           NKEYWORD, kwn_FramePadding },
291	{ "function",               FUNCTION, 0 },
292	{ "grabserver",             KEYWORD, kw0_GrabServer },
293	{ "i",                      ICON, 0 },
294	{ "icon",                   ICON, 0 },
295	{ "iconbackground",         CLKEYWORD, kwcl_IconBackground },
296	{ "iconbordercolor",        CLKEYWORD, kwcl_IconBorderColor },
297	{ "iconborderwidth",        NKEYWORD, kwn_IconBorderWidth },
298	{ "icondirectory",          SKEYWORD, kws_IconDirectory },
299	{ "iconfont",               SKEYWORD, kws_IconFont },
300	{ "iconforeground",         CLKEYWORD, kwcl_IconForeground },
301	{ "iconifybyunmapping",     ICONIFY_BY_UNMAPPING, 0 },
302	{ "iconifyfunction",        ICONIFY_FUNCTION, 0 },
303	{ "iconifystyle",           SKEYWORD, kws_IconifyStyle },
304	{ "iconjustification",      SKEYWORD, kws_IconJustification },
305	{ "iconmanagerbackground",  CLKEYWORD, kwcl_IconManagerBackground },
306	{ "iconmanagerdontshow",    ICONMGR_NOSHOW, 0 },
307	{ "iconmanagerfont",        SKEYWORD, kws_IconManagerFont },
308	{ "iconmanagerforeground",  CLKEYWORD, kwcl_IconManagerForeground },
309	{ "iconmanagergeometry",    ICONMGR_GEOMETRY, 0 },
310	{ "iconmanagerhighlight",   CLKEYWORD, kwcl_IconManagerHighlight },
311	{ "iconmanagers",           ICONMGRS, 0 },
312	{ "iconmanagershadowdepth", NKEYWORD, kwn_IconManagerShadowDepth },
313	{ "iconmanagershow",        ICONMGR_SHOW, 0 },
314	{ "iconmenudontshow",       ICONMENU_DONTSHOW, 0 },
315	{ "iconmgr",                ICONMGR, 0 },
316	{ "iconregion",             ICON_REGION, 0 },
317	{ "iconregionalignement",   SKEYWORD, kws_IconRegionAlignement },
318	{ "iconregionjustification", SKEYWORD, kws_IconRegionJustification },
319	{ "icons",                  ICONS, 0 },
320	{ "iconsize",               SKEYWORD, kws_IconSize },
321	{ "ignorecaseinmenuselection",      KEYWORD, kw0_IgnoreCaseInMenuSelection },
322	{ "ignorelockmodifier",     KEYWORD, kw0_IgnoreLockModifier },
323	{ "ignoremodifier",         IGNOREMODIFIER, 0 },
324	{ "ignoretransient",        IGNORE_TRANSIENT, 0 },
325	{ "interpolatemenucolors",  KEYWORD, kw0_InterpolateMenuColors },
326	{ "l",                      LOCK, 0 },
327	{ "left",                   SIJENUM, SIJ_LEFT },
328	{ "lefttitlebutton",        LEFT_TITLEBUTTON, 0 },
329	{ "lock",                   LOCK, 0 },
330	{ "m",                      META, 0 },
331	{ "maketitle",              MAKE_TITLE, 0 },
332	{ "mapwindowbackground",    CLKEYWORD, kwcl_MapWindowBackground },
333	{ "mapwindowcurrentworkspace", MAPWINDOWCURRENTWORKSPACE, 0},
334	{ "mapwindowdefaultworkspace", MAPWINDOWDEFAULTWORKSPACE, 0},
335	{ "mapwindowforeground",    CLKEYWORD, kwcl_MapWindowForeground },
336	{ "maxicontitlewidth",      NKEYWORD, kwn_MaxIconTitleWidth },
337	{ "maxwindowsize",          SKEYWORD, kws_MaxWindowSize },
338	{ "menu",                   MENU, 0 },
339	{ "menubackground",         CKEYWORD, kwc_MenuBackground },
340	{ "menufont",               SKEYWORD, kws_MenuFont },
341	{ "menuforeground",         CKEYWORD, kwc_MenuForeground },
342	{ "menushadowcolor",        CKEYWORD, kwc_MenuShadowColor },
343	{ "menushadowdepth",        NKEYWORD, kwn_MenuShadowDepth },
344	{ "menutitlebackground",    CKEYWORD, kwc_MenuTitleBackground },
345	{ "menutitleforeground",    CKEYWORD, kwc_MenuTitleForeground },
346	{ "meta",                   META, 0 },
347	{ "mod",                    META, 0 },  /* fake it */
348	{ "monitorlayout",          MONITOR_LAYOUT, 0 },
349	{ "monochrome",             MONOCHROME, 0 },
350	{ "move",                   MOVE, 0 },
351	{ "movedelta",              NKEYWORD, kwn_MoveDelta },
352	{ "moveoffresistance",      NKEYWORD, kwn_MoveOffResistance },
353	{ "movepackresistance",     NKEYWORD, kwn_MovePackResistance },
354	{ "mwmignore",              MWM_IGNORE, 0 },
355	{ "nobackingstore",         KEYWORD, kw0_NoBackingStore },
356	{ "noborder",               NO_BORDER, 0 },
357	{ "nocasesensitive",        KEYWORD, kw0_NoCaseSensitive },
358	{ "nodecoratetransients",   KEYWORD, kw0_NoDecorateTransients },
359	{ "nodefaults",             KEYWORD, kw0_NoDefaults },
360	{ "nograbserver",           KEYWORD, kw0_NoGrabServer },
361	{ "nohighlight",            NO_HILITE, 0 },
362	{ "noiconmanagerfocus",     KEYWORD, kw0_NoIconManagerFocus },
363	{ "noiconmanagers",         KEYWORD, kw0_NoIconManagers },
364	{ "noicontitle",            NO_ICON_TITLE, 0  },
365	{ "noimagesinworkspacemanager", KEYWORD, kw0_NoImagesInWorkSpaceManager },
366	{ "nomenushadows",          KEYWORD, kw0_NoMenuShadows },
367	{ "noopaquemove",           NOOPAQUEMOVE, 0 },
368	{ "noopaqueresize",         NOOPAQUERESIZE, 0 },
369	{ "noraiseondeiconify",     KEYWORD, kw0_NoRaiseOnDeiconify },
370	{ "noraiseonmove",          KEYWORD, kw0_NoRaiseOnMove },
371	{ "noraiseonresize",        KEYWORD, kw0_NoRaiseOnResize },
372	{ "noraiseonwarp",          KEYWORD, kw0_NoRaiseOnWarp },
373	{ "norestartpreviousstate", KEYWORD, kw0_NoRestartPreviousState },
374	{ "north",                  GRAVITY, GRAV_NORTH },
375	{ "nosaveunders",           KEYWORD, kw0_NoSaveUnders },
376	{ "noshowoccupyall",        KEYWORD, kw0_NoShowOccupyAll },
377	{ "nosorticonmanager",      KEYWORD, kw0_NoSortIconManager },
378	{ "nostackmode",            NO_STACKMODE, 0 },
379	{ "notitle",                NO_TITLE, 0 },
380	{ "notitlefocus",           KEYWORD, kw0_NoTitleFocus },
381	{ "notitlehighlight",       NO_TITLE_HILITE, 0 },
382	{ "nowarptomenutitle",      KEYWORD, kw0_NoWarpToMenuTitle },
383	{ "occupy",                 OCCUPYLIST, 0 },
384	{ "occupyall",              OCCUPYALL, 0 },
385	{ "ontoppriority",          ON_TOP_PRIORITY, 0 },
386	{ "opaquemove",             OPAQUEMOVE, 0 },
387	{ "opaquemovethreshold",    NKEYWORD, kwn_OpaqueMoveThreshold },
388	{ "opaqueresize",           OPAQUERESIZE, 0 },
389	{ "opaqueresizethreshold",  NKEYWORD, kwn_OpaqueResizeThreshold },
390	{ "openwindowtimeout",      NKEYWORD, kwn_OpenWindowTimeout },
391	{ "packnewwindows",         KEYWORD, kw0_PackNewWindows },
392	{ "pixmapdirectory",        SKEYWORD, kws_PixmapDirectory },
393	{ "pixmaps",                PIXMAPS, 0 },
394	{ "prioritynotswitching",   PRIORITY_NOT_SWITCHING, 0 },
395	{ "priorityswitching",      PRIORITY_SWITCHING, 0 },
396	{ "r",                      ROOT, 0 },
397	{ "raisedelay",             NKEYWORD, kwn_RaiseDelay },
398	{ "raiseonclick",           KEYWORD, kw0_RaiseOnClick },
399	{ "raiseonclickbutton",     NKEYWORD, kwn_RaiseOnClickButton },
400	{ "raiseonwarp",            KEYWORD, kw0_RaiseOnWarp },
401	{ "raisewhenautounsqueeze", KEYWORD, kw0_RaiseWhenAutoUnSqueeze },
402	{ "randomplacement",        SSKEYWORD, kwss_RandomPlacement },
403	{ "reallymoveinworkspacemanager",   KEYWORD, kw0_ReallyMoveInWorkspaceManager },
404	{ "resize",                 RESIZE, 0 },
405	{ "resizefont",             SKEYWORD, kws_ResizeFont },
406	{ "restartpreviousstate",   KEYWORD, kw0_RestartPreviousState },
407	{ "reversecurrentworkspace", KEYWORD, kw0_ReverseCurrentWorkspace },
408	{ "right",                  SIJENUM, SIJ_RIGHT },
409	{ "righttitlebutton",       RIGHT_TITLEBUTTON, 0 },
410	{ "root",                   ROOT, 0 },
411	{ "rplaysoundhost",         SKEYWORD, kws_RplaySoundHost },
412	{ "rplaysounds",            RPLAY_SOUNDS, 0 },
413	{ "s",                      SHIFT, 0 },
414	{ "savecolor",              SAVECOLOR, 0},
415	{ "saveworkspacefocus",     KEYWORD, kw0_SaveWorkspaceFocus },
416	{ "schrinkicontitles",      KEYWORD, kw0_ShrinkIconTitles },
417	{ "select",                 SELECT, 0 },
418	{ "shift",                  SHIFT, 0 },
419	{ "shortallwindowsmenus",   KEYWORD, kw0_ShortAllWindowsMenus },
420	{ "showiconmanager",        KEYWORD, kw0_ShowIconManager },
421	{ "showworkspacemanager",   KEYWORD, kw0_ShowWorkspaceManager },
422	{ "shrinkicontitles",       KEYWORD, kw0_ShrinkIconTitles },
423	{ "sloppyfocus",            KEYWORD, kw0_SloppyFocus },
424	{ "sorticonmanager",        KEYWORD, kw0_SortIconManager },
425	{ "soundhost",              SKEYWORD, kws_SoundHost },
426	{ "south",                  GRAVITY, GRAV_SOUTH },
427	{ "squeezetitle",           SQUEEZE_TITLE, 0 },
428	{ "starticonified",         START_ICONIFIED, 0 },
429	{ "startinbuttonstate",     KEYWORD, kw0_StartInButtonState },
430	{ "startinmapstate",        KEYWORD, kw0_StartInMapState },
431	{ "startsqueezed",          STARTSQUEEZED, 0 },
432	{ "stayupmenus",            KEYWORD, kw0_StayUpMenus },
433	{ "strictwinnameencoding",  KEYWORD, kw0_StrictWinNameEncoding  },
434	{ "sunkfocuswindowtitle",   KEYWORD, kw0_SunkFocusWindowTitle },
435	{ "t",                      TITLE, 0 },
436	{ "threedborderwidth",      NKEYWORD, kwn_ThreeDBorderWidth },
437	{ "title",                  TITLE, 0 },
438	{ "titlebackground",        CLKEYWORD, kwcl_TitleBackground },
439	{ "titlebuttonborderwidth", NKEYWORD, kwn_TitleButtonBorderWidth },
440	{ "titlebuttonshadowdepth", NKEYWORD, kwn_TitleButtonShadowDepth },
441	{ "titlefont",              SKEYWORD, kws_TitleFont },
442	{ "titleforeground",        CLKEYWORD, kwcl_TitleForeground },
443	{ "titlehighlight",         TITLE_HILITE, 0 },
444	{ "titlejustification",     SKEYWORD, kws_TitleJustification },
445	{ "titlepadding",           NKEYWORD, kwn_TitlePadding },
446	{ "titleshadowdepth",       NKEYWORD, kwn_TitleShadowDepth },
447	{ "transienthasoccupation", KEYWORD, kw0_TransientHasOccupation },
448	{ "transientontop",         NKEYWORD, kwn_TransientOnTop },
449	{ "unknownicon",            SKEYWORD, kws_UnknownIcon },
450	{ "unmapbymovingfaraway",   UNMAPBYMOVINGFARAWAY, 0 },
451	{ "usepposition",           SKEYWORD, kws_UsePPosition },
452	{ "usesunktitlepixmap",     KEYWORD, kw0_UseSunkTitlePixmap },
453	{ "usethreedborders",       KEYWORD, kw0_Use3DBorders },
454	{ "usethreediconmanagers",  KEYWORD, kw0_Use3DIconManagers },
455	{ "usethreedmenus",         KEYWORD, kw0_Use3DMenus },
456	{ "usethreedtitles",        KEYWORD, kw0_Use3DTitles },
457	{ "usethreedwmap",          KEYWORD, kw0_Use3DWMap },
458#ifdef VSCREEN
459	{ "virtualscreens",         VIRTUAL_SCREENS, 0 },
460#endif
461	{ "w",                      WINDOW, 0 },
462	{ "wait",                   WAITC, 0 },
463	{ "warpcursor",             WARP_CURSOR, 0 },
464	{ "warpondeiconify",        WARP_ON_DEICONIFY, 0 },
465	{ "warpringonscreen",       KEYWORD, kw0_WarpRingOnScreen },
466	{ "warptodefaultmenuentry", KEYWORD, kw0_WarpToDefaultMenuEntry },
467	{ "warpunmapped",           KEYWORD, kw0_WarpUnmapped },
468	{ "west",                   GRAVITY, GRAV_WEST },
469	{ "window",                 WINDOW, 0 },
470#ifdef WINBOX
471	{ "windowbox",              WINDOW_BOX, 0 },
472#endif
473	{ "windowfunction",         WINDOW_FUNCTION, 0 },
474	{ "windowgeometries",       WINDOW_GEOMETRIES, 0 },
475	{ "windowregion",           WINDOW_REGION, 0 },
476	{ "windowring",             WINDOW_RING, 0 },
477	{ "windowringexclude",      WINDOW_RING_EXCLUDE, 0},
478	{ "wmgrbuttonshadowdepth",  NKEYWORD, kwn_WMgrButtonShadowDepth },
479	{ "wmgrbuttonstyle",        SKEYWORD, kws_WMgrButtonStyle },
480	{ "wmgrhorizbuttonindent",  NKEYWORD, kwn_WMgrHorizButtonIndent },
481	{ "wmgrvertbuttonindent",   NKEYWORD, kwn_WMgrVertButtonIndent },
482	{ "workspace",              WORKSPACE, 0 },
483	{ "workspacefont",          SKEYWORD, kws_WorkSpaceFont },
484	{ "workspacemanagergeometry", WORKSPCMGR_GEOMETRY, 0 },
485	{ "workspaces",             WORKSPACES, 0},
486	{ "xmovegrid",              NKEYWORD, kwn_XMoveGrid },
487	{ "xorvalue",               NKEYWORD, kwn_XorValue },
488	{ "xpmicondirectory",       SKEYWORD, kws_PixmapDirectory },
489	{ "ymovegrid",              NKEYWORD, kwn_YMoveGrid },
490	{ "zoom",                   ZOOM, 0 },
491};
492
493static const size_t numkeywords = (sizeof(keytable) / sizeof(keytable[0]));
494
495
496/*
497 * The lookup table for functions is generated.
498 */
499#include "functions_parse_table.h"
500
501
502
503static int
504kt_compare(const void *lhs, const void *rhs)
505{
506	const TwmKeyword *l = lhs;
507	const TwmKeyword *r = rhs;
508	return strcasecmp(l->name, r->name);
509}
510
511int
512parse_keyword(const char *s, int *nump)
513{
514	const TwmKeyword srch = { .name = s };
515	TwmKeyword *ret;
516	const TwmKeyword *srchtab;
517	size_t nstab;
518
519	/* Guard; nothing can't be a valid keyword */
520	if(s == NULL || strlen(s) < 1) {
521		return ERRORTOKEN;
522	}
523
524	/*
525	 * Functions are in their own table, so check for them there.
526	 *
527	 * This is safe as long as (strlen >= 1), which we already checked.
528	 */
529	if(s[0] == 'f' && s[1] == '.') {
530		srchtab = funckeytable;
531		nstab = numfunckeywords;
532	}
533	else {
534		srchtab = keytable;
535		nstab = numkeywords;
536	}
537
538	/* Find it */
539	ret = bsearch(&srch, srchtab, nstab, sizeof(TwmKeyword), kt_compare);
540	if(ret) {
541		*nump = ret->subnum;
542		return ret->value;
543	}
544
545	return ERRORTOKEN;
546}
547
548
549/*
550 * Simple tester function
551 */
552void
553chk_keytable_order(void)
554{
555	int i;
556
557	for(i = 0 ; i < (numkeywords - 1) ; i++) {
558		if(strcasecmp(keytable[i].name, keytable[i + 1].name) >= 0) {
559			fprintf(stderr, "%s: INTERNAL ERROR: keytable sorting: "
560			        "'%s' >= '%s'\n", ProgramName,
561			        keytable[i].name, keytable[i + 1].name);
562		}
563	}
564
565	for(i = 0 ; i < (numfunckeywords - 1) ; i++) {
566		if(strcasecmp(funckeytable[i].name, funckeytable[i + 1].name) >= 0) {
567			fprintf(stderr, "%s: INTERNAL ERROR: funckeytable sorting: "
568			        "'%s' >= '%s'\n", ProgramName,
569			        funckeytable[i].name, funckeytable[i + 1].name);
570		}
571	}
572}
573
574
575
576/*
577 * action routines called by grammar
578 */
579
580bool
581do_single_keyword(int keyword)
582{
583	switch(keyword) {
584		case kw0_NoDefaults:
585			Scr->NoDefaults = true;
586			return true;
587
588		case kw0_AutoRelativeResize:
589			Scr->AutoRelativeResize = true;
590			return true;
591
592		case kw0_ForceIcons:
593			if(Scr->FirstTime) {
594				Scr->ForceIcon = true;
595			}
596			return true;
597
598		case kw0_NoIconManagers:
599			Scr->NoIconManagers = true;
600			return true;
601
602		case kw0_InterpolateMenuColors:
603			if(Scr->FirstTime) {
604				Scr->InterpolateMenuColors = true;
605			}
606			return true;
607
608		case kw0_SortIconManager:
609			if(Scr->FirstTime) {
610				Scr->SortIconMgr = true;
611			}
612			return true;
613
614		case kw0_NoSortIconManager:
615			if(Scr->FirstTime) {
616				Scr->SortIconMgr = false;
617			}
618			return true;
619
620		case kw0_GrabServer:
621			Scr->NoGrabServer = false;
622			return true;
623
624		case kw0_NoGrabServer:
625			Scr->NoGrabServer = true;
626			return true;
627
628		case kw0_NoMenuShadows:
629			if(Scr->FirstTime) {
630				Scr->Shadow = false;
631			}
632			return true;
633
634		case kw0_NoRaiseOnMove:
635			if(Scr->FirstTime) {
636				Scr->NoRaiseMove = true;
637			}
638			return true;
639
640		case kw0_NoRaiseOnResize:
641			if(Scr->FirstTime) {
642				Scr->NoRaiseResize = true;
643			}
644			return true;
645
646		case kw0_NoRaiseOnDeiconify:
647			if(Scr->FirstTime) {
648				Scr->NoRaiseDeicon = true;
649			}
650			return true;
651
652		case kw0_DontMoveOff:
653			Scr->DontMoveOff = true;
654			return true;
655
656		case kw0_NoBackingStore:
657			Scr->BackingStore = false;
658			return true;
659
660		case kw0_BackingStore:
661			Scr->BackingStore = true;
662			return true;
663
664		case kw0_NoSaveUnders:
665			Scr->SaveUnder = false;
666			return true;
667
668		// XXX Shouldn't these be in Scr too?
669		case kw0_RestartPreviousState:
670			RestartPreviousState = true;
671			return true;
672
673		case kw0_NoRestartPreviousState:
674			RestartPreviousState = false;
675			return true;
676
677		case kw0_ClientBorderWidth:
678			if(Scr->FirstTime) {
679				Scr->ClientBorderWidth = true;
680			}
681			return true;
682
683		case kw0_NoTitleFocus:
684			Scr->TitleFocus = false;
685			return true;
686
687		case kw0_DecorateTransients:
688			Scr->DecorateTransients = true;
689			return true;
690
691		case kw0_NoDecorateTransients:
692			Scr->DecorateTransients = false;
693			return true;
694
695		case kw0_ShowIconManager:
696			Scr->ShowIconManager = true;
697			return true;
698
699		case kw0_ShowWorkspaceManager:
700			Scr->ShowWorkspaceManager = true;
701			return true;
702
703		case kw0_StartInButtonState:
704			Scr->workSpaceMgr.initialstate = WMS_buttons;
705			return true;
706
707		case kw0_StartInMapState:
708			Scr->workSpaceMgr.initialstate = WMS_map;
709			return true;
710
711		case kw0_NoShowOccupyAll:
712			Scr->workSpaceMgr.noshowoccupyall = true;
713			return true;
714
715		case kw0_AutoOccupy:
716			Scr->AutoOccupy = true;
717			return true;
718
719		case kw0_AutoPriority:
720			Scr->AutoPriority = true;
721			return true;
722
723		case kw0_TransientHasOccupation:
724			Scr->TransientHasOccupation = true;
725			return true;
726
727		case kw0_DontPaintRootWindow:
728			Scr->DontPaintRootWindow = true;
729			return true;
730
731		case kw0_UseSunkTitlePixmap:
732			Scr->UseSunkTitlePixmap = true;
733			return true;
734
735		case kw0_Use3DBorders:
736			Scr->use3Dborders = true;
737			return true;
738
739		case kw0_Use3DIconManagers:
740			Scr->use3Diconmanagers = true;
741			return true;
742
743		case kw0_Use3DMenus:
744			Scr->use3Dmenus = true;
745			return true;
746
747		case kw0_Use3DTitles:
748			Scr->use3Dtitles = true;
749			return true;
750
751		case kw0_Use3DWMap:
752			Scr->use3Dwmap = true;
753			return true;
754
755		case kw0_SunkFocusWindowTitle:
756			Scr->SunkFocusWindowTitle = true;
757			return true;
758
759		case kw0_BeNiceToColormap:
760			Scr->BeNiceToColormap = true;
761			return true;
762
763		case kw0_BorderResizeCursors:
764			Scr->BorderCursors = true;
765			return true;
766
767		case kw0_NoCaseSensitive:
768			Scr->CaseSensitive = false;
769			return true;
770
771		case kw0_NoRaiseOnWarp:
772			Scr->RaiseOnWarp = false;
773			return true;
774
775		case kw0_RaiseOnWarp:
776			Scr->RaiseOnWarp = true;
777			return true;
778
779		case kw0_WarpUnmapped:
780			Scr->WarpUnmapped = true;
781			return true;
782
783		case kw0_WarpRingOnScreen:
784			Scr->WarpRingAnyWhere = false;
785			return true;
786
787		case kw0_NoIconManagerFocus:
788			Scr->IconManagerFocus = false;
789			return true;
790
791		case kw0_StayUpMenus:
792			Scr->StayUpMenus = true;
793			return true;
794
795		case kw0_ClickToFocus:
796			Scr->ClickToFocus = true;
797			return true;
798
799		case kw0_ReallyMoveInWorkspaceManager:
800			Scr->ReallyMoveInWorkspaceManager = true;
801			return true;
802
803		case kw0_ShowWinWhenMovingInWmgr:
804			Scr->ShowWinWhenMovingInWmgr = true;
805			return true;
806
807		case kw0_ReverseCurrentWorkspace:
808			Scr->ReverseCurrentWorkspace = true;
809			return true;
810
811		case kw0_DontWarpCursorInWMap:
812			Scr->DontWarpCursorInWMap = true;
813			return true;
814
815		case kw0_CenterFeedbackWindow:
816			Scr->CenterFeedbackWindow = true;
817			return true;
818
819		case kw0_WarpToDefaultMenuEntry:
820			Scr->WarpToDefaultMenuEntry = true;
821			return true;
822
823		case kw0_ShrinkIconTitles:
824			Scr->ShrinkIconTitles = true;
825			return true;
826
827		case kw0_AutoRaiseIcons:
828			Scr->AutoRaiseIcons = true;
829			return true;
830
831		/* kai */
832		case kw0_AutoFocusToTransients:
833			Scr->AutoFocusToTransients = true;
834			return true;
835
836		case kw0_ShortAllWindowsMenus:
837			Scr->ShortAllWindowsMenus = true;
838			return true;
839
840		case kw0_RaiseWhenAutoUnSqueeze:
841			Scr->RaiseWhenAutoUnSqueeze = true;
842			return true;
843
844		case kw0_RaiseOnClick:
845			Scr->RaiseOnClick = true;
846			return true;
847
848		case kw0_IgnoreLockModifier:
849			Scr->IgnoreModifier |= LockMask;
850			return true;
851
852		case kw0_PackNewWindows:
853			Scr->PackNewWindows = true;
854			return true;
855
856		case kw0_IgnoreCaseInMenuSelection:
857			Scr->IgnoreCaseInMenuSelection = true;
858			return true;
859
860		case kw0_SloppyFocus:
861			Scr->SloppyFocus = true;
862			return true;
863
864		case kw0_SaveWorkspaceFocus:
865			Scr->SaveWorkspaceFocus = true;
866			return true;
867
868		case kw0_NoImagesInWorkSpaceManager:
869			Scr->NoImagesInWorkSpaceManager = true;
870			return true;
871
872		case kw0_NoWarpToMenuTitle:
873			Scr->NoWarpToMenuTitle = true;
874			return true;
875
876		case kw0_DontShowWelcomeWindow:
877			Scr->ShowWelcomeWindow = false;
878			return true;
879
880		case kw0_DontToggleWorkspacemanagerState:
881			Scr->DontToggleWorkspaceManagerState = true;
882			return true;
883
884		case kw0_DontNameDecorations:
885			Scr->NameDecorations = false;
886			return true;
887
888		case kw0_StrictWinNameEncoding:
889			Scr->StrictWinNameEncoding = true;
890			return true;
891
892	}
893	return false;
894}
895
896
897bool
898do_string_string_keyword(int keyword, const char *s1, const char *s2)
899{
900	switch(keyword) {
901		case kwss_RandomPlacement: {
902			/* RandomPlacement {on,off,all,unmapped} [displacement geom] */
903			int rp;
904			int gmask, gx, gy;     // Geometry mask/x/y values
905			unsigned int gjw, gjh; // width/height (ignored)
906			int exmask = (XValue | YValue); // Bits we need in the mask
907
908			rp = ParseRandomPlacement(s1);
909			if(rp < 0) {
910				twmrc_error_prefix();
911				fprintf(stderr,
912				        "ignoring invalid RandomPlacement argument 1 \"%s\"\n",
913				        s1);
914			}
915			else {
916				Scr->RandomPlacement = rp;
917			}
918
919			/* If no geom, we're done */
920			if(s2 == NULL) {
921				return true;
922			}
923
924			/*
925			 * Figure what the geom means.  We actually don't care about
926			 * the size (it probably won't even be provided), so the
927			 * width/height are junk.  The X/Y offsets are what we need.
928			 * But we do need them.
929			 */
930			gmask = XParseGeometry(s2, &gx, &gy, &gjw, &gjh);
931#ifdef DEBUG
932			fprintf(stderr, "DEBUG:: Mask = %x, Width = %d, Height = %d\n",
933			        gmask, gjw, gjh);
934			fprintf(stderr, "DEBUG:: X = %d, Y = %d\n", gx, gy);
935#endif
936			if((gmask & exmask) != exmask) {
937				/* Didn't get X and Y */
938				twmrc_error_prefix();
939				fprintf(stderr,
940				        "ignoring invalid RandomPlacement displacement \"%s\"\n", s2);
941			}
942			else {
943				Scr->RandomDisplacementX = gx;
944				Scr->RandomDisplacementY = gy;
945			}
946
947			/* Done */
948			return true;
949		}
950	}
951	return false;
952}
953
954
955bool
956do_string_keyword(int keyword, char *s)
957{
958	switch(keyword) {
959		case kws_UsePPosition: {
960			int ppos = ParseUsePPosition(s);
961			if(ppos < 0) {
962				twmrc_error_prefix();
963				fprintf(stderr,
964				        "ignoring invalid UsePPosition argument \"%s\"\n", s);
965			}
966			else {
967				Scr->UsePPosition = ppos;
968			}
969			return true;
970		}
971
972		case kws_IconFont:
973			if(!Scr->HaveFonts) {
974				Scr->IconFont.basename = s;
975			}
976			return true;
977
978		case kws_ResizeFont:
979			if(!Scr->HaveFonts) {
980				Scr->SizeFont.basename = s;
981			}
982			return true;
983
984		case kws_MenuFont:
985			if(!Scr->HaveFonts) {
986				Scr->MenuFont.basename = s;
987			}
988			return true;
989
990		case kws_WorkSpaceFont:
991			if(!Scr->HaveFonts) {
992				Scr->workSpaceMgr.windowFont.basename = s;
993			}
994			return true;
995
996		case kws_TitleFont:
997			if(!Scr->HaveFonts) {
998				Scr->TitleBarFont.basename = s;
999			}
1000			return true;
1001
1002		case kws_IconManagerFont:
1003			if(!Scr->HaveFonts) {
1004				Scr->IconManagerFont.basename = s;
1005			}
1006			return true;
1007
1008		case kws_UnknownIcon:
1009			if(Scr->FirstTime) {
1010				Scr->UnknownImage = GetImage(s, Scr->IconC);
1011			}
1012			return true;
1013
1014		case kws_IconDirectory:
1015			if(Scr->FirstTime) {
1016				Scr->IconDirectory = ExpandFilePath(s);
1017			}
1018			return true;
1019
1020		case kws_PixmapDirectory:
1021			if(Scr->FirstTime) {
1022				Scr->PixmapDirectory = ExpandFilePath(s);
1023			}
1024			return true;
1025
1026		case kws_MaxWindowSize: {
1027			int gmask;
1028			int exmask = (WidthValue | HeightValue);
1029			unsigned int gw, gh; // Stuff we care about
1030			int gjx, gjy;        // Stuff we don't
1031
1032			gmask = XParseGeometry(s, &gjx, &gjy, &gw, &gh);
1033			if((gmask & exmask) != exmask) {
1034				twmrc_error_prefix();
1035				fprintf(stderr, "bad MaxWindowSize \"%s\"\n", s);
1036				return false;
1037			}
1038			if(gw == 0 || gh == 0) {
1039				twmrc_error_prefix();
1040				fprintf(stderr, "MaxWindowSize \"%s\" must be non-zero\n", s);
1041				return false;
1042			}
1043			Scr->MaxWindowWidth = gw;
1044			Scr->MaxWindowHeight = gh;
1045			return true;
1046		}
1047
1048		case kws_IconJustification: {
1049			int just = ParseTitleJustification(s);
1050
1051			if((just < 0) || (just == TJ_UNDEF)) {
1052				twmrc_error_prefix();
1053				fprintf(stderr,
1054				        "ignoring invalid IconJustification argument \"%s\"\n", s);
1055			}
1056			else {
1057				Scr->IconJustification = just;
1058			}
1059			return true;
1060		}
1061		case kws_IconRegionJustification: {
1062			int just = ParseIRJustification(s);
1063
1064			if(just < 0 || (just == IRJ_UNDEF)) {
1065				twmrc_error_prefix();
1066				fprintf(stderr,
1067				        "ignoring invalid IconRegionJustification argument \"%s\"\n", s);
1068			}
1069			else {
1070				Scr->IconRegionJustification = just;
1071			}
1072			return true;
1073		}
1074		case kws_IconRegionAlignement: {
1075			int just = ParseAlignement(s);
1076
1077			if(just < 0) {
1078				twmrc_error_prefix();
1079				fprintf(stderr,
1080				        "ignoring invalid IconRegionAlignement argument \"%s\"\n", s);
1081			}
1082			else {
1083				Scr->IconRegionAlignement = just;
1084			}
1085			return true;
1086		}
1087
1088		case kws_TitleJustification: {
1089			int just = ParseTitleJustification(s);
1090
1091			if((just < 0) || (just == TJ_UNDEF)) {
1092				twmrc_error_prefix();
1093				fprintf(stderr,
1094				        "ignoring invalid TitleJustification argument \"%s\"\n", s);
1095			}
1096			else {
1097				Scr->TitleJustification = just;
1098			}
1099			return true;
1100		}
1101		case kws_RplaySoundHost:
1102		case kws_SoundHost:
1103			if(Scr->FirstTime) {
1104				/* Warning to be enabled in the future before removal */
1105				if(0 && keyword == kws_SoundHost) {
1106					twmrc_error_prefix();
1107					fprintf(stderr, "SoundHost is deprecated, please "
1108					        "use RplaySoundHost instead.\n");
1109				}
1110#ifdef SOUNDS
1111				set_sound_host(s);
1112#else
1113				twmrc_error_prefix();
1114				fprintf(stderr, "Ignoring %sSoundHost; rplay not ronfigured.\n",
1115				        (keyword == kws_RplaySoundHost ? "Rplay" : ""));
1116#endif
1117			}
1118			return true;
1119
1120		case kws_WMgrButtonStyle: {
1121			int style = ParseButtonStyle(s);
1122
1123			if(style < 0) {
1124				twmrc_error_prefix();
1125				fprintf(stderr,
1126				        "ignoring invalid WMgrButtonStyle argument \"%s\"\n", s);
1127			}
1128			else {
1129				Scr->workSpaceMgr.buttonStyle = style;
1130			}
1131			return true;
1132		}
1133
1134		case kws_IconifyStyle: {
1135			int style = ParseIconifyStyle(s);
1136
1137			if(style < 0) {
1138				twmrc_error_prefix();
1139				fprintf(stderr, "ignoring invalid IconifyStyle argument \"%s\"\n", s);
1140			}
1141			else {
1142				Scr->IconifyStyle = style;
1143			}
1144			return true;
1145		}
1146
1147#ifdef EWMH
1148		case kws_IconSize:
1149			if(sscanf(s, "%dx%d", &Scr->PreferredIconWidth,
1150			                &Scr->PreferredIconHeight) == 2) {
1151				/* ok */
1152			}
1153			else if(sscanf(s, "%d", &Scr->PreferredIconWidth) == 1) {
1154				Scr->PreferredIconHeight = Scr->PreferredIconWidth;
1155			}
1156			else {
1157				Scr->PreferredIconHeight = Scr->PreferredIconWidth = 48;
1158			}
1159			return true;
1160#endif
1161	}
1162	return false;
1163}
1164
1165
1166bool
1167do_number_keyword(int keyword, int num)
1168{
1169	switch(keyword) {
1170		case kwn_ConstrainedMoveTime:
1171			ConstrainedMoveTime = num;
1172			return true;
1173
1174		case kwn_MoveDelta:
1175			Scr->MoveDelta = num;
1176			return true;
1177
1178		case kwn_MoveOffResistance:
1179			Scr->MoveOffResistance = num;
1180			return true;
1181
1182		case kwn_MovePackResistance:
1183			if(num < 0) {
1184				num = 20;
1185			}
1186			Scr->MovePackResistance = num;
1187			return true;
1188
1189		case kwn_XMoveGrid:
1190			if(num < 1) {
1191				num = 1;
1192			}
1193			if(num > 100) {
1194				num = 100;
1195			}
1196			Scr->XMoveGrid = num;
1197			return true;
1198
1199		case kwn_YMoveGrid:
1200			if(num < 1) {
1201				num = 1;
1202			}
1203			if(num > 100) {
1204				num = 100;
1205			}
1206			Scr->YMoveGrid = num;
1207			return true;
1208
1209		case kwn_XorValue:
1210			if(Scr->FirstTime) {
1211				Scr->XORvalue = num;
1212			}
1213			return true;
1214
1215		case kwn_FramePadding:
1216			if(Scr->FirstTime) {
1217				Scr->FramePadding = num;
1218			}
1219			return true;
1220
1221		case kwn_TitlePadding:
1222			if(Scr->FirstTime) {
1223				Scr->TitlePadding = num;
1224			}
1225			return true;
1226
1227		case kwn_ButtonIndent:
1228			if(Scr->FirstTime) {
1229				Scr->ButtonIndent = num;
1230			}
1231			return true;
1232
1233		case kwn_ThreeDBorderWidth:
1234			if(Scr->FirstTime) {
1235				Scr->ThreeDBorderWidth = num;
1236			}
1237			return true;
1238
1239		case kwn_BorderWidth:
1240			if(Scr->FirstTime) {
1241				Scr->BorderWidth = num;
1242			}
1243			return true;
1244
1245		case kwn_IconBorderWidth:
1246			if(Scr->FirstTime) {
1247				Scr->IconBorderWidth = num;
1248			}
1249			return true;
1250
1251		case kwn_TitleButtonBorderWidth:
1252			if(Scr->FirstTime) {
1253				Scr->TBInfo.border = num;
1254			}
1255			return true;
1256
1257		case kwn_RaiseDelay:
1258			RaiseDelay = num;
1259			return true;
1260
1261		case kwn_TransientOnTop:
1262			if(Scr->FirstTime) {
1263				Scr->TransientOnTop = num;
1264			}
1265			return true;
1266
1267		case kwn_OpaqueMoveThreshold:
1268			if(Scr->FirstTime) {
1269				Scr->OpaqueMoveThreshold = num;
1270			}
1271			return true;
1272
1273		case kwn_OpaqueResizeThreshold:
1274			if(Scr->FirstTime) {
1275				Scr->OpaqueResizeThreshold = num;
1276			}
1277			return true;
1278
1279		case kwn_WMgrVertButtonIndent:
1280			if(Scr->FirstTime) {
1281				Scr->WMgrVertButtonIndent = num;
1282			}
1283			if(Scr->WMgrVertButtonIndent < 0) {
1284				Scr->WMgrVertButtonIndent = 0;
1285			}
1286			Scr->workSpaceMgr.vspace = Scr->WMgrVertButtonIndent;
1287			Scr->workSpaceMgr.occupyWindow->vspace = Scr->WMgrVertButtonIndent;
1288			return true;
1289
1290		case kwn_WMgrHorizButtonIndent:
1291			if(Scr->FirstTime) {
1292				Scr->WMgrHorizButtonIndent = num;
1293			}
1294			if(Scr->WMgrHorizButtonIndent < 0) {
1295				Scr->WMgrHorizButtonIndent = 0;
1296			}
1297			Scr->workSpaceMgr.hspace = Scr->WMgrHorizButtonIndent;
1298			Scr->workSpaceMgr.occupyWindow->hspace = Scr->WMgrHorizButtonIndent;
1299			return true;
1300
1301		case kwn_WMgrButtonShadowDepth:
1302			if(Scr->FirstTime) {
1303				Scr->WMgrButtonShadowDepth = num;
1304			}
1305			if(Scr->WMgrButtonShadowDepth < 1) {
1306				Scr->WMgrButtonShadowDepth = 1;
1307			}
1308			return true;
1309
1310		case kwn_MaxIconTitleWidth:
1311			if(Scr->FirstTime) {
1312				Scr->MaxIconTitleWidth = num;
1313			}
1314			return true;
1315
1316		case kwn_ClearShadowContrast:
1317			if(Scr->FirstTime) {
1318				Scr->ClearShadowContrast = num;
1319			}
1320			if(Scr->ClearShadowContrast < 0) {
1321				Scr->ClearShadowContrast = 0;
1322			}
1323			if(Scr->ClearShadowContrast > 100) {
1324				Scr->ClearShadowContrast = 100;
1325			}
1326			return true;
1327
1328		case kwn_DarkShadowContrast:
1329			if(Scr->FirstTime) {
1330				Scr->DarkShadowContrast = num;
1331			}
1332			if(Scr->DarkShadowContrast < 0) {
1333				Scr->DarkShadowContrast = 0;
1334			}
1335			if(Scr->DarkShadowContrast > 100) {
1336				Scr->DarkShadowContrast = 100;
1337			}
1338			return true;
1339
1340		case kwn_AnimationSpeed:
1341			if(num < 0) {
1342				num = 0;
1343			}
1344			SetAnimationSpeed(num);
1345			return true;
1346
1347		case kwn_BorderShadowDepth:
1348			if(Scr->FirstTime) {
1349				Scr->BorderShadowDepth = num;
1350			}
1351			if(Scr->BorderShadowDepth < 0) {
1352				Scr->BorderShadowDepth = 2;
1353			}
1354			return true;
1355
1356		case kwn_BorderLeft:
1357			if(Scr->FirstTime) {
1358				Scr->BorderLeft = num;
1359			}
1360			if(Scr->BorderLeft < 0) {
1361				Scr->BorderLeft = 0;
1362			}
1363			return true;
1364
1365		case kwn_BorderRight:
1366			if(Scr->FirstTime) {
1367				Scr->BorderRight = num;
1368			}
1369			if(Scr->BorderRight < 0) {
1370				Scr->BorderRight = 0;
1371			}
1372			return true;
1373
1374		case kwn_BorderTop:
1375			if(Scr->FirstTime) {
1376				Scr->BorderTop = num;
1377			}
1378			if(Scr->BorderTop < 0) {
1379				Scr->BorderTop = 0;
1380			}
1381			return true;
1382
1383		case kwn_BorderBottom:
1384			if(Scr->FirstTime) {
1385				Scr->BorderBottom = num;
1386			}
1387			if(Scr->BorderBottom < 0) {
1388				Scr->BorderBottom = 0;
1389			}
1390			return true;
1391
1392		case kwn_TitleButtonShadowDepth:
1393			if(Scr->FirstTime) {
1394				Scr->TitleButtonShadowDepth = num;
1395			}
1396			if(Scr->TitleButtonShadowDepth < 0) {
1397				Scr->TitleButtonShadowDepth = 2;
1398			}
1399			return true;
1400
1401		case kwn_TitleShadowDepth:
1402			if(Scr->FirstTime) {
1403				Scr->TitleShadowDepth = num;
1404			}
1405			if(Scr->TitleShadowDepth < 0) {
1406				Scr->TitleShadowDepth = 2;
1407			}
1408			return true;
1409
1410		case kwn_IconManagerShadowDepth:
1411			if(Scr->FirstTime) {
1412				Scr->IconManagerShadowDepth = num;
1413			}
1414			if(Scr->IconManagerShadowDepth < 0) {
1415				Scr->IconManagerShadowDepth = 2;
1416			}
1417			return true;
1418
1419		case kwn_MenuShadowDepth:
1420			if(Scr->FirstTime) {
1421				Scr->MenuShadowDepth = num;
1422			}
1423			if(Scr->MenuShadowDepth < 0) {
1424				Scr->MenuShadowDepth = 2;
1425			}
1426			return true;
1427
1428		case kwn_OpenWindowTimeout:
1429			if(Scr->FirstTime) {
1430				Scr->OpenWindowTimeout = num;
1431			}
1432			if(Scr->OpenWindowTimeout < 0) {
1433				Scr->OpenWindowTimeout = 0;
1434			}
1435			return true;
1436
1437		case kwn_RaiseOnClickButton:
1438			if(Scr->FirstTime) {
1439				Scr->RaiseOnClickButton = num;
1440			}
1441			if(Scr->RaiseOnClickButton < 1) {
1442				Scr->RaiseOnClickButton = 1;
1443			}
1444			if(Scr->RaiseOnClickButton > MAX_BUTTONS) {
1445				Scr->RaiseOnClickButton = MAX_BUTTONS;
1446			}
1447			return true;
1448
1449
1450	}
1451
1452	return false;
1453}
1454
1455name_list **
1456do_colorlist_keyword(int keyword, int colormode, char *s)
1457{
1458	switch(keyword) {
1459		case kwcl_BorderColor:
1460			GetColor(colormode, &Scr->BorderColorC.back, s);
1461			return &Scr->BorderColorL;
1462
1463		case kwcl_IconManagerHighlight:
1464			GetColor(colormode, &Scr->IconManagerHighlight, s);
1465			return &Scr->IconManagerHighlightL;
1466
1467		case kwcl_BorderTileForeground:
1468			GetColor(colormode, &Scr->BorderTileC.fore, s);
1469			return &Scr->BorderTileForegroundL;
1470
1471		case kwcl_BorderTileBackground:
1472			GetColor(colormode, &Scr->BorderTileC.back, s);
1473			return &Scr->BorderTileBackgroundL;
1474
1475		case kwcl_TitleForeground:
1476			GetColor(colormode, &Scr->TitleC.fore, s);
1477			return &Scr->TitleForegroundL;
1478
1479		case kwcl_TitleBackground:
1480			GetColor(colormode, &Scr->TitleC.back, s);
1481			return &Scr->TitleBackgroundL;
1482
1483		case kwcl_IconForeground:
1484			GetColor(colormode, &Scr->IconC.fore, s);
1485			return &Scr->IconForegroundL;
1486
1487		case kwcl_IconBackground:
1488			GetColor(colormode, &Scr->IconC.back, s);
1489			return &Scr->IconBackgroundL;
1490
1491		case kwcl_IconBorderColor:
1492			GetColor(colormode, &Scr->IconBorderColor, s);
1493			return &Scr->IconBorderColorL;
1494
1495		case kwcl_IconManagerForeground:
1496			GetColor(colormode, &Scr->IconManagerC.fore, s);
1497			return &Scr->IconManagerFL;
1498
1499		case kwcl_IconManagerBackground:
1500			GetColor(colormode, &Scr->IconManagerC.back, s);
1501			return &Scr->IconManagerBL;
1502
1503		case kwcl_MapWindowBackground:
1504			GetColor(colormode, &Scr->workSpaceMgr.windowcp.back, s);
1505			Scr->workSpaceMgr.windowcpgiven = true;
1506			return &Scr->workSpaceMgr.windowBackgroundL;
1507
1508		case kwcl_MapWindowForeground:
1509			GetColor(colormode, &Scr->workSpaceMgr.windowcp.fore, s);
1510			Scr->workSpaceMgr.windowcpgiven = true;
1511			return &Scr->workSpaceMgr.windowForegroundL;
1512	}
1513	return NULL;
1514}
1515
1516bool
1517do_color_keyword(int keyword, int colormode, char *s)
1518{
1519	switch(keyword) {
1520		case kwc_DefaultForeground:
1521			GetColor(colormode, &Scr->DefaultC.fore, s);
1522			return true;
1523
1524		case kwc_DefaultBackground:
1525			GetColor(colormode, &Scr->DefaultC.back, s);
1526			return true;
1527
1528		case kwc_MenuForeground:
1529			GetColor(colormode, &Scr->MenuC.fore, s);
1530			return true;
1531
1532		case kwc_MenuBackground:
1533			GetColor(colormode, &Scr->MenuC.back, s);
1534			return true;
1535
1536		case kwc_MenuTitleForeground:
1537			GetColor(colormode, &Scr->MenuTitleC.fore, s);
1538			return true;
1539
1540		case kwc_MenuTitleBackground:
1541			GetColor(colormode, &Scr->MenuTitleC.back, s);
1542			return true;
1543
1544		case kwc_MenuShadowColor:
1545			GetColor(colormode, &Scr->MenuShadowColor, s);
1546			return true;
1547
1548	}
1549
1550	return false;
1551}
1552
1553/*
1554 * put_pixel_on_root() Save a pixel value in twm root window color property.
1555 */
1556static void
1557put_pixel_on_root(Pixel pixel)
1558{
1559	bool addone = true;
1560	Atom          retAtom;
1561	int           retFormat;
1562	unsigned long nPixels, retAfter;
1563	Pixel        *retProp;
1564
1565	// Get current list
1566	if(XGetWindowProperty(dpy, Scr->Root, XA__MIT_PRIORITY_COLORS, 0, 8192,
1567	                      False, XA_CARDINAL, &retAtom,
1568	                      &retFormat, &nPixels, &retAfter,
1569	                      (unsigned char **)&retProp) != Success || !retProp) {
1570		return;
1571	}
1572
1573	// See if we already have this one
1574	for(int i = 0; i < nPixels; i++) {
1575		if(pixel == retProp[i]) {
1576			addone = false;
1577		}
1578	}
1579	XFree(retProp);
1580
1581	// If not, append it
1582	if(addone) {
1583		XChangeProperty(dpy, Scr->Root, XA__MIT_PRIORITY_COLORS,
1584		                XA_CARDINAL, 32, PropModeAppend,
1585		                (unsigned char *)&pixel, 1);
1586	}
1587}
1588
1589/*
1590 * Stash for SaveColor{} values during config parsing.
1591 */
1592typedef struct _cnode {
1593	int i;
1594	int cmode;
1595	char *sname;
1596	struct _cnode *next;
1597} Cnode;
1598static Cnode *chead = NULL;
1599
1600/**
1601 * Add a SaveColor{} entry to our stash.
1602 */
1603static void
1604add_cnode(int kwcl, int cmode, char *colname)
1605{
1606	Cnode *cnew;
1607
1608	cnew = calloc(1, sizeof(Cnode));
1609	cnew->i     = kwcl;
1610	cnew->cmode = cmode;
1611	cnew->sname = colname;
1612
1613	if(!chead) {
1614		chead = cnew;
1615	}
1616	else {
1617		cnew->next = chead;
1618		chead = cnew;
1619	}
1620
1621	return;
1622}
1623
1624
1625/*
1626 * do_string_savecolor() save a color from a string in the twmrc file.
1627 */
1628void
1629do_string_savecolor(int colormode, char *s)
1630{
1631	add_cnode(0, colormode, s);
1632}
1633
1634/*
1635 * do_var_savecolor() save a color from a var in the twmrc file.
1636 */
1637void
1638do_var_savecolor(int key)
1639{
1640	add_cnode(key, 0, NULL);
1641}
1642
1643/*
1644 * assign_var_savecolor() traverse the var save color list placeing the pixels
1645 *                        in the root window property.
1646 */
1647void
1648assign_var_savecolor(void)
1649{
1650	Cnode *cp = chead;
1651
1652	// Start with an empty property
1653	XChangeProperty(dpy, Scr->Root, XA__MIT_PRIORITY_COLORS,
1654	                XA_CARDINAL, 32, PropModeReplace, NULL, 0);
1655
1656	// Loop over, stash 'em, and clean up
1657	while(cp != NULL) {
1658		Cnode *tmp_cp = cp;
1659
1660		switch(cp->i) {
1661			case kwcl_BorderColor:
1662				put_pixel_on_root(Scr->BorderColorC.back);
1663				break;
1664			case kwcl_IconManagerHighlight:
1665				put_pixel_on_root(Scr->IconManagerHighlight);
1666				break;
1667			case kwcl_BorderTileForeground:
1668				put_pixel_on_root(Scr->BorderTileC.fore);
1669				break;
1670			case kwcl_BorderTileBackground:
1671				put_pixel_on_root(Scr->BorderTileC.back);
1672				break;
1673			case kwcl_TitleForeground:
1674				put_pixel_on_root(Scr->TitleC.fore);
1675				break;
1676			case kwcl_TitleBackground:
1677				put_pixel_on_root(Scr->TitleC.back);
1678				break;
1679			case kwcl_IconForeground:
1680				put_pixel_on_root(Scr->IconC.fore);
1681				break;
1682			case kwcl_IconBackground:
1683				put_pixel_on_root(Scr->IconC.back);
1684				break;
1685			case kwcl_IconBorderColor:
1686				put_pixel_on_root(Scr->IconBorderColor);
1687				break;
1688			case kwcl_IconManagerForeground:
1689				put_pixel_on_root(Scr->IconManagerC.fore);
1690				break;
1691			case kwcl_IconManagerBackground:
1692				put_pixel_on_root(Scr->IconManagerC.back);
1693				break;
1694			case kwcl_MapWindowForeground:
1695				put_pixel_on_root(Scr->workSpaceMgr.windowcp.fore);
1696				break;
1697			case kwcl_MapWindowBackground:
1698				put_pixel_on_root(Scr->workSpaceMgr.windowcp.back);
1699				break;
1700			case 0: {
1701				// This means it's a string, not one of our keywords
1702				Pixel p;
1703				GetColor(cp->cmode, &p, cp->sname);
1704				put_pixel_on_root(p);
1705			}
1706		}
1707
1708		cp = cp->next;
1709		free(tmp_cp);
1710	}
1711	if(chead) {
1712		chead = NULL;
1713	}
1714}
1715
1716
1717/*
1718 * RandomPlacement [...] parse
1719 */
1720static int
1721ParseRandomPlacement(const char *s)
1722{
1723	/* No first arg -> 'all' */
1724	if(s == NULL) {
1725		return RP_ALL;
1726	}
1727	if(strlen(s) == 0) {
1728		return RP_ALL;
1729	}
1730
1731#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return RP_##ret; }
1732	CHK(DEFSTRING,  ALL);
1733	CHK("on",       ALL);
1734	CHK("all",      ALL);
1735	CHK("off",      OFF);
1736	CHK("unmapped", UNMAPPED);
1737#undef CHK
1738
1739	return -1;
1740}
1741
1742
1743/*
1744 * Parse out IconRegionJustification string.
1745 *
1746 * X-ref comment on ParseAlignement about return value.
1747 */
1748int
1749ParseIRJustification(const char *s)
1750{
1751	if(strlen(s) == 0) {
1752		return -1;
1753	}
1754
1755#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return IRJ_##ret; }
1756	CHK(DEFSTRING, CENTER);
1757	CHK("undef",   UNDEF);
1758	CHK("left",    LEFT);
1759	CHK("center",  CENTER);
1760	CHK("right",   RIGHT);
1761	CHK("border",  BORDER);
1762#undef CHK
1763
1764	return -1;
1765}
1766
1767
1768/*
1769 * Parse out string for title justification.  From TitleJustification,
1770 * IconJustification, iconjust arg to IconRegion.
1771 *
1772 * X-ref comment on ParseAlignement about return value.
1773 */
1774int
1775ParseTitleJustification(const char *s)
1776{
1777	if(strlen(s) == 0) {
1778		return -1;
1779	}
1780
1781#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return TJ_##ret; }
1782	/* XXX Different uses really have different defaults... */
1783	CHK(DEFSTRING, CENTER);
1784	CHK("undef",   UNDEF);
1785	CHK("left",    LEFT);
1786	CHK("center",  CENTER);
1787	CHK("right",   RIGHT);
1788#undef CHK
1789
1790	return -1;
1791}
1792
1793
1794/*
1795 * Parse out the string specifier for IconRegion Alignement[sic].
1796 * Strictly speaking, this [almost always] returns an IRAlignement enum
1797 * value.  However, it's specified as int to allow the -1 return for
1798 * invalid values.  enum's start numbering from 0 (unless specific values
1799 * are given), so that's a safe out-of-bounds value.  And making an
1800 * IRA_INVALID value would just add unnecessary complication, since
1801 * during parsing is the only time it makes sense.
1802 */
1803int
1804ParseAlignement(const char *s)
1805{
1806	if(strlen(s) == 0) {
1807		return -1;
1808	}
1809
1810#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return IRA_##ret; }
1811	CHK(DEFSTRING, CENTER);
1812	CHK("center",  CENTER);
1813	CHK("top",     TOP);
1814	CHK("bottom",  BOTTOM);
1815	CHK("border",  BORDER);
1816	CHK("undef",   UNDEF);
1817#undef CHK
1818
1819	return -1;
1820}
1821
1822static int
1823ParseUsePPosition(const char *s)
1824{
1825	if(strlen(s) == 0) {
1826		return -1;
1827	}
1828
1829#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return PPOS_##ret; }
1830	CHK(DEFSTRING,  OFF);
1831	CHK("off",      OFF);
1832	CHK("on",       ON);
1833	CHK("non-zero", NON_ZERO);
1834	CHK("nonzero",  NON_ZERO);
1835#undef CHK
1836
1837	return -1;
1838}
1839
1840static int
1841ParseButtonStyle(const char *s)
1842{
1843	if(s == NULL || strlen(s) == 0) {
1844		return -1;
1845	}
1846
1847#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return STYLE_##ret; }
1848	CHK(DEFSTRING, NORMAL);
1849	CHK("normal",  NORMAL);
1850	CHK("style1",  STYLE1);
1851	CHK("style2",  STYLE2);
1852	CHK("style3",  STYLE3);
1853#undef CHK
1854
1855	return -1;
1856}
1857
1858static int
1859ParseIconifyStyle(const char *s)
1860{
1861	if(s == NULL || strlen(s) == 0) {
1862		return -1;
1863	}
1864
1865#define CHK(str, ret) if(strcasecmp(s, str) == 0) { return ICONIFY_##ret; }
1866	CHK(DEFSTRING, NORMAL);
1867	CHK("normal",  NORMAL);
1868	CHK("mosaic",  MOSAIC);
1869	CHK("zoomin",  ZOOMIN);
1870	CHK("zoomout", ZOOMOUT);
1871	CHK("fade",    FADE);
1872	CHK("sweep",   SWEEP);
1873#undef CHK
1874
1875	return -1;
1876}
1877
1878void
1879do_squeeze_entry(name_list **slist, // squeeze or dont-squeeze list
1880                 const char *name,  // window name
1881                 SIJust justify,    // left, center, right
1882                 int num,           // signed num
1883                 int denom)         // 0 or indicates fraction denom
1884{
1885	int absnum = (num < 0 ? -num : num);
1886
1887	if(denom < 0) {
1888		twmrc_error_prefix();
1889		fprintf(stderr, "negative SqueezeTitle denominator %d\n", denom);
1890		ParseError = true;
1891		return;
1892	}
1893	if(absnum > denom && denom != 0) {
1894		twmrc_error_prefix();
1895		fprintf(stderr, "SqueezeTitle fraction %d/%d outside window\n",
1896		        num, denom);
1897		ParseError = true;
1898		return;
1899	}
1900	/* Process the special cases from the manual here rather than
1901	 * each time we calculate the position of the title bar
1902	 * in ComputeTitleLocation().
1903	 * In fact, it's better to get rid of them entirely, but we
1904	 * probably should not do that for compatibility's sake.
1905	 * By using a non-zero denominator the position will be relative.
1906	 */
1907	if(denom == 0 && num == 0) {
1908		if(justify == SIJ_CENTER) {
1909			num = 1;
1910			denom = 2;
1911		}
1912		else if(justify == SIJ_RIGHT) {
1913			num = 2;
1914			denom = 2;
1915		}
1916		twmrc_error_prefix();
1917		fprintf(stderr, "deprecated SqueezeTitle faction 0/0, assuming %d/%d\n",
1918		        num, denom);
1919	}
1920
1921	if(HasShape) {
1922		SqueezeInfo *sinfo;
1923		sinfo = malloc(sizeof(SqueezeInfo));
1924
1925		if(!sinfo) {
1926			twmrc_error_prefix();
1927			fprintf(stderr, "unable to allocate %lu bytes for squeeze info\n",
1928			        (unsigned long) sizeof(SqueezeInfo));
1929			ParseError = true;
1930			return;
1931		}
1932		sinfo->justify = justify;
1933		sinfo->num = num;
1934		sinfo->denom = denom;
1935		AddToList(slist, name, sinfo);
1936	}
1937	return;
1938}
1939
1940
1941/*
1942 * Parsing for EWMHIgnore { } lists
1943 */
1944void
1945proc_ewmh_ignore(void)
1946{
1947#ifndef EWMH
1948	twmrc_error_prefix();
1949	fprintf(stderr, "EWMH not enabled, EWMHIgnore { } ignored.\n");
1950	ParseError = true;
1951	return;
1952#endif
1953	/* else nada */
1954	return;
1955}
1956void
1957add_ewmh_ignore(char *s)
1958{
1959#ifndef EWMH
1960	return;
1961#else
1962
1963#define HANDLE(x) \
1964        if(strcasecmp(s, (x)) == 0) { \
1965                AddToList(&Scr->EWMHIgnore, (x), ""); \
1966                return; \
1967        }
1968	HANDLE("STATE_MAXIMIZED_VERT");
1969	HANDLE("STATE_MAXIMIZED_HORZ");
1970	HANDLE("STATE_FULLSCREEN");
1971	HANDLE("STATE_SHADED");
1972	HANDLE("STATE_ABOVE");
1973	HANDLE("STATE_BELOW");
1974#undef HANDLE
1975
1976	twmrc_error_prefix();
1977	fprintf(stderr, "Unexpected EWMHIgnore value '%s'\n", s);
1978	ParseError = true;
1979	return;
1980#endif /* EWMH */
1981}
1982
1983
1984/*
1985 * Parsing for MWMIgnore { } lists
1986 */
1987void
1988proc_mwm_ignore(void)
1989{
1990	/* Nothing to do */
1991	return;
1992}
1993void
1994add_mwm_ignore(char *s)
1995{
1996#define HANDLE(x) \
1997        if(strcasecmp(s, (x)) == 0) { \
1998                AddToList(&Scr->MWMIgnore, (x), ""); \
1999                return; \
2000        }
2001	HANDLE("DECOR_BORDER");
2002	HANDLE("DECOR_TITLE");
2003#undef HANDLE
2004
2005	twmrc_error_prefix();
2006	fprintf(stderr, "Unexpected MWMIgnore value '%s'\n", s);
2007	ParseError = true;
2008	return;
2009}
2010
2011
2012/*
2013 * Parsing for Layout { } lists, to override the monitor layout we
2014 * assumed or got from RANDR.
2015 */
2016static RAreaList *override_monitors;
2017static struct {
2018	char **names;
2019	int len;
2020	int cap;
2021} override_monitors_names;
2022
2023
2024/**
2025 * Allocate space for our monitor override list.
2026 */
2027void
2028init_layout_override(void)
2029{
2030	// 4 seems like a good guess.  If we're doing this, we're probably
2031	// making at least 2 monitors, and >4 is gonna be pretty rare, so...
2032	const int initsz = 4;
2033
2034	override_monitors = RAreaListNew(initsz, NULL);
2035	if(override_monitors == NULL) {
2036		twmrc_error_prefix();
2037		fprintf(stderr, "Failed allocating RAreaList for monitors.\n");
2038		ParseError = true;
2039		return;
2040		// Maybe we should just abort(); if malloc failed allocating a
2041		// few dozen bytes this early, we're _screwed_.
2042	}
2043
2044	override_monitors_names.names = calloc(initsz, sizeof(char *));
2045	override_monitors_names.len = 0;
2046	override_monitors_names.cap = initsz;
2047
2048	return;
2049}
2050
2051/**
2052 * Add an entry to our monitor list
2053 *
2054 * Expecting: [Name:]WxH[+X[+Y]]
2055 */
2056void
2057add_layout_override_entry(const char *s)
2058{
2059	const char *tmp;
2060	int xpgret;
2061	int x, y;
2062	unsigned int width, height;
2063
2064	if(override_monitors == NULL) {
2065		// alloc failed, so just give up; we'll fail in the end anyway...
2066		return;
2067	}
2068
2069	// Got a name?
2070	tmp = strchr(s, ':');
2071	if(tmp != NULL && tmp != s) {
2072		// Stash the name
2073		override_monitors_names.names[override_monitors_names.len]
2074		        = strndup(s, tmp - s);
2075		// len advances below
2076
2077		// Advance to geom
2078		s = tmp + 1;
2079	}
2080	// Advance whether we got a name or not, to keep in sync.
2081	override_monitors_names.len++;
2082
2083
2084	// Either way, s points at the geom now
2085	xpgret = XParseGeometry(s, &x, &y, &width, &height);
2086
2087	// Width and height are non-optional.  If x/y aren't given, we assume
2088	// +0+0.  If we're given -0's, well, we don't _support_ that, but
2089	// XPG() turns them into positives for us, so just accept it...
2090	const int has_hw = (WidthValue | HeightValue);
2091	if((xpgret & has_hw) != has_hw) {
2092		twmrc_error_prefix();
2093		fprintf(stderr, "Need both height and width in '%s'\n", s);
2094		ParseError = true;
2095		// Don't bother free()'ing stuff, we're going to exit after
2096		// parse completes
2097		return;
2098	}
2099	if(!(xpgret & XValue)) {
2100		x = 0;
2101	}
2102	if(!(xpgret & YValue)) {
2103		y = 0;
2104	}
2105
2106
2107	// And stash it
2108	RAreaListAdd(override_monitors, RAreaNewStatic(x, y, width, height));
2109
2110	// Whether we had a name for this 'monitor' or not, we need to
2111	// possibly grow the names list, since it has to stay in lockstep
2112	// with the areas as we add 'em.
2113	{
2114		char ***names = &override_monitors_names.names;
2115		int len = override_monitors_names.len;
2116
2117		if(len == override_monitors_names.cap) {
2118			char **tnames = realloc(*names, (len + 1) * sizeof(char *));
2119			if(tnames == NULL) {
2120				abort();
2121			}
2122			*names = tnames;
2123			override_monitors_names.cap++;
2124		}
2125	}
2126
2127	return;
2128}
2129
2130/**
2131 * Finalize the override layout and store it up globally.
2132 */
2133void
2134proc_layout_override(void)
2135{
2136	RLayout *new_layout;
2137
2138	// Guard
2139	if(RAreaListLen(override_monitors) < 1) {
2140		// Make this non-fatal, so an empty spec not-quite-quietly does
2141		// nothing.
2142		twmrc_error_prefix();
2143		fprintf(stderr, "no monitors specified, ignoring MonitorLayout\n");
2144
2145		// Since it's non-fatal, we _do_ need to cleanup more
2146		// carefully...
2147		RAreaListFree(override_monitors);
2148		for(int i = 0; i < override_monitors_names.len ; i++) {
2149			free(override_monitors_names.names[i]);
2150		}
2151		free(override_monitors_names.names);
2152		return;
2153	}
2154
2155	new_layout = RLayoutNew(override_monitors);
2156	RLayoutSetMonitorsNames(new_layout, override_monitors_names.names);
2157	// Silently stop paying attention to o_m_n.  Don't free() anything,
2158	// since new_layout now owns it.  If we get another MonitorLayout{}
2159	// block, it'll start over again with init(), and allocate new space.
2160
2161#ifdef DEBUG
2162	fprintf(stderr, "Overridden layout: ");
2163	RLayoutPrint(new_layout);
2164#endif
2165
2166	RLayoutFree(Scr->Layout);
2167	Scr->Layout = new_layout;
2168	return;
2169}
2170