Maximus: Tiled Maximization
[wmaker-crm.git] / src / defaults.c
1 /* defaults.c - manage configuration through defaults db
2  *
3  *  Window Maker window manager
4  *
5  *  Copyright (c) 1997-2003 Alfredo K. Kojima
6  *  Copyright (c) 1998-2003 Dan Pascu
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21  *  USA.
22  */
23
24 #include "wconfig.h"
25
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <time.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <limits.h>
37 #include <signal.h>
38
39 #ifdef HAVE_DLFCN_H
40 # include <dlfcn.h>
41 #endif
42
43 #ifndef PATH_MAX
44 #define PATH_MAX DEFAULT_PATH_MAX
45 #endif
46
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 #include <X11/keysym.h>
50
51 #include <wraster.h>
52
53 #include "WindowMaker.h"
54 #include "wcore.h"
55 #include "framewin.h"
56 #include "window.h"
57 #include "texture.h"
58 #include "screen.h"
59 #include "resources.h"
60 #include "defaults.h"
61 #include "keybind.h"
62 #include "xmodifier.h"
63 #include "icon.h"
64 #include "funcs.h"
65 #include "actions.h"
66 #include "dock.h"
67 #include "workspace.h"
68 #include "properties.h"
69
70 #define MAX_SHORTCUT_LENGTH 32
71
72 #ifndef GLOBAL_DEFAULTS_SUBDIR
73 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
74 #endif
75
76 /***** Global *****/
77
78 extern WDDomain *WDWindowMaker;
79 extern WDDomain *WDWindowAttributes;
80 extern WDDomain *WDRootMenu;
81
82 extern int wScreenCount;
83
84 extern Atom _XA_WINDOWMAKER_ICON_SIZE;
85 extern Atom _XA_WINDOWMAKER_ICON_TILE;
86
87 /*
88  extern WMPropList *wDomainName;
89  extern WMPropList *wAttributeDomainName;
90  */
91 extern WPreferences wPreferences;
92
93 extern WShortKey wKeyBindings[WKBD_LAST];
94
95 typedef struct {
96         char *key;
97         char *default_value;
98         void *extra_data;
99         void *addr;
100         int (*convert) ();
101         int (*update) ();
102         WMPropList *plkey;
103         WMPropList *plvalue;    /* default value */
104 } WDefaultEntry;
105
106 /* used to map strings to integers */
107 typedef struct {
108         char *string;
109         short value;
110         char is_alias;
111 } WOptionEnumeration;
112
113 /* type converters */
114 static int getBool();
115 static int getInt();
116 static int getCoord();
117 #if 0
118 /* this is not used yet */
119 static int getString();
120 #endif
121 static int getPathList();
122 static int getEnum();
123 static int getTexture();
124 static int getWSBackground();
125 static int getWSSpecificBackground();
126 static int getFont();
127 static int getColor();
128 static int getKeybind();
129 static int getModMask();
130 #ifdef NEWSTUFF
131 static int getRImage();
132 #endif
133 static int getPropList();
134
135 /* value setting functions */
136 static int setJustify();
137 static int setClearance();
138 static int setIfDockPresent();
139 static int setStickyIcons();
140 /*
141  static int setPositive();
142  */
143 static int setWidgetColor();
144 static int setIconTile();
145 static int setWinTitleFont();
146 static int setMenuTitleFont();
147 static int setMenuTextFont();
148 static int setIconTitleFont();
149 static int setIconTitleColor();
150 static int setIconTitleBack();
151 static int setLargeDisplayFont();
152 static int setWTitleColor();
153 static int setFTitleBack();
154 static int setPTitleBack();
155 static int setUTitleBack();
156 static int setResizebarBack();
157 static int setWorkspaceBack();
158 static int setWorkspaceSpecificBack();
159 #ifdef VIRTUAL_DESKTOP
160 static int setVirtualDeskEnable();
161 #endif
162 static int setMenuTitleColor();
163 static int setMenuTextColor();
164 static int setMenuDisabledColor();
165 static int setMenuTitleBack();
166 static int setMenuTextBack();
167 static int setHightlight();
168 static int setHightlightText();
169 static int setKeyGrab();
170 static int setDoubleClick();
171 static int setIconPosition();
172
173 static int setClipTitleFont();
174 static int setClipTitleColor();
175
176 static int setMenuStyle();
177 static int setSwPOptions();
178 static int updateUsableArea();
179
180 extern Cursor wCursor[WCUR_LAST];
181 static int getCursor();
182 static int setCursor();
183
184 /*
185  * Tables to convert strings to enumeration values.
186  * Values stored are char
187  */
188
189 /* WARNING: sum of length of all value strings must not exceed
190  * this value */
191 #define TOTAL_VALUES_LENGTH     80
192
193 #define REFRESH_WINDOW_TEXTURES (1<<0)
194 #define REFRESH_MENU_TEXTURE    (1<<1)
195 #define REFRESH_MENU_FONT       (1<<2)
196 #define REFRESH_MENU_COLOR      (1<<3)
197 #define REFRESH_MENU_TITLE_TEXTURE      (1<<4)
198 #define REFRESH_MENU_TITLE_FONT (1<<5)
199 #define REFRESH_MENU_TITLE_COLOR        (1<<6)
200 #define REFRESH_WINDOW_TITLE_COLOR (1<<7)
201 #define REFRESH_WINDOW_FONT     (1<<8)
202 #define REFRESH_ICON_TILE       (1<<9)
203 #define REFRESH_ICON_FONT       (1<<10)
204 #define REFRESH_WORKSPACE_BACK  (1<<11)
205
206 #define REFRESH_BUTTON_IMAGES   (1<<12)
207
208 #define REFRESH_ICON_TITLE_COLOR (1<<13)
209 #define REFRESH_ICON_TITLE_BACK (1<<14)
210
211 static WOptionEnumeration seFocusModes[] = {
212         {"Manual", WKF_CLICK, 0}, {"ClickToFocus", WKF_CLICK, 1},
213         {"Sloppy", WKF_SLOPPY, 0}, {"SemiAuto", WKF_SLOPPY, 1}, {"Auto", WKF_SLOPPY, 1},
214         {NULL, 0, 0}
215 };
216
217 static WOptionEnumeration seColormapModes[] = {
218         {"Manual", WCM_CLICK, 0}, {"ClickToFocus", WCM_CLICK, 1},
219         {"Auto", WCM_POINTER, 0}, {"FocusFollowMouse", WCM_POINTER, 1},
220         {NULL, 0, 0}
221 };
222
223 static WOptionEnumeration sePlacements[] = {
224         {"Auto", WPM_AUTO, 0},
225         {"Smart", WPM_SMART, 0},
226         {"Cascade", WPM_CASCADE, 0},
227         {"Random", WPM_RANDOM, 0},
228         {"Manual", WPM_MANUAL, 0},
229         {NULL, 0, 0}
230 };
231
232 static WOptionEnumeration seGeomDisplays[] = {
233         {"None", WDIS_NONE, 0},
234         {"Center", WDIS_CENTER, 0},
235         {"Corner", WDIS_TOPLEFT, 0},
236         {"Floating", WDIS_FRAME_CENTER, 0},
237         {"Line", WDIS_NEW, 0},
238         {NULL, 0, 0}
239 };
240
241 static WOptionEnumeration seSpeeds[] = {
242         {"UltraFast", SPEED_ULTRAFAST, 0},
243         {"Fast", SPEED_FAST, 0},
244         {"Medium", SPEED_MEDIUM, 0},
245         {"Slow", SPEED_SLOW, 0},
246         {"UltraSlow", SPEED_ULTRASLOW, 0},
247         {NULL, 0, 0}
248 };
249
250 static WOptionEnumeration seMouseButtonActions[] = {
251         {"None", WA_NONE, 0},
252         {"SelectWindows", WA_SELECT_WINDOWS, 0},
253         {"OpenApplicationsMenu", WA_OPEN_APPMENU, 0},
254         {"OpenWindowListMenu", WA_OPEN_WINLISTMENU, 0},
255         {NULL, 0, 0}
256 };
257
258 static WOptionEnumeration seMouseWheelActions[] = {
259         {"None", WA_NONE, 0},
260         {"SwitchWorkspaces", WA_SWITCH_WORKSPACES, 0},
261         {NULL, 0, 0}
262 };
263
264 static WOptionEnumeration seIconificationStyles[] = {
265         {"Zoom", WIS_ZOOM, 0},
266         {"Twist", WIS_TWIST, 0},
267         {"Flip", WIS_FLIP, 0},
268         {"None", WIS_NONE, 0},
269         {"random", WIS_RANDOM, 0},
270         {NULL, 0, 0}
271 };
272
273 static WOptionEnumeration seJustifications[] = {
274         {"Left", WTJ_LEFT, 0},
275         {"Center", WTJ_CENTER, 0},
276         {"Right", WTJ_RIGHT, 0},
277         {NULL, 0, 0}
278 };
279
280 static WOptionEnumeration seIconPositions[] = {
281         {"blv", IY_BOTTOM | IY_LEFT | IY_VERT, 0},
282         {"blh", IY_BOTTOM | IY_LEFT | IY_HORIZ, 0},
283         {"brv", IY_BOTTOM | IY_RIGHT | IY_VERT, 0},
284         {"brh", IY_BOTTOM | IY_RIGHT | IY_HORIZ, 0},
285         {"tlv", IY_TOP | IY_LEFT | IY_VERT, 0},
286         {"tlh", IY_TOP | IY_LEFT | IY_HORIZ, 0},
287         {"trv", IY_TOP | IY_RIGHT | IY_VERT, 0},
288         {"trh", IY_TOP | IY_RIGHT | IY_HORIZ, 0},
289         {NULL, 0, 0}
290 };
291
292 static WOptionEnumeration seMenuStyles[] = {
293         {"normal", MS_NORMAL, 0},
294         {"singletexture", MS_SINGLE_TEXTURE, 0},
295         {"flat", MS_FLAT, 0},
296         {NULL, 0, 0}
297 };
298
299 static WOptionEnumeration seDisplayPositions[] = {
300         {"none", WD_NONE, 0},
301         {"center", WD_CENTER, 0},
302         {"top", WD_TOP, 0},
303         {"bottom", WD_BOTTOM, 0},
304         {"topleft", WD_TOPLEFT, 0},
305         {"topright", WD_TOPRIGHT, 0},
306         {"bottomleft", WD_BOTTOMLEFT, 0},
307         {"bottomright", WD_BOTTOMRIGHT, 0},
308         {NULL, 0, 0}
309 };
310
311 static WOptionEnumeration seWorkspaceBorder[] = {
312         {"None", WB_NONE, 0},
313         {"LeftRight", WB_LEFTRIGHT, 0},
314         {"TopBottom", WB_TOPBOTTOM, 0},
315         {"AllDirections", WB_ALLDIRS, 0},
316         {NULL, 0, 0}
317 };
318
319 /*
320  * ALL entries in the tables bellow, NEED to have a default value
321  * defined, and this value needs to be correct.
322  */
323
324 /* these options will only affect the window manager on startup
325  *
326  * static defaults can't access the screen data, because it is
327  * created after these defaults are read
328  */
329 WDefaultEntry staticOptionList[] = {
330
331         {"ColormapSize", "4", NULL,
332          &wPreferences.cmap_size, getInt, NULL},
333         {"DisableDithering", "NO", NULL,
334          &wPreferences.no_dithering, getBool, NULL},
335         /* static by laziness */
336         {"IconSize", "64", NULL,
337          &wPreferences.icon_size, getInt, NULL},
338         {"ModifierKey", "Mod1", NULL,
339          &wPreferences.modifier_mask, getModMask, NULL},
340         {"DisableWSMouseActions", "NO", NULL,
341          &wPreferences.disable_root_mouse, getBool, NULL},
342         {"FocusMode", "manual", seFocusModes,
343          &wPreferences.focus_mode, getEnum, NULL},      /* have a problem when switching from manual to sloppy without restart */
344         {"NewStyle", "NO", NULL,
345          &wPreferences.new_style, getBool, NULL},
346         {"DisableDock", "NO", (void *)WM_DOCK,
347          NULL, getBool, setIfDockPresent},
348         {"DisableClip", "NO", (void *)WM_CLIP,
349          NULL, getBool, setIfDockPresent},
350         {"DisableMiniwindows", "NO", NULL,
351          &wPreferences.disable_miniwindows, getBool, NULL}
352 };
353
354 WDefaultEntry optionList[] = {
355         /* dynamic options */
356         {"IconPosition", "blh", seIconPositions,
357          &wPreferences.icon_yard, getEnum, setIconPosition},
358         {"IconificationStyle", "Zoom", seIconificationStyles,
359          &wPreferences.iconification_style, getEnum, NULL},
360         {"MouseLeftButtonAction", "SelectWindows", seMouseButtonActions,
361          &wPreferences.mouse_button1, getEnum, NULL},
362         {"MouseMiddleButtonAction", "OpenWindowListMenu", seMouseButtonActions,
363          &wPreferences.mouse_button2, getEnum, NULL},
364         {"MouseRightButtonAction", "OpenApplicationsMenu", seMouseButtonActions,
365          &wPreferences.mouse_button3, getEnum, NULL},
366         {"MouseWheelAction", "None", seMouseWheelActions,
367          &wPreferences.mouse_wheel, getEnum, NULL},
368         {"PixmapPath", DEF_PIXMAP_PATHS, NULL,
369          &wPreferences.pixmap_path, getPathList, NULL},
370         {"IconPath", DEF_ICON_PATHS, NULL,
371          &wPreferences.icon_path, getPathList, NULL},
372         {"ColormapMode", "auto", seColormapModes,
373          &wPreferences.colormap_mode, getEnum, NULL},
374         {"AutoFocus", "NO", NULL,
375          &wPreferences.auto_focus, getBool, NULL},
376         {"RaiseDelay", "0", NULL,
377          &wPreferences.raise_delay, getInt, NULL},
378         {"CirculateRaise", "NO", NULL,
379          &wPreferences.circ_raise, getBool, NULL},
380         {"Superfluous", "NO", NULL,
381          &wPreferences.superfluous, getBool, NULL},
382         {"AdvanceToNewWorkspace", "NO", NULL,
383          &wPreferences.ws_advance, getBool, NULL},
384         {"CycleWorkspaces", "NO", NULL,
385          &wPreferences.ws_cycle, getBool, NULL},
386         {"WorkspaceNameDisplayPosition", "center", seDisplayPositions,
387          &wPreferences.workspace_name_display_position, getEnum, NULL},
388         {"WorkspaceBorder", "None", seWorkspaceBorder,
389          &wPreferences.workspace_border_position, getEnum, updateUsableArea},
390         {"WorkspaceBorderSize", "0", NULL,
391          &wPreferences.workspace_border_size, getInt, updateUsableArea},
392 #ifdef VIRTUAL_DESKTOP
393         {"EnableVirtualDesktop", "NO", NULL,
394          &wPreferences.vdesk_enable, getBool, setVirtualDeskEnable},
395         {"VirtualEdgeExtendSpace", "0", NULL,
396          &wPreferences.vedge_bordersize, getInt, NULL},
397         {"VirtualEdgeHorizonScrollSpeed", "30", NULL,
398          &wPreferences.vedge_hscrollspeed, getInt, NULL},
399         {"VirtualEdgeVerticalScrollSpeed", "30", NULL,
400          &wPreferences.vedge_vscrollspeed, getInt, NULL},
401         {"VirtualEdgeResistance", "30", NULL,
402          &wPreferences.vedge_resistance, getInt, NULL},
403         {"VirtualEdgeAttraction", "30", NULL,
404          &wPreferences.vedge_attraction, getInt, NULL},
405         {"VirtualEdgeLeftKey", "None", (void *)WKBD_VDESK_LEFT,
406          NULL, getKeybind, setKeyGrab},
407         {"VirtualEdgeRightKey", "None", (void *)WKBD_VDESK_RIGHT,
408          NULL, getKeybind, setKeyGrab},
409         {"VirtualEdgeUpKey", "None", (void *)WKBD_VDESK_UP,
410          NULL, getKeybind, setKeyGrab},
411         {"VirtualEdgeDownKey", "None", (void *)WKBD_VDESK_DOWN,
412          NULL, getKeybind, setKeyGrab},
413 #endif
414         {"StickyIcons", "NO", NULL,
415          &wPreferences.sticky_icons, getBool, setStickyIcons},
416         {"SaveSessionOnExit", "NO", NULL,
417          &wPreferences.save_session_on_exit, getBool, NULL},
418         {"WrapMenus", "NO", NULL,
419          &wPreferences.wrap_menus, getBool, NULL},
420         {"ScrollableMenus", "NO", NULL,
421          &wPreferences.scrollable_menus, getBool, NULL},
422         {"MenuScrollSpeed", "medium", seSpeeds,
423          &wPreferences.menu_scroll_speed, getEnum, NULL},
424         {"IconSlideSpeed", "medium", seSpeeds,
425          &wPreferences.icon_slide_speed, getEnum, NULL},
426         {"ShadeSpeed", "medium", seSpeeds,
427          &wPreferences.shade_speed, getEnum, NULL},
428         {"DoubleClickTime", "250", (void *)&wPreferences.dblclick_time,
429          &wPreferences.dblclick_time, getInt, setDoubleClick,
430          },
431         {"AlignSubmenus", "NO", NULL,
432          &wPreferences.align_menus, getBool, NULL},
433         {"OpenTransientOnOwnerWorkspace", "NO", NULL,
434          &wPreferences.open_transients_with_parent, getBool, NULL},
435         {"WindowPlacement", "auto", sePlacements,
436          &wPreferences.window_placement, getEnum, NULL},
437         {"IgnoreFocusClick", "NO", NULL,
438          &wPreferences.ignore_focus_click, getBool, NULL},
439         {"UseSaveUnders", "NO", NULL,
440          &wPreferences.use_saveunders, getBool, NULL},
441         {"OpaqueMove", "NO", NULL,
442          &wPreferences.opaque_move, getBool, NULL},
443         {"DisableSound", "NO", NULL,
444          &wPreferences.no_sound, getBool, NULL},
445         {"DisableAnimations", "NO", NULL,
446          &wPreferences.no_animations, getBool, NULL},
447         {"DontLinkWorkspaces", "NO", NULL,
448          &wPreferences.no_autowrap, getBool, NULL},
449         {"AutoArrangeIcons", "NO", NULL,
450          &wPreferences.auto_arrange_icons, getBool, NULL},
451         {"NoWindowOverDock", "NO", NULL,
452          &wPreferences.no_window_over_dock, getBool, updateUsableArea},
453         {"NoWindowOverIcons", "NO", NULL,
454          &wPreferences.no_window_over_icons, getBool, updateUsableArea},
455         {"WindowPlaceOrigin", "(0, 0)", NULL,
456          &wPreferences.window_place_origin, getCoord, NULL},
457         {"ResizeDisplay", "corner", seGeomDisplays,
458          &wPreferences.size_display, getEnum, NULL},
459         {"MoveDisplay", "corner", seGeomDisplays,
460          &wPreferences.move_display, getEnum, NULL},
461         {"DontConfirmKill", "NO", NULL,
462          &wPreferences.dont_confirm_kill, getBool, NULL},
463         {"WindowTitleBalloons", "NO", NULL,
464          &wPreferences.window_balloon, getBool, NULL},
465         {"MiniwindowTitleBalloons", "NO", NULL,
466          &wPreferences.miniwin_balloon, getBool, NULL},
467         {"AppIconBalloons", "NO", NULL,
468          &wPreferences.appicon_balloon, getBool, NULL},
469         {"HelpBalloons", "NO", NULL,
470          &wPreferences.help_balloon, getBool, NULL},
471         {"EdgeResistance", "30", NULL,
472          &wPreferences.edge_resistance, getInt, NULL},
473         {"Attraction", "NO", NULL,
474          &wPreferences.attract, getBool, NULL},
475         {"DisableBlinking", "NO", NULL,
476          &wPreferences.dont_blink, getBool, NULL},
477         /* style options */
478         {"MenuStyle", "normal", seMenuStyles,
479          &wPreferences.menu_style, getEnum, setMenuStyle},
480         {"WidgetColor", "(solid, gray)", NULL,
481          NULL, getTexture, setWidgetColor,
482          },
483         {"WorkspaceSpecificBack", "()", NULL,
484          NULL, getWSSpecificBackground, setWorkspaceSpecificBack},
485         /* WorkspaceBack must come after WorkspaceSpecificBack or
486          * WorkspaceBack wont know WorkspaceSpecificBack was also
487          * specified and 2 copies of wmsetbg will be launched */
488         {"WorkspaceBack", "(solid, black)", NULL,
489          NULL, getWSBackground, setWorkspaceBack},
490         {"SmoothWorkspaceBack", "NO", NULL,
491          NULL, getBool, NULL},
492         {"IconBack", "(solid, gray)", NULL,
493          NULL, getTexture, setIconTile},
494         {"TitleJustify", "center", seJustifications,
495          &wPreferences.title_justification, getEnum, setJustify},
496         {"WindowTitleFont", DEF_TITLE_FONT, NULL,
497          NULL, getFont, setWinTitleFont,
498          },
499         {"WindowTitleExtendSpace", DEF_WINDOW_TITLE_EXTEND_SPACE, NULL,
500          &wPreferences.window_title_clearance, getInt, setClearance},
501         {"MenuTitleExtendSpace", DEF_MENU_TITLE_EXTEND_SPACE, NULL,
502          &wPreferences.menu_title_clearance, getInt, setClearance},
503         {"MenuTextExtendSpace", DEF_MENU_TEXT_EXTEND_SPACE, NULL,
504          &wPreferences.menu_text_clearance, getInt, setClearance},
505         {"MenuTitleFont", DEF_MENU_TITLE_FONT, NULL,
506          NULL, getFont, setMenuTitleFont},
507         {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL,
508          NULL, getFont, setMenuTextFont},
509         {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL,
510          NULL, getFont, setIconTitleFont},
511         {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL,
512          NULL, getFont, setClipTitleFont},
513         {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL,
514          NULL, getFont, setLargeDisplayFont},
515         {"HighlightColor", "white", NULL,
516          NULL, getColor, setHightlight},
517         {"HighlightTextColor", "black", NULL,
518          NULL, getColor, setHightlightText},
519         {"ClipTitleColor", "black", (void *)CLIP_NORMAL,
520          NULL, getColor, setClipTitleColor},
521         {"CClipTitleColor", "\"#454045\"", (void *)CLIP_COLLAPSED,
522          NULL, getColor, setClipTitleColor},
523         {"FTitleColor", "white", (void *)WS_FOCUSED,
524          NULL, getColor, setWTitleColor},
525         {"PTitleColor", "white", (void *)WS_PFOCUSED,
526          NULL, getColor, setWTitleColor},
527         {"UTitleColor", "black", (void *)WS_UNFOCUSED,
528          NULL, getColor, setWTitleColor},
529         {"FTitleBack", "(solid, black)", NULL,
530          NULL, getTexture, setFTitleBack},
531         {"PTitleBack", "(solid, \"#616161\")", NULL,
532          NULL, getTexture, setPTitleBack},
533         {"UTitleBack", "(solid, gray)", NULL,
534          NULL, getTexture, setUTitleBack},
535         {"ResizebarBack", "(solid, gray)", NULL,
536          NULL, getTexture, setResizebarBack},
537         {"MenuTitleColor", "white", NULL,
538          NULL, getColor, setMenuTitleColor},
539         {"MenuTextColor", "black", NULL,
540          NULL, getColor, setMenuTextColor},
541         {"MenuDisabledColor", "\"#616161\"", NULL,
542          NULL, getColor, setMenuDisabledColor},
543         {"MenuTitleBack", "(solid, black)", NULL,
544          NULL, getTexture, setMenuTitleBack},
545         {"MenuTextBack", "(solid, gray)", NULL,
546          NULL, getTexture, setMenuTextBack},
547         {"IconTitleColor", "white", NULL,
548          NULL, getColor, setIconTitleColor},
549         {"IconTitleBack", "black", NULL,
550          NULL, getColor, setIconTitleBack},
551         {"SwitchPanelImages", "(swtile.png, swback.png, 30, 40)", &wPreferences,
552          NULL, getPropList, setSwPOptions},
553         /* keybindings */
554         {"RootMenuKey", "None", (void *)WKBD_ROOTMENU,
555          NULL, getKeybind, setKeyGrab},
556         {"WindowListKey", "None", (void *)WKBD_WINDOWLIST,
557          NULL, getKeybind, setKeyGrab},
558         {"WindowMenuKey", "None", (void *)WKBD_WINDOWMENU,
559          NULL, getKeybind, setKeyGrab},
560         {"ClipLowerKey", "None", (void *)WKBD_CLIPLOWER,
561          NULL, getKeybind, setKeyGrab},
562         {"ClipRaiseKey", "None", (void *)WKBD_CLIPRAISE,
563          NULL, getKeybind, setKeyGrab},
564         {"ClipRaiseLowerKey", "None", (void *)WKBD_CLIPRAISELOWER,
565          NULL, getKeybind, setKeyGrab},
566         {"MiniaturizeKey", "None", (void *)WKBD_MINIATURIZE,
567          NULL, getKeybind, setKeyGrab},
568         {"HideKey", "None", (void *)WKBD_HIDE,
569          NULL, getKeybind, setKeyGrab},
570         {"HideOthersKey", "None", (void *)WKBD_HIDE_OTHERS,
571          NULL, getKeybind, setKeyGrab},
572         {"MoveResizeKey", "None", (void *)WKBD_MOVERESIZE,
573          NULL, getKeybind, setKeyGrab},
574         {"CloseKey", "None", (void *)WKBD_CLOSE,
575          NULL, getKeybind, setKeyGrab},
576         {"MaximizeKey", "None", (void *)WKBD_MAXIMIZE,
577          NULL, getKeybind, setKeyGrab},
578         {"VMaximizeKey", "None", (void *)WKBD_VMAXIMIZE,
579          NULL, getKeybind, setKeyGrab},
580         {"HMaximizeKey", "None", (void *)WKBD_HMAXIMIZE,
581          NULL, getKeybind, setKeyGrab},
582         {"LHMaximizeKey", "None", (void*)WKBD_LHMAXIMIZE,
583          NULL, getKeybind, setKeyGrab},
584         {"RHMaximizeKey", "None", (void*)WKBD_RHMAXIMIZE,
585          NULL, getKeybind, setKeyGrab},
586         {"MaximusKey", "None", (void*)WKBD_MAXIMUS,
587          NULL, getKeybind, setKeyGrab},
588         {"RaiseKey", "\"Meta+Up\"", (void *)WKBD_RAISE,
589          NULL, getKeybind, setKeyGrab},
590         {"LowerKey", "\"Meta+Down\"", (void *)WKBD_LOWER,
591          NULL, getKeybind, setKeyGrab},
592         {"RaiseLowerKey", "None", (void *)WKBD_RAISELOWER,
593          NULL, getKeybind, setKeyGrab},
594         {"ShadeKey", "None", (void *)WKBD_SHADE,
595          NULL, getKeybind, setKeyGrab},
596         {"SelectKey", "None", (void *)WKBD_SELECT,
597          NULL, getKeybind, setKeyGrab},
598         {"FocusNextKey", "None", (void *)WKBD_FOCUSNEXT,
599          NULL, getKeybind, setKeyGrab},
600         {"FocusPrevKey", "None", (void *)WKBD_FOCUSPREV,
601          NULL, getKeybind, setKeyGrab},
602         {"NextWorkspaceKey", "None", (void *)WKBD_NEXTWORKSPACE,
603          NULL, getKeybind, setKeyGrab},
604         {"PrevWorkspaceKey", "None", (void *)WKBD_PREVWORKSPACE,
605          NULL, getKeybind, setKeyGrab},
606         {"NextWorkspaceLayerKey", "None", (void *)WKBD_NEXTWSLAYER,
607          NULL, getKeybind, setKeyGrab},
608         {"PrevWorkspaceLayerKey", "None", (void *)WKBD_PREVWSLAYER,
609          NULL, getKeybind, setKeyGrab},
610         {"Workspace1Key", "None", (void *)WKBD_WORKSPACE1,
611          NULL, getKeybind, setKeyGrab},
612         {"Workspace2Key", "None", (void *)WKBD_WORKSPACE2,
613          NULL, getKeybind, setKeyGrab},
614         {"Workspace3Key", "None", (void *)WKBD_WORKSPACE3,
615          NULL, getKeybind, setKeyGrab},
616         {"Workspace4Key", "None", (void *)WKBD_WORKSPACE4,
617          NULL, getKeybind, setKeyGrab},
618         {"Workspace5Key", "None", (void *)WKBD_WORKSPACE5,
619          NULL, getKeybind, setKeyGrab},
620         {"Workspace6Key", "None", (void *)WKBD_WORKSPACE6,
621          NULL, getKeybind, setKeyGrab},
622         {"Workspace7Key", "None", (void *)WKBD_WORKSPACE7,
623          NULL, getKeybind, setKeyGrab},
624         {"Workspace8Key", "None", (void *)WKBD_WORKSPACE8,
625          NULL, getKeybind, setKeyGrab},
626         {"Workspace9Key", "None", (void *)WKBD_WORKSPACE9,
627          NULL, getKeybind, setKeyGrab},
628         {"Workspace10Key", "None", (void *)WKBD_WORKSPACE10,
629          NULL, getKeybind, setKeyGrab},
630         {"WindowShortcut1Key", "None", (void *)WKBD_WINDOW1,
631          NULL, getKeybind, setKeyGrab},
632         {"WindowShortcut2Key", "None", (void *)WKBD_WINDOW2,
633          NULL, getKeybind, setKeyGrab},
634         {"WindowShortcut3Key", "None", (void *)WKBD_WINDOW3,
635          NULL, getKeybind, setKeyGrab},
636         {"WindowShortcut4Key", "None", (void *)WKBD_WINDOW4,
637          NULL, getKeybind, setKeyGrab}
638         , {"WindowShortcut5Key", "None", (void *)WKBD_WINDOW5,
639            NULL, getKeybind, setKeyGrab},
640         {"WindowShortcut6Key", "None", (void *)WKBD_WINDOW6,
641          NULL, getKeybind, setKeyGrab},
642         {"WindowShortcut7Key", "None", (void *)WKBD_WINDOW7,
643          NULL, getKeybind, setKeyGrab},
644         {"WindowShortcut8Key", "None", (void *)WKBD_WINDOW8,
645          NULL, getKeybind, setKeyGrab},
646         {"WindowShortcut9Key", "None", (void *)WKBD_WINDOW9,
647          NULL, getKeybind, setKeyGrab},
648         {"WindowShortcut10Key", "None", (void *)WKBD_WINDOW10,
649          NULL, getKeybind, setKeyGrab},
650         {"ScreenSwitchKey", "None", (void *)WKBD_SWITCH_SCREEN,
651          NULL, getKeybind, setKeyGrab},
652
653 #ifdef KEEP_XKB_LOCK_STATUS
654         {"ToggleKbdModeKey", "None", (void *)WKBD_TOGGLE,
655          NULL, getKeybind, setKeyGrab},
656         {"KbdModeLock", "NO", NULL,
657          &wPreferences.modelock, getBool, NULL},
658 #endif                          /* KEEP_XKB_LOCK_STATUS */
659
660         {"NormalCursor", "(builtin, left_ptr)", (void *)WCUR_ROOT,
661          NULL, getCursor, setCursor},
662         {"ArrowCursor", "(builtin, top_left_arrow)", (void *)WCUR_ARROW,
663          NULL, getCursor, setCursor},
664         {"MoveCursor", "(builtin, fleur)", (void *)WCUR_MOVE,
665          NULL, getCursor, setCursor},
666         {"ResizeCursor", "(builtin, sizing)", (void *)WCUR_RESIZE,
667          NULL, getCursor, setCursor},
668         {"TopLeftResizeCursor", "(builtin, top_left_corner)",
669          (void *)WCUR_TOPLEFTRESIZE,
670          NULL, getCursor, setCursor},
671         {"TopRightResizeCursor", "(builtin, top_right_corner)",
672          (void *)WCUR_TOPRIGHTRESIZE,
673          NULL, getCursor, setCursor},
674         {"BottomLeftResizeCursor", "(builtin, bottom_left_corner)",
675          (void *)WCUR_BOTTOMLEFTRESIZE,
676          NULL, getCursor, setCursor},
677         {"BottomRightResizeCursor", "(builtin, bottom_right_corner)",
678          (void *)WCUR_BOTTOMRIGHTRESIZE,
679          NULL, getCursor, setCursor},
680         {"VerticalResizeCursor", "(builtin, sb_v_double_arrow)",
681          (void *)WCUR_VERTICALRESIZE,
682          NULL, getCursor, setCursor},
683         {"HorizontalResizeCursor", "(builtin, sb_h_double_arrow)",
684          (void *)WCUR_HORIZONRESIZE,
685          NULL, getCursor, setCursor},
686         {"WaitCursor", "(builtin, watch)", (void *)WCUR_WAIT,
687          NULL, getCursor, setCursor},
688         {"QuestionCursor", "(builtin, question_arrow)", (void *)WCUR_QUESTION,
689          NULL, getCursor, setCursor},
690         {"TextCursor", "(builtin, xterm)", (void *)WCUR_TEXT,
691          NULL, getCursor, setCursor},
692         {"SelectCursor", "(builtin, cross)", (void *)WCUR_SELECT,
693          NULL, getCursor, setCursor}
694 };
695
696 #if 0
697 static void rereadDefaults(void);
698 #endif
699
700 #if 0
701 static void rereadDefaults(void)
702 {
703         /* must defer the update because accessing X data from a
704          * signal handler can mess up Xlib */
705
706 }
707 #endif
708
709 static void initDefaults()
710 {
711         unsigned int i;
712         WDefaultEntry *entry;
713
714         WMPLSetCaseSensitive(False);
715
716         for (i = 0; i < sizeof(optionList) / sizeof(WDefaultEntry); i++) {
717                 entry = &optionList[i];
718
719                 entry->plkey = WMCreatePLString(entry->key);
720                 if (entry->default_value)
721                         entry->plvalue = WMCreatePropListFromDescription(entry->default_value);
722                 else
723                         entry->plvalue = NULL;
724         }
725
726         for (i = 0; i < sizeof(staticOptionList) / sizeof(WDefaultEntry); i++) {
727                 entry = &staticOptionList[i];
728
729                 entry->plkey = WMCreatePLString(entry->key);
730                 if (entry->default_value)
731                         entry->plvalue = WMCreatePropListFromDescription(entry->default_value);
732                 else
733                         entry->plvalue = NULL;
734         }
735
736         /*
737            wDomainName = WMCreatePLString(WMDOMAIN_NAME);
738            wAttributeDomainName = WMCreatePLString(WMATTRIBUTE_DOMAIN_NAME);
739
740            PLRegister(wDomainName, rereadDefaults);
741            PLRegister(wAttributeDomainName, rereadDefaults);
742          */
743 }
744
745 static WMPropList *readGlobalDomain(char *domainName, Bool requireDictionary)
746 {
747         WMPropList *globalDict = NULL;
748         char path[PATH_MAX];
749         struct stat stbuf;
750
751         snprintf(path, sizeof(path), "%s/%s/%s", SYSCONFDIR, GLOBAL_DEFAULTS_SUBDIR, domainName);
752         if (stat(path, &stbuf) >= 0) {
753                 globalDict = WMReadPropListFromFile(path);
754                 if (globalDict && requireDictionary && !WMIsPLDictionary(globalDict)) {
755                         wwarning(_("Domain %s (%s) of global defaults database is corrupted!"), domainName, path);
756                         WMReleasePropList(globalDict);
757                         globalDict = NULL;
758                 } else if (!globalDict) {
759                         wwarning(_("could not load domain %s from global defaults database"), domainName);
760                 }
761         }
762
763         return globalDict;
764 }
765
766 #if defined(GLOBAL_PREAMBLE_MENU_FILE) || defined(GLOBAL_EPILOGUE_MENU_FILE)
767 static void prependMenu(WMPropList * destarr, WMPropList * array)
768 {
769         WMPropList *item;
770         int i;
771
772         for (i = 0; i < WMGetPropListItemCount(array); i++) {
773                 item = WMGetFromPLArray(array, i);
774                 if (item)
775                         WMInsertInPLArray(destarr, i + 1, item);
776         }
777 }
778
779 static void appendMenu(WMPropList * destarr, WMPropList * array)
780 {
781         WMPropList *item;
782         int i;
783
784         for (i = 0; i < WMGetPropListItemCount(array); i++) {
785                 item = WMGetFromPLArray(array, i);
786                 if (item)
787                         WMAddToPLArray(destarr, item);
788         }
789 }
790 #endif
791
792 /* Fixup paths for cached pixmaps from .AppInfo to Library/WindowMaker/... */
793 static Bool fixupCachedPixmapsPaths(WMPropList * dict)
794 {
795         WMPropList *allApps, *app, *props, *iconkey, *icon, *newicon;
796         char *path, *fixedpath, *ptr, *search;
797         int i, len, slen;
798         Bool changed = False;
799
800         search = "/.AppInfo/WindowMaker/";
801         slen = strlen(search);
802
803         iconkey = WMCreatePLString("Icon");
804         allApps = WMGetPLDictionaryKeys(dict);
805
806         for (i = 0; i < WMGetPropListItemCount(allApps); i++) {
807                 app = WMGetFromPLArray(allApps, i);
808                 props = WMGetFromPLDictionary(dict, app);
809                 if (!props)
810                         continue;
811                 icon = WMGetFromPLDictionary(props, iconkey);
812                 if (icon && WMIsPLString(icon)) {
813                         path = WMGetFromPLString(icon);
814                         ptr = strstr(path, search);
815                         if (ptr) {
816                                 changed = True;
817                                 len = (ptr - path);
818                                 fixedpath = wmalloc(strlen(path) + 32);
819                                 strncpy(fixedpath, path, len);
820                                 fixedpath[len] = 0;
821                                 strcat(fixedpath, "/Library/WindowMaker/CachedPixmaps/");
822                                 strcat(fixedpath, ptr + slen);
823                                 newicon = WMCreatePLString(fixedpath);
824                                 WMPutInPLDictionary(props, iconkey, newicon);
825                                 WMReleasePropList(newicon);
826                                 wfree(fixedpath);
827                         }
828                 }
829         }
830
831         WMReleasePropList(allApps);
832         WMReleasePropList(iconkey);
833
834         return changed;
835 }
836
837 void wDefaultsMergeGlobalMenus(WDDomain * menuDomain)
838 {
839         WMPropList *menu = menuDomain->dictionary;
840         WMPropList *submenu;
841
842         if (!menu || !WMIsPLArray(menu))
843                 return;
844
845 #ifdef GLOBAL_PREAMBLE_MENU_FILE
846         submenu = WMReadPropListFromFile(SYSCONFDIR "/" GLOBAL_DEFAULTS_SUBDIR "/" GLOBAL_PREAMBLE_MENU_FILE);
847
848         if (submenu && !WMIsPLArray(submenu)) {
849                 wwarning(_("invalid global menu file %s"), GLOBAL_PREAMBLE_MENU_FILE);
850                 WMReleasePropList(submenu);
851                 submenu = NULL;
852         }
853         if (submenu) {
854                 prependMenu(menu, submenu);
855                 WMReleasePropList(submenu);
856         }
857 #endif
858
859 #ifdef GLOBAL_EPILOGUE_MENU_FILE
860         submenu = WMReadPropListFromFile(SYSCONFDIR "/" GLOBAL_DEFAULTS_SUBDIR "/" GLOBAL_EPILOGUE_MENU_FILE);
861
862         if (submenu && !WMIsPLArray(submenu)) {
863                 wwarning(_("invalid global menu file %s"), GLOBAL_EPILOGUE_MENU_FILE);
864                 WMReleasePropList(submenu);
865                 submenu = NULL;
866         }
867         if (submenu) {
868                 appendMenu(menu, submenu);
869                 WMReleasePropList(submenu);
870         }
871 #endif
872
873         menuDomain->dictionary = menu;
874 }
875
876 #if 0
877 WMPropList *wDefaultsInit(int screen_number)
878 {
879         static int defaults_inited = 0;
880         WMPropList *dict;
881
882         if (!defaults_inited) {
883                 initDefaults();
884         }
885
886         dict = PLGetDomain(wDomainName);
887         if (!dict) {
888                 wwarning(_("could not read domain \"%s\" from defaults database"), WMGetFromPLString(wDomainName));
889         }
890
891         return dict;
892 }
893 #endif
894
895 void wDefaultsDestroyDomain(WDDomain * domain)
896 {
897         if (domain->dictionary)
898                 WMReleasePropList(domain->dictionary);
899         wfree(domain->path);
900         wfree(domain);
901 }
902
903 WDDomain *wDefaultsInitDomain(char *domain, Bool requireDictionary)
904 {
905         WDDomain *db;
906         struct stat stbuf;
907         static int inited = 0;
908         char path[PATH_MAX];
909         char *the_path;
910         WMPropList *shared_dict = NULL;
911
912         if (!inited) {
913                 inited = 1;
914                 initDefaults();
915         }
916
917         db = wmalloc(sizeof(WDDomain));
918         memset(db, 0, sizeof(WDDomain));
919         db->domain_name = domain;
920         db->path = wdefaultspathfordomain(domain);
921         the_path = db->path;
922
923         if (the_path && stat(the_path, &stbuf) >= 0) {
924                 db->dictionary = WMReadPropListFromFile(the_path);
925                 if (db->dictionary) {
926                         if (requireDictionary && !WMIsPLDictionary(db->dictionary)) {
927                                 WMReleasePropList(db->dictionary);
928                                 db->dictionary = NULL;
929                                 wwarning(_("Domain %s (%s) of defaults database is corrupted!"), domain, the_path);
930                         }
931                         if (strcmp(domain, "WMWindowAttributes") == 0 && db->dictionary) {
932                                 if (fixupCachedPixmapsPaths(db->dictionary)) {
933                                         WMWritePropListToFile(db->dictionary, db->path, True);
934                                         /* re-read the timestamp. if this fails take current time */
935                                         if (stat(db->path, &stbuf) < 0) {
936                                                 stbuf.st_mtime = time(NULL);
937                                         }
938                                 }
939                         }
940                         db->timestamp = stbuf.st_mtime;
941                 } else {
942                         wwarning(_("could not load domain %s from user defaults database"), domain);
943                 }
944         }
945
946         /* global system dictionary */
947         snprintf(path, sizeof(path), "%s/%s/%s", SYSCONFDIR, GLOBAL_DEFAULTS_SUBDIR, domain);
948         if (stat(path, &stbuf) >= 0) {
949                 shared_dict = WMReadPropListFromFile(path);
950                 if (shared_dict) {
951                         if (requireDictionary && !WMIsPLDictionary(shared_dict)) {
952                                 wwarning(_("Domain %s (%s) of global defaults database is corrupted!"),
953                                          domain, path);
954                                 WMReleasePropList(shared_dict);
955                                 shared_dict = NULL;
956                         } else {
957                                 if (db->dictionary && WMIsPLDictionary(shared_dict) &&
958                                     WMIsPLDictionary(db->dictionary)) {
959                                         WMMergePLDictionaries(shared_dict, db->dictionary, True);
960                                         WMReleasePropList(db->dictionary);
961                                         db->dictionary = shared_dict;
962                                         if (stbuf.st_mtime > db->timestamp)
963                                                 db->timestamp = stbuf.st_mtime;
964                                 } else if (!db->dictionary) {
965                                         db->dictionary = shared_dict;
966                                         if (stbuf.st_mtime > db->timestamp)
967                                                 db->timestamp = stbuf.st_mtime;
968                                 }
969                         }
970                 } else {
971                         wwarning(_("could not load domain %s from global defaults database (%s)"), domain, path);
972                 }
973         }
974
975         return db;
976 }
977
978 void wReadStaticDefaults(WMPropList * dict)
979 {
980         WMPropList *plvalue;
981         WDefaultEntry *entry;
982         unsigned int i;
983         void *tdata;
984
985         for (i = 0; i < sizeof(staticOptionList) / sizeof(WDefaultEntry); i++) {
986                 entry = &staticOptionList[i];
987
988                 if (dict)
989                         plvalue = WMGetFromPLDictionary(dict, entry->plkey);
990                 else
991                         plvalue = NULL;
992
993                 if (!plvalue) {
994                         /* no default in the DB. Use builtin default */
995                         plvalue = entry->plvalue;
996                 }
997
998                 if (plvalue) {
999                         /* convert data */
1000                         (*entry->convert) (NULL, entry, plvalue, entry->addr, &tdata);
1001                         if (entry->update) {
1002                                 (*entry->update) (NULL, entry, tdata, entry->extra_data);
1003                         }
1004                 }
1005         }
1006 }
1007
1008 void wDefaultsCheckDomains(void)
1009 {
1010         WScreen *scr;
1011         struct stat stbuf;
1012         WMPropList *shared_dict = NULL;
1013         WMPropList *dict;
1014         int i;
1015
1016 #ifdef HEARTBEAT
1017         puts("Checking domains...");
1018 #endif
1019         if (stat(WDWindowMaker->path, &stbuf) >= 0 && WDWindowMaker->timestamp < stbuf.st_mtime) {
1020 #ifdef HEARTBEAT
1021                 puts("Checking WindowMaker domain");
1022 #endif
1023                 WDWindowMaker->timestamp = stbuf.st_mtime;
1024
1025                 /* global dictionary */
1026                 shared_dict = readGlobalDomain("WindowMaker", True);
1027                 /* user dictionary */
1028                 dict = WMReadPropListFromFile(WDWindowMaker->path);
1029                 if (dict) {
1030                         if (!WMIsPLDictionary(dict)) {
1031                                 WMReleasePropList(dict);
1032                                 dict = NULL;
1033                                 wwarning(_("Domain %s (%s) of defaults database is corrupted!"),
1034                                          "WindowMaker", WDWindowMaker->path);
1035                         } else {
1036                                 if (shared_dict) {
1037                                         WMMergePLDictionaries(shared_dict, dict, True);
1038                                         WMReleasePropList(dict);
1039                                         dict = shared_dict;
1040                                         shared_dict = NULL;
1041                                 }
1042                                 for (i = 0; i < wScreenCount; i++) {
1043                                         scr = wScreenWithNumber(i);
1044                                         if (scr)
1045                                                 wReadDefaults(scr, dict);
1046                                 }
1047                                 if (WDWindowMaker->dictionary) {
1048                                         WMReleasePropList(WDWindowMaker->dictionary);
1049                                 }
1050                                 WDWindowMaker->dictionary = dict;
1051                         }
1052                 } else {
1053                         wwarning(_("could not load domain %s from user defaults database"), "WindowMaker");
1054                 }
1055                 if (shared_dict) {
1056                         WMReleasePropList(shared_dict);
1057                 }
1058         }
1059
1060         if (stat(WDWindowAttributes->path, &stbuf) >= 0 && WDWindowAttributes->timestamp < stbuf.st_mtime) {
1061 #ifdef HEARTBEAT
1062                 puts("Checking WMWindowAttributes domain");
1063 #endif
1064                 /* global dictionary */
1065                 shared_dict = readGlobalDomain("WMWindowAttributes", True);
1066                 /* user dictionary */
1067                 dict = WMReadPropListFromFile(WDWindowAttributes->path);
1068                 if (dict) {
1069                         if (!WMIsPLDictionary(dict)) {
1070                                 WMReleasePropList(dict);
1071                                 dict = NULL;
1072                                 wwarning(_("Domain %s (%s) of defaults database is corrupted!"),
1073                                          "WMWindowAttributes", WDWindowAttributes->path);
1074                         } else {
1075                                 if (shared_dict) {
1076                                         WMMergePLDictionaries(shared_dict, dict, True);
1077                                         WMReleasePropList(dict);
1078                                         dict = shared_dict;
1079                                         shared_dict = NULL;
1080                                 }
1081                                 if (WDWindowAttributes->dictionary) {
1082                                         WMReleasePropList(WDWindowAttributes->dictionary);
1083                                 }
1084                                 WDWindowAttributes->dictionary = dict;
1085                                 for (i = 0; i < wScreenCount; i++) {
1086                                         scr = wScreenWithNumber(i);
1087                                         if (scr) {
1088                                                 RImage *image;
1089
1090                                                 wDefaultUpdateIcons(scr);
1091
1092                                                 /* Update the panel image if changed */
1093                                                 /* Don't worry. If the image is the same these
1094                                                  * functions will have no performance impact. */
1095                                                 image = wDefaultGetImage(scr, "Logo", "WMPanel");
1096
1097                                                 if (!image) {
1098                                                         wwarning(_("could not load logo image for panels: %s"),
1099                                                                  RMessageForError(RErrorCode));
1100                                                 } else {
1101                                                         WMSetApplicationIconImage(scr->wmscreen, image);
1102                                                         RReleaseImage(image);
1103                                                 }
1104                                         }
1105                                 }
1106                         }
1107                 } else {
1108                         wwarning(_("could not load domain %s from user defaults database"), "WMWindowAttributes");
1109                 }
1110                 WDWindowAttributes->timestamp = stbuf.st_mtime;
1111                 if (shared_dict) {
1112                         WMReleasePropList(shared_dict);
1113                 }
1114         }
1115
1116         if (stat(WDRootMenu->path, &stbuf) >= 0 && WDRootMenu->timestamp < stbuf.st_mtime) {
1117                 dict = WMReadPropListFromFile(WDRootMenu->path);
1118 #ifdef HEARTBEAT
1119                 puts("Checking WMRootMenu domain");
1120 #endif
1121                 if (dict) {
1122                         if (!WMIsPLArray(dict) && !WMIsPLString(dict)) {
1123                                 WMReleasePropList(dict);
1124                                 dict = NULL;
1125                                 wwarning(_("Domain %s (%s) of defaults database is corrupted!"),
1126                                          "WMRootMenu", WDRootMenu->path);
1127                         } else {
1128                                 if (WDRootMenu->dictionary) {
1129                                         WMReleasePropList(WDRootMenu->dictionary);
1130                                 }
1131                                 WDRootMenu->dictionary = dict;
1132                                 wDefaultsMergeGlobalMenus(WDRootMenu);
1133                         }
1134                 } else {
1135                         wwarning(_("could not load domain %s from user defaults database"), "WMRootMenu");
1136                 }
1137                 WDRootMenu->timestamp = stbuf.st_mtime;
1138         }
1139 }
1140
1141 void wReadDefaults(WScreen * scr, WMPropList * new_dict)
1142 {
1143         WMPropList *plvalue, *old_value;
1144         WDefaultEntry *entry;
1145         unsigned int i, must_update;
1146         int update_workspace_back = 0;  /* kluge :/ */
1147         unsigned int needs_refresh;
1148         void *tdata;
1149         WMPropList *old_dict = (WDWindowMaker->dictionary != new_dict ? WDWindowMaker->dictionary : NULL);
1150
1151         must_update = 0;
1152
1153         needs_refresh = 0;
1154
1155         for (i = 0; i < sizeof(optionList) / sizeof(WDefaultEntry); i++) {
1156                 entry = &optionList[i];
1157
1158                 if (new_dict)
1159                         plvalue = WMGetFromPLDictionary(new_dict, entry->plkey);
1160                 else
1161                         plvalue = NULL;
1162
1163                 if (!old_dict)
1164                         old_value = NULL;
1165                 else
1166                         old_value = WMGetFromPLDictionary(old_dict, entry->plkey);
1167
1168                 if (!plvalue && !old_value) {
1169                         /* no default in  the DB. Use builtin default */
1170                         plvalue = entry->plvalue;
1171                         if (plvalue && new_dict) {
1172                                 WMPutInPLDictionary(new_dict, entry->plkey, plvalue);
1173                                 must_update = 1;
1174                         }
1175                 } else if (!plvalue) {
1176                         /* value was deleted from DB. Keep current value */
1177                         continue;
1178                 } else if (!old_value) {
1179                         /* set value for the 1st time */
1180                 } else if (!WMIsPropListEqualTo(plvalue, old_value)) {
1181                         /* value has changed */
1182                 } else {
1183
1184                         if (strcmp(entry->key, "WorkspaceBack") == 0
1185                             && update_workspace_back && scr->flags.backimage_helper_launched) {
1186                         } else {
1187                                 /* value was not changed since last time */
1188                                 continue;
1189                         }
1190                 }
1191
1192                 if (plvalue) {
1193 #ifdef DEBUG
1194                         printf("Updating %s to %s\n", entry->key, WMGetPropListDescription(plvalue, False));
1195 #endif
1196                         /* convert data */
1197                         if ((*entry->convert) (scr, entry, plvalue, entry->addr, &tdata)) {
1198                                 /*
1199                                  * If the WorkspaceSpecificBack data has been changed
1200                                  * so that the helper will be launched now, we must be
1201                                  * sure to send the default background texture config
1202                                  * to the helper.
1203                                  */
1204                                 if (strcmp(entry->key, "WorkspaceSpecificBack") == 0
1205                                     && !scr->flags.backimage_helper_launched) {
1206                                         update_workspace_back = 1;
1207                                 }
1208                                 if (entry->update) {
1209                                         needs_refresh |= (*entry->update) (scr, entry, tdata, entry->extra_data);
1210                                 }
1211                         }
1212                 }
1213         }
1214
1215         if (needs_refresh != 0 && !scr->flags.startup) {
1216                 int foo;
1217
1218                 foo = 0;
1219                 if (needs_refresh & REFRESH_MENU_TITLE_TEXTURE)
1220                         foo |= WTextureSettings;
1221                 if (needs_refresh & REFRESH_MENU_TITLE_FONT)
1222                         foo |= WFontSettings;
1223                 if (needs_refresh & REFRESH_MENU_TITLE_COLOR)
1224                         foo |= WColorSettings;
1225                 if (foo)
1226                         WMPostNotificationName(WNMenuTitleAppearanceSettingsChanged, NULL,
1227                                                (void *)(uintptr_t) foo);
1228
1229                 foo = 0;
1230                 if (needs_refresh & REFRESH_MENU_TEXTURE)
1231                         foo |= WTextureSettings;
1232                 if (needs_refresh & REFRESH_MENU_FONT)
1233                         foo |= WFontSettings;
1234                 if (needs_refresh & REFRESH_MENU_COLOR)
1235                         foo |= WColorSettings;
1236                 if (foo)
1237                         WMPostNotificationName(WNMenuAppearanceSettingsChanged, NULL, (void *)(uintptr_t) foo);
1238
1239                 foo = 0;
1240                 if (needs_refresh & REFRESH_WINDOW_FONT) {
1241                         foo |= WFontSettings;
1242                 }
1243                 if (needs_refresh & REFRESH_WINDOW_TEXTURES) {
1244                         foo |= WTextureSettings;
1245                 }
1246                 if (needs_refresh & REFRESH_WINDOW_TITLE_COLOR) {
1247                         foo |= WColorSettings;
1248                 }
1249                 if (foo)
1250                         WMPostNotificationName(WNWindowAppearanceSettingsChanged, NULL, (void *)(uintptr_t) foo);
1251
1252                 if (!(needs_refresh & REFRESH_ICON_TILE)) {
1253                         foo = 0;
1254                         if (needs_refresh & REFRESH_ICON_FONT) {
1255                                 foo |= WFontSettings;
1256                         }
1257                         if (needs_refresh & REFRESH_ICON_TITLE_COLOR) {
1258                                 foo |= WTextureSettings;
1259                         }
1260                         if (needs_refresh & REFRESH_ICON_TITLE_BACK) {
1261                                 foo |= WTextureSettings;
1262                         }
1263                         if (foo)
1264                                 WMPostNotificationName(WNIconAppearanceSettingsChanged, NULL,
1265                                                        (void *)(uintptr_t) foo);
1266                 }
1267                 if (needs_refresh & REFRESH_ICON_TILE)
1268                         WMPostNotificationName(WNIconTileSettingsChanged, NULL, NULL);
1269         }
1270 }
1271
1272 void wDefaultUpdateIcons(WScreen * scr)
1273 {
1274         WAppIcon *aicon = scr->app_icon_list;
1275         WWindow *wwin = scr->focused_window;
1276         char *file;
1277
1278         while (aicon) {
1279                 file = wDefaultGetIconFile(scr, aicon->wm_instance, aicon->wm_class, False);
1280                 if ((file && aicon->icon->file && strcmp(file, aicon->icon->file) != 0)
1281                     || (file && !aicon->icon->file)) {
1282                         RImage *new_image;
1283
1284                         if (aicon->icon->file)
1285                                 wfree(aicon->icon->file);
1286                         aicon->icon->file = wstrdup(file);
1287
1288                         new_image = wDefaultGetImage(scr, aicon->wm_instance, aicon->wm_class);
1289                         if (new_image) {
1290                                 wIconChangeImage(aicon->icon, new_image);
1291                                 wAppIconPaint(aicon);
1292                         }
1293                 }
1294                 aicon = aicon->next;
1295         }
1296
1297         if (!wPreferences.flags.noclip)
1298                 wClipIconPaint(scr->clip_icon);
1299
1300         while (wwin) {
1301                 if (wwin->icon && wwin->flags.miniaturized) {
1302                         file = wDefaultGetIconFile(scr, wwin->wm_instance, wwin->wm_class, False);
1303                         if ((file && wwin->icon->file && strcmp(file, wwin->icon->file) != 0)
1304                             || (file && !wwin->icon->file)) {
1305                                 RImage *new_image;
1306
1307                                 if (wwin->icon->file)
1308                                         wfree(wwin->icon->file);
1309                                 wwin->icon->file = wstrdup(file);
1310
1311                                 new_image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class);
1312                                 if (new_image)
1313                                         wIconChangeImage(wwin->icon, new_image);
1314                         }
1315                 }
1316                 wwin = wwin->prev;
1317         }
1318 }
1319
1320 /* --------------------------- Local ----------------------- */
1321
1322 #define GET_STRING_OR_DEFAULT(x, var) if (!WMIsPLString(value)) { \
1323     wwarning(_("Wrong option format for key \"%s\". Should be %s."), \
1324     entry->key, x); \
1325     wwarning(_("using default \"%s\" instead"), entry->default_value); \
1326     var = entry->default_value;\
1327     } else var = WMGetFromPLString(value)\
1328
1329
1330 static int string2index(WMPropList * key, WMPropList * val, char *def, WOptionEnumeration * values)
1331 {
1332         char *str;
1333         WOptionEnumeration *v;
1334         char buffer[TOTAL_VALUES_LENGTH];
1335
1336         if (WMIsPLString(val) && (str = WMGetFromPLString(val))) {
1337                 for (v = values; v->string != NULL; v++) {
1338                         if (strcasecmp(v->string, str) == 0)
1339                                 return v->value;
1340                 }
1341         }
1342
1343         buffer[0] = 0;
1344         for (v = values; v->string != NULL; v++) {
1345                 if (!v->is_alias) {
1346                         if (buffer[0] != 0)
1347                                 strcat(buffer, ", ");
1348                         strcat(buffer, v->string);
1349                 }
1350         }
1351         wwarning(_("wrong option value for key \"%s\". Should be one of %s"), WMGetFromPLString(key), buffer);
1352
1353         if (def) {
1354                 return string2index(key, val, NULL, values);
1355         }
1356
1357         return -1;
1358 }
1359
1360 /*
1361  * value - is the value in the defaults DB
1362  * addr - is the address to store the data
1363  * ret - is the address to store a pointer to a temporary buffer. ret
1364  *      must not be freed and is used by the set functions
1365  */
1366 static int getBool(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1367 {
1368         static char data;
1369         char *val;
1370         int second_pass = 0;
1371
1372         GET_STRING_OR_DEFAULT("Boolean", val);
1373
1374  again:
1375         if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
1376             || strcasecmp(val, "YES") == 0) {
1377
1378                 data = 1;
1379         } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
1380                    || strcasecmp(val, "NO") == 0) {
1381                 data = 0;
1382         } else {
1383                 int i;
1384                 if (sscanf(val, "%i", &i) == 1) {
1385                         if (i != 0)
1386                                 data = 1;
1387                         else
1388                                 data = 0;
1389                 } else {
1390                         wwarning(_("can't convert \"%s\" to boolean for key \"%s\""), val, entry->key);
1391                         if (second_pass == 0) {
1392                                 val = WMGetFromPLString(entry->plvalue);
1393                                 second_pass = 1;
1394                                 wwarning(_("using default \"%s\" instead"), val);
1395                                 goto again;
1396                         }
1397                         return False;
1398                 }
1399         }
1400
1401         if (ret)
1402                 *ret = &data;
1403         if (addr)
1404                 *(char *)addr = data;
1405
1406         return True;
1407 }
1408
1409 static int getInt(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1410 {
1411         static int data;
1412         char *val;
1413
1414         GET_STRING_OR_DEFAULT("Integer", val);
1415
1416         if (sscanf(val, "%i", &data) != 1) {
1417                 wwarning(_("can't convert \"%s\" to integer for key \"%s\""), val, entry->key);
1418                 val = WMGetFromPLString(entry->plvalue);
1419                 wwarning(_("using default \"%s\" instead"), val);
1420                 if (sscanf(val, "%i", &data) != 1) {
1421                         return False;
1422                 }
1423         }
1424
1425         if (ret)
1426                 *ret = &data;
1427         if (addr)
1428                 *(int *)addr = data;
1429
1430         return True;
1431 }
1432
1433 static int getCoord(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1434 {
1435         static WCoord data;
1436         char *val_x, *val_y;
1437         int nelem, changed = 0;
1438         WMPropList *elem_x, *elem_y;
1439
1440  again:
1441         if (!WMIsPLArray(value)) {
1442                 wwarning(_("Wrong option format for key \"%s\". Should be %s."), entry->key, "Coordinate");
1443                 if (changed == 0) {
1444                         value = entry->plvalue;
1445                         changed = 1;
1446                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1447                         goto again;
1448                 }
1449                 return False;
1450         }
1451
1452         nelem = WMGetPropListItemCount(value);
1453         if (nelem != 2) {
1454                 wwarning(_("Incorrect number of elements in array for key \"%s\"."), entry->key);
1455                 if (changed == 0) {
1456                         value = entry->plvalue;
1457                         changed = 1;
1458                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1459                         goto again;
1460                 }
1461                 return False;
1462         }
1463
1464         elem_x = WMGetFromPLArray(value, 0);
1465         elem_y = WMGetFromPLArray(value, 1);
1466
1467         if (!elem_x || !elem_y || !WMIsPLString(elem_x) || !WMIsPLString(elem_y)) {
1468                 wwarning(_("Wrong value for key \"%s\". Should be Coordinate."), entry->key);
1469                 if (changed == 0) {
1470                         value = entry->plvalue;
1471                         changed = 1;
1472                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1473                         goto again;
1474                 }
1475                 return False;
1476         }
1477
1478         val_x = WMGetFromPLString(elem_x);
1479         val_y = WMGetFromPLString(elem_y);
1480
1481         if (sscanf(val_x, "%i", &data.x) != 1 || sscanf(val_y, "%i", &data.y) != 1) {
1482                 wwarning(_("can't convert array to integers for \"%s\"."), entry->key);
1483                 if (changed == 0) {
1484                         value = entry->plvalue;
1485                         changed = 1;
1486                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1487                         goto again;
1488                 }
1489                 return False;
1490         }
1491
1492         if (data.x < 0)
1493                 data.x = 0;
1494         else if (data.x > scr->scr_width / 3)
1495                 data.x = scr->scr_width / 3;
1496         if (data.y < 0)
1497                 data.y = 0;
1498         else if (data.y > scr->scr_height / 3)
1499                 data.y = scr->scr_height / 3;
1500
1501         if (ret)
1502                 *ret = &data;
1503         if (addr)
1504                 *(WCoord *) addr = data;
1505
1506         return True;
1507 }
1508
1509 static int getPropList(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1510 {
1511         WMRetainPropList(value);
1512
1513         *ret = value;
1514
1515         return True;
1516 }
1517
1518 #if 0
1519 /* This function is not used at the moment. */
1520 static int getString(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1521 {
1522         static char *data;
1523
1524         GET_STRING_OR_DEFAULT("String", data);
1525
1526         if (!data) {
1527                 data = WMGetFromPLString(entry->plvalue);
1528                 if (!data)
1529                         return False;
1530         }
1531
1532         if (ret)
1533                 *ret = &data;
1534         if (addr)
1535                 *(char **)addr = wstrdup(data);
1536
1537         return True;
1538 }
1539 #endif
1540
1541 static int getPathList(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1542 {
1543         static char *data;
1544         int i, count, len;
1545         char *ptr;
1546         WMPropList *d;
1547         int changed = 0;
1548
1549  again:
1550         if (!WMIsPLArray(value)) {
1551                 wwarning(_("Wrong option format for key \"%s\". Should be %s."), entry->key, "an array of paths");
1552                 if (changed == 0) {
1553                         value = entry->plvalue;
1554                         changed = 1;
1555                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1556                         goto again;
1557                 }
1558                 return False;
1559         }
1560
1561         i = 0;
1562         count = WMGetPropListItemCount(value);
1563         if (count < 1) {
1564                 if (changed == 0) {
1565                         value = entry->plvalue;
1566                         changed = 1;
1567                         wwarning(_("using default \"%s\" instead"), entry->default_value);
1568                         goto again;
1569                 }
1570                 return False;
1571         }
1572
1573         len = 0;
1574         for (i = 0; i < count; i++) {
1575                 d = WMGetFromPLArray(value, i);
1576                 if (!d || !WMIsPLString(d)) {
1577                         count = i;
1578                         break;
1579                 }
1580                 len += strlen(WMGetFromPLString(d)) + 1;
1581         }
1582
1583         ptr = data = wmalloc(len + 1);
1584
1585         for (i = 0; i < count; i++) {
1586                 d = WMGetFromPLArray(value, i);
1587                 if (!d || !WMIsPLString(d)) {
1588                         break;
1589                 }
1590                 strcpy(ptr, WMGetFromPLString(d));
1591                 ptr += strlen(WMGetFromPLString(d));
1592                 *ptr = ':';
1593                 ptr++;
1594         }
1595         ptr--;
1596         *(ptr--) = 0;
1597
1598         if (*(char **)addr != NULL) {
1599                 wfree(*(char **)addr);
1600         }
1601         *(char **)addr = data;
1602
1603         return True;
1604 }
1605
1606 static int getEnum(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
1607 {
1608         static signed char data;
1609
1610         data = string2index(entry->plkey, value, entry->default_value, (WOptionEnumeration *) entry->extra_data);
1611         if (data < 0)
1612                 return False;
1613
1614         if (ret)
1615                 *ret = &data;
1616         if (addr)
1617                 *(signed char *)addr = data;
1618
1619         return True;
1620 }
1621
1622 /*
1623  * (solid <color>)
1624  * (hgradient <color> <color>)
1625  * (vgradient <color> <color>)
1626  * (dgradient <color> <color>)
1627  * (mhgradient <color> <color> ...)
1628  * (mvgradient <color> <color> ...)
1629  * (mdgradient <color> <color> ...)
1630  * (igradient <color1> <color1> <thickness1> <color2> <color2> <thickness2>)
1631  * (tpixmap <file> <color>)
1632  * (spixmap <file> <color>)
1633  * (cpixmap <file> <color>)
1634  * (thgradient <file> <opaqueness> <color> <color>)
1635  * (tvgradient <file> <opaqueness> <color> <color>)
1636  * (tdgradient <file> <opaqueness> <color> <color>)
1637  * (function <lib> <function> ...)
1638  */
1639
1640 static WTexture *parse_texture(WScreen * scr, WMPropList * pl)
1641 {
1642         WMPropList *elem;
1643         char *val;
1644         int nelem;
1645         WTexture *texture = NULL;
1646
1647         nelem = WMGetPropListItemCount(pl);
1648         if (nelem < 1)
1649                 return NULL;
1650
1651         elem = WMGetFromPLArray(pl, 0);
1652         if (!elem || !WMIsPLString(elem))
1653                 return NULL;
1654         val = WMGetFromPLString(elem);
1655
1656         if (strcasecmp(val, "solid") == 0) {
1657                 XColor color;
1658
1659                 if (nelem != 2)
1660                         return NULL;
1661
1662                 /* get color */
1663
1664                 elem = WMGetFromPLArray(pl, 1);
1665                 if (!elem || !WMIsPLString(elem))
1666                         return NULL;
1667                 val = WMGetFromPLString(elem);
1668
1669                 if (!XParseColor(dpy, scr->w_colormap, val, &color)) {
1670                         wwarning(_("\"%s\" is not a valid color name"), val);
1671                         return NULL;
1672                 }
1673
1674                 texture = (WTexture *) wTextureMakeSolid(scr, &color);
1675         } else if (strcasecmp(val, "dgradient") == 0
1676                    || strcasecmp(val, "vgradient") == 0 || strcasecmp(val, "hgradient") == 0) {
1677                 RColor color1, color2;
1678                 XColor xcolor;
1679                 int type;
1680
1681                 if (nelem != 3) {
1682                         wwarning(_("bad number of arguments in gradient specification"));
1683                         return NULL;
1684                 }
1685
1686                 if (val[0] == 'd' || val[0] == 'D')
1687                         type = WTEX_DGRADIENT;
1688                 else if (val[0] == 'h' || val[0] == 'H')
1689                         type = WTEX_HGRADIENT;
1690                 else
1691                         type = WTEX_VGRADIENT;
1692
1693                 /* get from color */
1694                 elem = WMGetFromPLArray(pl, 1);
1695                 if (!elem || !WMIsPLString(elem))
1696                         return NULL;
1697                 val = WMGetFromPLString(elem);
1698
1699                 if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1700                         wwarning(_("\"%s\" is not a valid color name"), val);
1701                         return NULL;
1702                 }
1703                 color1.alpha = 255;
1704                 color1.red = xcolor.red >> 8;
1705                 color1.green = xcolor.green >> 8;
1706                 color1.blue = xcolor.blue >> 8;
1707
1708                 /* get to color */
1709                 elem = WMGetFromPLArray(pl, 2);
1710                 if (!elem || !WMIsPLString(elem)) {
1711                         return NULL;
1712                 }
1713                 val = WMGetFromPLString(elem);
1714
1715                 if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1716                         wwarning(_("\"%s\" is not a valid color name"), val);
1717                         return NULL;
1718                 }
1719                 color2.alpha = 255;
1720                 color2.red = xcolor.red >> 8;
1721                 color2.green = xcolor.green >> 8;
1722                 color2.blue = xcolor.blue >> 8;
1723
1724                 texture = (WTexture *) wTextureMakeGradient(scr, type, &color1, &color2);
1725
1726         } else if (strcasecmp(val, "igradient") == 0) {
1727                 RColor colors1[2], colors2[2];
1728                 int th1, th2;
1729                 XColor xcolor;
1730                 int i;
1731
1732                 if (nelem != 7) {
1733                         wwarning(_("bad number of arguments in gradient specification"));
1734                         return NULL;
1735                 }
1736
1737                 /* get from color */
1738                 for (i = 0; i < 2; i++) {
1739                         elem = WMGetFromPLArray(pl, 1 + i);
1740                         if (!elem || !WMIsPLString(elem))
1741                                 return NULL;
1742                         val = WMGetFromPLString(elem);
1743
1744                         if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1745                                 wwarning(_("\"%s\" is not a valid color name"), val);
1746                                 return NULL;
1747                         }
1748                         colors1[i].alpha = 255;
1749                         colors1[i].red = xcolor.red >> 8;
1750                         colors1[i].green = xcolor.green >> 8;
1751                         colors1[i].blue = xcolor.blue >> 8;
1752                 }
1753                 elem = WMGetFromPLArray(pl, 3);
1754                 if (!elem || !WMIsPLString(elem))
1755                         return NULL;
1756                 val = WMGetFromPLString(elem);
1757                 th1 = atoi(val);
1758
1759                 /* get from color */
1760                 for (i = 0; i < 2; i++) {
1761                         elem = WMGetFromPLArray(pl, 4 + i);
1762                         if (!elem || !WMIsPLString(elem))
1763                                 return NULL;
1764                         val = WMGetFromPLString(elem);
1765
1766                         if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1767                                 wwarning(_("\"%s\" is not a valid color name"), val);
1768                                 return NULL;
1769                         }
1770                         colors2[i].alpha = 255;
1771                         colors2[i].red = xcolor.red >> 8;
1772                         colors2[i].green = xcolor.green >> 8;
1773                         colors2[i].blue = xcolor.blue >> 8;
1774                 }
1775                 elem = WMGetFromPLArray(pl, 6);
1776                 if (!elem || !WMIsPLString(elem))
1777                         return NULL;
1778                 val = WMGetFromPLString(elem);
1779                 th2 = atoi(val);
1780
1781                 texture = (WTexture *) wTextureMakeIGradient(scr, th1, colors1, th2, colors2);
1782
1783         } else if (strcasecmp(val, "mhgradient") == 0
1784                    || strcasecmp(val, "mvgradient") == 0 || strcasecmp(val, "mdgradient") == 0) {
1785                 XColor color;
1786                 RColor **colors;
1787                 int i, count;
1788                 int type;
1789
1790                 if (nelem < 3) {
1791                         wwarning(_("too few arguments in multicolor gradient specification"));
1792                         return NULL;
1793                 }
1794
1795                 if (val[1] == 'h' || val[1] == 'H')
1796                         type = WTEX_MHGRADIENT;
1797                 else if (val[1] == 'v' || val[1] == 'V')
1798                         type = WTEX_MVGRADIENT;
1799                 else
1800                         type = WTEX_MDGRADIENT;
1801
1802                 count = nelem - 1;
1803
1804                 colors = wmalloc(sizeof(RColor *) * (count + 1));
1805
1806                 for (i = 0; i < count; i++) {
1807                         elem = WMGetFromPLArray(pl, i + 1);
1808                         if (!elem || !WMIsPLString(elem)) {
1809                                 for (--i; i >= 0; --i) {
1810                                         wfree(colors[i]);
1811                                 }
1812                                 wfree(colors);
1813                                 return NULL;
1814                         }
1815                         val = WMGetFromPLString(elem);
1816
1817                         if (!XParseColor(dpy, scr->w_colormap, val, &color)) {
1818                                 wwarning(_("\"%s\" is not a valid color name"), val);
1819                                 for (--i; i >= 0; --i) {
1820                                         wfree(colors[i]);
1821                                 }
1822                                 wfree(colors);
1823                                 return NULL;
1824                         } else {
1825                                 colors[i] = wmalloc(sizeof(RColor));
1826                                 colors[i]->red = color.red >> 8;
1827                                 colors[i]->green = color.green >> 8;
1828                                 colors[i]->blue = color.blue >> 8;
1829                         }
1830                 }
1831                 colors[i] = NULL;
1832
1833                 texture = (WTexture *) wTextureMakeMGradient(scr, type, colors);
1834         } else if (strcasecmp(val, "spixmap") == 0 ||
1835                    strcasecmp(val, "cpixmap") == 0 || strcasecmp(val, "tpixmap") == 0) {
1836                 XColor color;
1837                 int type;
1838
1839                 if (nelem != 3)
1840                         return NULL;
1841
1842                 if (val[0] == 's' || val[0] == 'S')
1843                         type = WTP_SCALE;
1844                 else if (val[0] == 'c' || val[0] == 'C')
1845                         type = WTP_CENTER;
1846                 else
1847                         type = WTP_TILE;
1848
1849                 /* get color */
1850                 elem = WMGetFromPLArray(pl, 2);
1851                 if (!elem || !WMIsPLString(elem)) {
1852                         return NULL;
1853                 }
1854                 val = WMGetFromPLString(elem);
1855
1856                 if (!XParseColor(dpy, scr->w_colormap, val, &color)) {
1857                         wwarning(_("\"%s\" is not a valid color name"), val);
1858                         return NULL;
1859                 }
1860
1861                 /* file name */
1862                 elem = WMGetFromPLArray(pl, 1);
1863                 if (!elem || !WMIsPLString(elem))
1864                         return NULL;
1865                 val = WMGetFromPLString(elem);
1866
1867                 texture = (WTexture *) wTextureMakePixmap(scr, type, val, &color);
1868         } else if (strcasecmp(val, "thgradient") == 0
1869                    || strcasecmp(val, "tvgradient") == 0 || strcasecmp(val, "tdgradient") == 0) {
1870                 RColor color1, color2;
1871                 XColor xcolor;
1872                 int opacity;
1873                 int style;
1874
1875                 if (val[1] == 'h' || val[1] == 'H')
1876                         style = WTEX_THGRADIENT;
1877                 else if (val[1] == 'v' || val[1] == 'V')
1878                         style = WTEX_TVGRADIENT;
1879                 else
1880                         style = WTEX_TDGRADIENT;
1881
1882                 if (nelem != 5) {
1883                         wwarning(_("bad number of arguments in textured gradient specification"));
1884                         return NULL;
1885                 }
1886
1887                 /* get from color */
1888                 elem = WMGetFromPLArray(pl, 3);
1889                 if (!elem || !WMIsPLString(elem))
1890                         return NULL;
1891                 val = WMGetFromPLString(elem);
1892
1893                 if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1894                         wwarning(_("\"%s\" is not a valid color name"), val);
1895                         return NULL;
1896                 }
1897                 color1.alpha = 255;
1898                 color1.red = xcolor.red >> 8;
1899                 color1.green = xcolor.green >> 8;
1900                 color1.blue = xcolor.blue >> 8;
1901
1902                 /* get to color */
1903                 elem = WMGetFromPLArray(pl, 4);
1904                 if (!elem || !WMIsPLString(elem)) {
1905                         return NULL;
1906                 }
1907                 val = WMGetFromPLString(elem);
1908
1909                 if (!XParseColor(dpy, scr->w_colormap, val, &xcolor)) {
1910                         wwarning(_("\"%s\" is not a valid color name"), val);
1911                         return NULL;
1912                 }
1913                 color2.alpha = 255;
1914                 color2.red = xcolor.red >> 8;
1915                 color2.green = xcolor.green >> 8;
1916                 color2.blue = xcolor.blue >> 8;
1917
1918                 /* get opacity */
1919                 elem = WMGetFromPLArray(pl, 2);
1920                 if (!elem || !WMIsPLString(elem))
1921                         opacity = 128;
1922                 else
1923                         val = WMGetFromPLString(elem);
1924
1925                 if (!val || (opacity = atoi(val)) < 0 || opacity > 255) {
1926                         wwarning(_("bad opacity value for tgradient texture \"%s\". Should be [0..255]"), val);
1927                         opacity = 128;
1928                 }
1929
1930                 /* get file name */
1931                 elem = WMGetFromPLArray(pl, 1);
1932                 if (!elem || !WMIsPLString(elem))
1933                         return NULL;
1934                 val = WMGetFromPLString(elem);
1935
1936                 texture = (WTexture *) wTextureMakeTGradient(scr, style, &color1, &color2, val, opacity);
1937         }
1938 #ifdef TEXTURE_PLUGIN
1939         else if (strcasecmp(val, "function") == 0) {
1940                 WTexFunction *function;
1941                 void (*initFunc) (Display *, Colormap);
1942                 char *lib, *func, **argv;
1943                 int i, argc;
1944
1945                 if (nelem < 3)
1946                         return NULL;
1947
1948                 /* get the library name */
1949                 elem = WMGetFromPLArray(pl, 1);
1950                 if (!elem || !WMIsPLString(elem)) {
1951                         return NULL;
1952                 }
1953                 lib = WMGetFromPLString(elem);
1954
1955                 /* get the function name */
1956                 elem = WMGetFromPLArray(pl, 2);
1957                 if (!elem || !WMIsPLString(elem)) {
1958                         return NULL;
1959                 }
1960                 func = WMGetFromPLString(elem);
1961
1962                 argc = nelem - 2;
1963                 argv = (char **)wmalloc(argc * sizeof(char *));
1964
1965                 /* get the parameters */
1966                 argv[0] = wstrdup(func);
1967                 for (i = 0; i < argc - 1; i++) {
1968                         elem = WMGetFromPLArray(pl, 3 + i);
1969                         if (!elem || !WMIsPLString(elem)) {
1970                                 wfree(argv);
1971
1972                                 return NULL;
1973                         }
1974                         argv[i + 1] = wstrdup(WMGetFromPLString(elem));
1975                 }
1976
1977                 function = wTextureMakeFunction(scr, lib, func, argc, argv);
1978
1979 #ifdef HAVE_DLFCN_H
1980                 if (function) {
1981                         initFunc = dlsym(function->handle, "initWindowMaker");
1982                         if (initFunc) {
1983                                 initFunc(dpy, scr->w_colormap);
1984                         } else {
1985                                 wwarning(_("could not initialize library %s"), lib);
1986                         }
1987                 } else {
1988                         wwarning(_("could not find function %s::%s"), lib, func);
1989                 }
1990 #endif                          /* HAVE_DLFCN_H */
1991                 texture = (WTexture *) function;
1992         }
1993 #endif                          /* TEXTURE_PLUGIN */
1994         else {
1995                 wwarning(_("invalid texture type %s"), val);
1996                 return NULL;
1997         }
1998         return texture;
1999 }
2000
2001 static int getTexture(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2002 {
2003         static WTexture *texture;
2004         int changed = 0;
2005
2006  again:
2007         if (!WMIsPLArray(value)) {
2008                 wwarning(_("Wrong option format for key \"%s\". Should be %s."), entry->key, "Texture");
2009                 if (changed == 0) {
2010                         value = entry->plvalue;
2011                         changed = 1;
2012                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2013                         goto again;
2014                 }
2015                 return False;
2016         }
2017
2018         if (strcmp(entry->key, "WidgetColor") == 0 && !changed) {
2019                 WMPropList *pl;
2020
2021                 pl = WMGetFromPLArray(value, 0);
2022                 if (!pl || !WMIsPLString(pl) || !WMGetFromPLString(pl)
2023                     || strcasecmp(WMGetFromPLString(pl), "solid") != 0) {
2024                         wwarning(_("Wrong option format for key \"%s\". Should be %s."),
2025                                  entry->key, "Solid Texture");
2026
2027                         value = entry->plvalue;
2028                         changed = 1;
2029                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2030                         goto again;
2031                 }
2032         }
2033
2034         texture = parse_texture(scr, value);
2035
2036         if (!texture) {
2037                 wwarning(_("Error in texture specification for key \"%s\""), entry->key);
2038                 if (changed == 0) {
2039                         value = entry->plvalue;
2040                         changed = 1;
2041                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2042                         goto again;
2043                 }
2044                 return False;
2045         }
2046
2047         if (ret)
2048                 *ret = &texture;
2049
2050         if (addr)
2051                 *(WTexture **) addr = texture;
2052
2053         return True;
2054 }
2055
2056 static int getWSBackground(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2057 {
2058         WMPropList *elem;
2059         int changed = 0;
2060         char *val;
2061         int nelem;
2062
2063  again:
2064         if (!WMIsPLArray(value)) {
2065                 wwarning(_("Wrong option format for key \"%s\". Should be %s."),
2066                          "WorkspaceBack", "Texture or None");
2067                 if (changed == 0) {
2068                         value = entry->plvalue;
2069                         changed = 1;
2070                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2071                         goto again;
2072                 }
2073                 return False;
2074         }
2075
2076         /* only do basic error checking and verify for None texture */
2077
2078         nelem = WMGetPropListItemCount(value);
2079         if (nelem > 0) {
2080                 elem = WMGetFromPLArray(value, 0);
2081                 if (!elem || !WMIsPLString(elem)) {
2082                         wwarning(_("Wrong type for workspace background. Should be a texture type."));
2083                         if (changed == 0) {
2084                                 value = entry->plvalue;
2085                                 changed = 1;
2086                                 wwarning(_("using default \"%s\" instead"), entry->default_value);
2087                                 goto again;
2088                         }
2089                         return False;
2090                 }
2091                 val = WMGetFromPLString(elem);
2092
2093                 if (strcasecmp(val, "None") == 0)
2094                         return True;
2095         }
2096         *ret = WMRetainPropList(value);
2097
2098         return True;
2099 }
2100
2101 static int
2102 getWSSpecificBackground(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2103 {
2104         WMPropList *elem;
2105         int nelem;
2106         int changed = 0;
2107
2108  again:
2109         if (!WMIsPLArray(value)) {
2110                 wwarning(_("Wrong option format for key \"%s\". Should be %s."),
2111                          "WorkspaceSpecificBack", "an array of textures");
2112                 if (changed == 0) {
2113                         value = entry->plvalue;
2114                         changed = 1;
2115                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2116                         goto again;
2117                 }
2118                 return False;
2119         }
2120
2121         /* only do basic error checking and verify for None texture */
2122
2123         nelem = WMGetPropListItemCount(value);
2124         if (nelem > 0) {
2125                 while (nelem--) {
2126                         elem = WMGetFromPLArray(value, nelem);
2127                         if (!elem || !WMIsPLArray(elem)) {
2128                                 wwarning(_("Wrong type for background of workspace %i. Should be a texture."),
2129                                          nelem);
2130                         }
2131                 }
2132         }
2133
2134         *ret = WMRetainPropList(value);
2135
2136 #ifdef notworking
2137         /*
2138          * Kluge to force wmsetbg helper to set the default background.
2139          * If the WorkspaceSpecificBack is changed once wmaker has started,
2140          * the WorkspaceBack won't be sent to the helper, unless the user
2141          * changes it's value too. So, we must force this by removing the
2142          * value from the defaults DB.
2143          */
2144         if (!scr->flags.backimage_helper_launched && !scr->flags.startup) {
2145                 WMPropList *key = WMCreatePLString("WorkspaceBack");
2146
2147                 WMRemoveFromPLDictionary(WDWindowMaker->dictionary, key);
2148
2149                 WMReleasePropList(key);
2150         }
2151 #endif
2152         return True;
2153 }
2154
2155 static int getFont(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2156 {
2157         static WMFont *font;
2158         char *val;
2159
2160         GET_STRING_OR_DEFAULT("Font", val);
2161
2162         font = WMCreateFont(scr->wmscreen, val);
2163         if (!font)
2164                 font = WMCreateFont(scr->wmscreen, "fixed");
2165
2166         if (!font) {
2167                 wfatal(_("could not load any usable font!!!"));
2168                 exit(1);
2169         }
2170
2171         if (ret)
2172                 *ret = font;
2173
2174         /* can't assign font value outside update function */
2175         wassertrv(addr == NULL, True);
2176
2177         return True;
2178 }
2179
2180 static int getColor(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2181 {
2182         static XColor color;
2183         char *val;
2184         int second_pass = 0;
2185
2186         GET_STRING_OR_DEFAULT("Color", val);
2187
2188  again:
2189         if (!wGetColor(scr, val, &color)) {
2190                 wwarning(_("could not get color for key \"%s\""), entry->key);
2191                 if (second_pass == 0) {
2192                         val = WMGetFromPLString(entry->plvalue);
2193                         second_pass = 1;
2194                         wwarning(_("using default \"%s\" instead"), val);
2195                         goto again;
2196                 }
2197                 return False;
2198         }
2199
2200         if (ret)
2201                 *ret = &color;
2202
2203         assert(addr == NULL);
2204         /*
2205            if (addr)
2206            *(unsigned long*)addr = pixel;
2207          */
2208
2209         return True;
2210 }
2211
2212 static int getKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2213 {
2214         static WShortKey shortcut;
2215         KeySym ksym;
2216         char *val;
2217         char *k;
2218         char buf[MAX_SHORTCUT_LENGTH], *b;
2219
2220         GET_STRING_OR_DEFAULT("Key spec", val);
2221
2222         if (!val || strcasecmp(val, "NONE") == 0) {
2223                 shortcut.keycode = 0;
2224                 shortcut.modifier = 0;
2225                 if (ret)
2226                         *ret = &shortcut;
2227                 return True;
2228         }
2229
2230         strncpy(buf, val, MAX_SHORTCUT_LENGTH);
2231
2232         b = (char *)buf;
2233
2234         /* get modifiers */
2235         shortcut.modifier = 0;
2236         while ((k = strchr(b, '+')) != NULL) {
2237                 int mod;
2238
2239                 *k = 0;
2240                 mod = wXModifierFromKey(b);
2241                 if (mod < 0) {
2242                         wwarning(_("%s: invalid key modifier \"%s\""), entry->key, b);
2243                         return False;
2244                 }
2245                 shortcut.modifier |= mod;
2246
2247                 b = k + 1;
2248         }
2249
2250         /* get key */
2251         ksym = XStringToKeysym(b);
2252
2253         if (ksym == NoSymbol) {
2254                 wwarning(_("%s:invalid kbd shortcut specification \"%s\""), entry->key, val);
2255                 return False;
2256         }
2257
2258         shortcut.keycode = XKeysymToKeycode(dpy, ksym);
2259         if (shortcut.keycode == 0) {
2260                 wwarning(_("%s:invalid key in shortcut \"%s\""), entry->key, val);
2261                 return False;
2262         }
2263
2264         if (ret)
2265                 *ret = &shortcut;
2266
2267         return True;
2268 }
2269
2270 static int getModMask(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2271 {
2272         static int mask;
2273         char *str;
2274
2275         GET_STRING_OR_DEFAULT("Modifier Key", str);
2276
2277         if (!str)
2278                 return False;
2279
2280         mask = wXModifierFromKey(str);
2281         if (mask < 0) {
2282                 wwarning(_("%s: modifier key %s is not valid"), entry->key, str);
2283                 mask = 0;
2284                 return False;
2285         }
2286
2287         if (addr)
2288                 *(int *)addr = mask;
2289
2290         if (ret)
2291                 *ret = &mask;
2292
2293         return True;
2294 }
2295
2296 #ifdef NEWSTUFF
2297 static int getRImages(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2298 {
2299         unsigned int mask;
2300         char *str;
2301         RImage *image;
2302         int i, n;
2303         int w, h;
2304
2305         GET_STRING_OR_DEFAULT("Image File Path", str);
2306         if (!str)
2307                 return False;
2308
2309         image = RLoadImage(scr->rcontext, str, 0);
2310         if (!image) {
2311                 wwarning(_("could not load image in option %s: %s"), entry->key, RMessageForError(RErrorCode));
2312                 return False;
2313         }
2314
2315         if (*(RImage **) addr) {
2316                 RReleaseImage(*(RImage **) addr);
2317         }
2318         if (addr)
2319                 *(RImage **) addr = image;
2320
2321         assert(ret == NULL);
2322         /*
2323            if (ret)
2324            *(RImage**)ret = image;
2325          */
2326
2327         return True;
2328 }
2329 #endif
2330
2331 # include <X11/cursorfont.h>
2332 typedef struct {
2333         char *name;
2334         int id;
2335 } WCursorLookup;
2336
2337 #define CURSOR_ID_NONE  (XC_num_glyphs)
2338
2339 static WCursorLookup cursor_table[] = {
2340         {"X_cursor", XC_X_cursor},
2341         {"arrow", XC_arrow},
2342         {"based_arrow_down", XC_based_arrow_down},
2343         {"based_arrow_up", XC_based_arrow_up},
2344         {"boat", XC_boat},
2345         {"bogosity", XC_bogosity},
2346         {"bottom_left_corner", XC_bottom_left_corner},
2347         {"bottom_right_corner", XC_bottom_right_corner},
2348         {"bottom_side", XC_bottom_side},
2349         {"bottom_tee", XC_bottom_tee},
2350         {"box_spiral", XC_box_spiral},
2351         {"center_ptr", XC_center_ptr},
2352         {"circle", XC_circle},
2353         {"clock", XC_clock},
2354         {"coffee_mug", XC_coffee_mug},
2355         {"cross", XC_cross},
2356         {"cross_reverse", XC_cross_reverse},
2357         {"crosshair", XC_crosshair},
2358         {"diamond_cross", XC_diamond_cross},
2359         {"dot", XC_dot},
2360         {"dotbox", XC_dotbox},
2361         {"double_arrow", XC_double_arrow},
2362         {"draft_large", XC_draft_large},
2363         {"draft_small", XC_draft_small},
2364         {"draped_box", XC_draped_box},
2365         {"exchange", XC_exchange},
2366         {"fleur", XC_fleur},
2367         {"gobbler", XC_gobbler},
2368         {"gumby", XC_gumby},
2369         {"hand1", XC_hand1},
2370         {"hand2", XC_hand2},
2371         {"heart", XC_heart},
2372         {"icon", XC_icon},
2373         {"iron_cross", XC_iron_cross},
2374         {"left_ptr", XC_left_ptr},
2375         {"left_side", XC_left_side},
2376         {"left_tee", XC_left_tee},
2377         {"leftbutton", XC_leftbutton},
2378         {"ll_angle", XC_ll_angle},
2379         {"lr_angle", XC_lr_angle},
2380         {"man", XC_man},
2381         {"middlebutton", XC_middlebutton},
2382         {"mouse", XC_mouse},
2383         {"pencil", XC_pencil},
2384         {"pirate", XC_pirate},
2385         {"plus", XC_plus},
2386         {"question_arrow", XC_question_arrow},
2387         {"right_ptr", XC_right_ptr},
2388         {"right_side", XC_right_side},
2389         {"right_tee", XC_right_tee},
2390         {"rightbutton", XC_rightbutton},
2391         {"rtl_logo", XC_rtl_logo},
2392         {"sailboat", XC_sailboat},
2393         {"sb_down_arrow", XC_sb_down_arrow},
2394         {"sb_h_double_arrow", XC_sb_h_double_arrow},
2395         {"sb_left_arrow", XC_sb_left_arrow},
2396         {"sb_right_arrow", XC_sb_right_arrow},
2397         {"sb_up_arrow", XC_sb_up_arrow},
2398         {"sb_v_double_arrow", XC_sb_v_double_arrow},
2399         {"shuttle", XC_shuttle},
2400         {"sizing", XC_sizing},
2401         {"spider", XC_spider},
2402         {"spraycan", XC_spraycan},
2403         {"star", XC_star},
2404         {"target", XC_target},
2405         {"tcross", XC_tcross},
2406         {"top_left_arrow", XC_top_left_arrow},
2407         {"top_left_corner", XC_top_left_corner},
2408         {"top_right_corner", XC_top_right_corner},
2409         {"top_side", XC_top_side},
2410         {"top_tee", XC_top_tee},
2411         {"trek", XC_trek},
2412         {"ul_angle", XC_ul_angle},
2413         {"umbrella", XC_umbrella},
2414         {"ur_angle", XC_ur_angle},
2415         {"watch", XC_watch},
2416         {"xterm", XC_xterm},
2417         {NULL, CURSOR_ID_NONE}
2418 };
2419
2420 static void check_bitmap_status(int status, char *filename, Pixmap bitmap)
2421 {
2422         switch (status) {
2423         case BitmapOpenFailed:
2424                 wwarning(_("failed to open bitmap file \"%s\""), filename);
2425                 break;
2426         case BitmapFileInvalid:
2427                 wwarning(_("\"%s\" is not a valid bitmap file"), filename);
2428                 break;
2429         case BitmapNoMemory:
2430                 wwarning(_("out of memory reading bitmap file \"%s\""), filename);
2431                 break;
2432         case BitmapSuccess:
2433                 XFreePixmap(dpy, bitmap);
2434                 break;
2435         }
2436 }
2437
2438 /*
2439  * (none)
2440  * (builtin, <cursor_name>)
2441  * (bitmap, <cursor_bitmap>, <cursor_mask>)
2442  */
2443 static int parse_cursor(WScreen * scr, WMPropList * pl, Cursor * cursor)
2444 {
2445         WMPropList *elem;
2446         char *val;
2447         int nelem;
2448         int status = 0;
2449
2450         nelem = WMGetPropListItemCount(pl);
2451         if (nelem < 1) {
2452                 return (status);
2453         }
2454         elem = WMGetFromPLArray(pl, 0);
2455         if (!elem || !WMIsPLString(elem)) {
2456                 return (status);
2457         }
2458         val = WMGetFromPLString(elem);
2459
2460         if (0 == strcasecmp(val, "none")) {
2461                 status = 1;
2462                 *cursor = None;
2463         } else if (0 == strcasecmp(val, "builtin")) {
2464                 int i;
2465                 int cursor_id = CURSOR_ID_NONE;
2466
2467                 if (2 != nelem) {
2468                         wwarning(_("bad number of arguments in cursor specification"));
2469                         return (status);
2470                 }
2471                 elem = WMGetFromPLArray(pl, 1);
2472                 if (!elem || !WMIsPLString(elem)) {
2473                         return (status);
2474                 }
2475                 val = WMGetFromPLString(elem);
2476
2477                 for (i = 0; NULL != cursor_table[i].name; i++) {
2478                         if (0 == strcasecmp(val, cursor_table[i].name)) {
2479                                 cursor_id = cursor_table[i].id;
2480                                 break;
2481                         }
2482                 }
2483                 if (CURSOR_ID_NONE == cursor_id) {
2484                         wwarning(_("unknown builtin cursor name \"%s\""), val);
2485                 } else {
2486                         *cursor = XCreateFontCursor(dpy, cursor_id);
2487                         status = 1;
2488                 }
2489         } else if (0 == strcasecmp(val, "bitmap")) {
2490                 char *bitmap_name;
2491                 char *mask_name;
2492                 int bitmap_status;
2493                 int mask_status;
2494                 Pixmap bitmap;
2495                 Pixmap mask;
2496                 unsigned int w, h;
2497                 int x, y;
2498                 XColor fg, bg;
2499
2500                 if (3 != nelem) {
2501                         wwarning(_("bad number of arguments in cursor specification"));
2502                         return (status);
2503                 }
2504                 elem = WMGetFromPLArray(pl, 1);
2505                 if (!elem || !WMIsPLString(elem)) {
2506                         return (status);
2507                 }
2508                 val = WMGetFromPLString(elem);
2509                 bitmap_name = FindImage(wPreferences.pixmap_path, val);
2510                 if (!bitmap_name) {
2511                         wwarning(_("could not find cursor bitmap file \"%s\""), val);
2512                         return (status);
2513                 }
2514                 elem = WMGetFromPLArray(pl, 2);
2515                 if (!elem || !WMIsPLString(elem)) {
2516                         wfree(bitmap_name);
2517                         return (status);
2518                 }
2519                 val = WMGetFromPLString(elem);
2520                 mask_name = FindImage(wPreferences.pixmap_path, val);
2521                 if (!mask_name) {
2522                         wfree(bitmap_name);
2523                         wwarning(_("could not find cursor bitmap file \"%s\""), val);
2524                         return (status);
2525                 }
2526                 mask_status = XReadBitmapFile(dpy, scr->w_win, mask_name, &w, &h, &mask, &x, &y);
2527                 bitmap_status = XReadBitmapFile(dpy, scr->w_win, bitmap_name, &w, &h, &bitmap, &x, &y);
2528                 if ((BitmapSuccess == bitmap_status) && (BitmapSuccess == mask_status)) {
2529                         fg.pixel = scr->black_pixel;
2530                         bg.pixel = scr->white_pixel;
2531                         XQueryColor(dpy, scr->w_colormap, &fg);
2532                         XQueryColor(dpy, scr->w_colormap, &bg);
2533                         *cursor = XCreatePixmapCursor(dpy, bitmap, mask, &fg, &bg, x, y);
2534                         status = 1;
2535                 }
2536                 check_bitmap_status(bitmap_status, bitmap_name, bitmap);
2537                 check_bitmap_status(mask_status, mask_name, mask);
2538                 wfree(bitmap_name);
2539                 wfree(mask_name);
2540         }
2541         return (status);
2542 }
2543
2544 static int getCursor(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *addr, void **ret)
2545 {
2546         static Cursor cursor;
2547         int status;
2548         int changed = 0;
2549
2550  again:
2551         if (!WMIsPLArray(value)) {
2552                 wwarning(_("Wrong option format for key \"%s\". Should be %s."),
2553                          entry->key, "cursor specification");
2554                 if (!changed) {
2555                         value = entry->plvalue;
2556                         changed = 1;
2557                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2558                         goto again;
2559                 }
2560                 return (False);
2561         }
2562         status = parse_cursor(scr, value, &cursor);
2563         if (!status) {
2564                 wwarning(_("Error in cursor specification for key \"%s\""), entry->key);
2565                 if (!changed) {
2566                         value = entry->plvalue;
2567                         changed = 1;
2568                         wwarning(_("using default \"%s\" instead"), entry->default_value);
2569                         goto again;
2570                 }
2571                 return (False);
2572         }
2573         if (ret) {
2574                 *ret = &cursor;
2575         }
2576         if (addr) {
2577                 *(Cursor *) addr = cursor;
2578         }
2579         return (True);
2580 }
2581
2582 #undef CURSOR_ID_NONE
2583
2584 /* ---------------- value setting functions --------------- */
2585 static int setJustify(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
2586 {
2587         return REFRESH_WINDOW_TITLE_COLOR;
2588 }
2589
2590 static int setClearance(WScreen * scr, WDefaultEntry * entry, void *bar, void *foo)
2591 {
2592         return REFRESH_WINDOW_FONT | REFRESH_BUTTON_IMAGES | REFRESH_MENU_TITLE_FONT | REFRESH_MENU_FONT;
2593 }
2594
2595 static int setIfDockPresent(WScreen * scr, WDefaultEntry * entry, char *flag, long which)
2596 {
2597         switch (which) {
2598         case WM_DOCK:
2599                 wPreferences.flags.nodock = wPreferences.flags.nodock || *flag;
2600                 break;
2601         case WM_CLIP:
2602                 wPreferences.flags.noclip = wPreferences.flags.noclip || *flag;
2603                 break;
2604         default:
2605                 break;
2606         }
2607         return 0;
2608 }
2609
2610 static int setStickyIcons(WScreen * scr, WDefaultEntry * entry, void *bar, void *foo)
2611 {
2612         if (scr->workspaces) {
2613                 wWorkspaceForceChange(scr, scr->current_workspace);
2614                 wArrangeIcons(scr, False);
2615         }
2616         return 0;
2617 }
2618
2619 #if not_used
2620 static int setPositive(WScreen * scr, WDefaultEntry * entry, int *value, void *foo)
2621 {
2622         if (*value <= 0)
2623                 *(int *)foo = 1;
2624
2625         return 0;
2626 }
2627 #endif
2628
2629 static int setIconTile(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
2630 {
2631         Pixmap pixmap;
2632         RImage *img;
2633         int reset = 0;
2634
2635         img = wTextureRenderImage(*texture, wPreferences.icon_size,
2636                                   wPreferences.icon_size, ((*texture)->any.type & WREL_BORDER_MASK)
2637                                   ? WREL_ICON : WREL_FLAT);
2638         if (!img) {
2639                 wwarning(_("could not render texture for icon background"));
2640                 if (!entry->addr)
2641                         wTextureDestroy(scr, *texture);
2642                 return 0;
2643         }
2644         RConvertImage(scr->rcontext, img, &pixmap);
2645
2646         if (scr->icon_tile) {
2647                 reset = 1;
2648                 RReleaseImage(scr->icon_tile);
2649                 XFreePixmap(dpy, scr->icon_tile_pixmap);
2650         }
2651
2652         scr->icon_tile = img;
2653
2654         /* put the icon in the noticeboard hint */
2655         PropSetIconTileHint(scr, img);
2656
2657         if (!wPreferences.flags.noclip) {
2658                 if (scr->clip_tile) {
2659                         RReleaseImage(scr->clip_tile);
2660                 }
2661                 scr->clip_tile = wClipMakeTile(scr, img);
2662         }
2663
2664         scr->icon_tile_pixmap = pixmap;
2665
2666         if (scr->def_icon_pixmap) {
2667                 XFreePixmap(dpy, scr->def_icon_pixmap);
2668                 scr->def_icon_pixmap = None;
2669         }
2670         if (scr->def_ticon_pixmap) {
2671                 XFreePixmap(dpy, scr->def_ticon_pixmap);
2672                 scr->def_ticon_pixmap = None;
2673         }
2674
2675         if (scr->icon_back_texture) {
2676                 wTextureDestroy(scr, (WTexture *) scr->icon_back_texture);
2677         }
2678         scr->icon_back_texture = wTextureMakeSolid(scr, &((*texture)->any.color));
2679
2680         if (scr->clip_balloon)
2681                 XSetWindowBackground(dpy, scr->clip_balloon, (*texture)->any.color.pixel);
2682
2683         /*
2684          * Free the texture as nobody else will use it, nor refer to it.
2685          */
2686         if (!entry->addr)
2687                 wTextureDestroy(scr, *texture);
2688
2689         return (reset ? REFRESH_ICON_TILE : 0);
2690 }
2691
2692 static int setWinTitleFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2693 {
2694         if (scr->title_font) {
2695                 WMReleaseFont(scr->title_font);
2696         }
2697         scr->title_font = font;
2698
2699         return REFRESH_WINDOW_FONT | REFRESH_BUTTON_IMAGES;
2700 }
2701
2702 static int setMenuTitleFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2703 {
2704         if (scr->menu_title_font) {
2705                 WMReleaseFont(scr->menu_title_font);
2706         }
2707
2708         scr->menu_title_font = font;
2709
2710         return REFRESH_MENU_TITLE_FONT;
2711 }
2712
2713 static int setMenuTextFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2714 {
2715         if (scr->menu_entry_font) {
2716                 WMReleaseFont(scr->menu_entry_font);
2717         }
2718         scr->menu_entry_font = font;
2719
2720         return REFRESH_MENU_FONT;
2721 }
2722
2723 static int setIconTitleFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2724 {
2725         if (scr->icon_title_font) {
2726                 WMReleaseFont(scr->icon_title_font);
2727         }
2728
2729         scr->icon_title_font = font;
2730
2731         return REFRESH_ICON_FONT;
2732 }
2733
2734 static int setClipTitleFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2735 {
2736         if (scr->clip_title_font) {
2737                 WMReleaseFont(scr->clip_title_font);
2738         }
2739
2740         scr->clip_title_font = font;
2741
2742         return REFRESH_ICON_FONT;
2743 }
2744
2745 static int setLargeDisplayFont(WScreen * scr, WDefaultEntry * entry, WMFont * font, void *foo)
2746 {
2747         if (scr->workspace_name_font) {
2748                 WMReleaseFont(scr->workspace_name_font);
2749         }
2750
2751         scr->workspace_name_font = font;
2752
2753         return 0;
2754 }
2755
2756 static int setHightlight(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2757 {
2758         if (scr->select_color)
2759                 WMReleaseColor(scr->select_color);
2760
2761         scr->select_color = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2762
2763         wFreeColor(scr, color->pixel);
2764
2765         return REFRESH_MENU_COLOR;
2766 }
2767
2768 static int setHightlightText(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2769 {
2770         if (scr->select_text_color)
2771                 WMReleaseColor(scr->select_text_color);
2772
2773         scr->select_text_color = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2774
2775         wFreeColor(scr, color->pixel);
2776
2777         return REFRESH_MENU_COLOR;
2778 }
2779
2780 static int setClipTitleColor(WScreen * scr, WDefaultEntry * entry, XColor * color, long widx)
2781 {
2782         if (scr->clip_title_color[widx])
2783                 WMReleaseColor(scr->clip_title_color[widx]);
2784         scr->clip_title_color[widx] = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2785 #ifdef GRADIENT_CLIP_ARROW
2786         if (widx == CLIP_NORMAL) {
2787                 RImage *image;
2788                 RColor color1, color2;
2789                 int pt = CLIP_BUTTON_SIZE * wPreferences.icon_size / 64;
2790                 int as = pt - 15;       /* 15 = 5+5+5 */
2791
2792                 FREE_PIXMAP(scr->clip_arrow_gradient);
2793
2794                 color1.red = (color->red >> 8) * 6 / 10;
2795                 color1.green = (color->green >> 8) * 6 / 10;
2796                 color1.blue = (color->blue >> 8) * 6 / 10;
2797
2798                 color2.red = WMIN((color->red >> 8) * 20 / 10, 255);
2799                 color2.green = WMIN((color->green >> 8) * 20 / 10, 255);
2800                 color2.blue = WMIN((color->blue >> 8) * 20 / 10, 255);
2801
2802                 image = RRenderGradient(as + 1, as + 1, &color1, &color2, RDiagonalGradient);
2803                 RConvertImage(scr->rcontext, image, &scr->clip_arrow_gradient);
2804                 RReleaseImage(image);
2805         }
2806 #endif                          /* GRADIENT_CLIP_ARROW */
2807
2808         wFreeColor(scr, color->pixel);
2809
2810         return REFRESH_ICON_TITLE_COLOR;
2811 }
2812
2813 static int setWTitleColor(WScreen * scr, WDefaultEntry * entry, XColor * color, long widx)
2814 {
2815         if (scr->window_title_color[widx])
2816                 WMReleaseColor(scr->window_title_color[widx]);
2817
2818         scr->window_title_color[widx] =
2819             WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2820
2821         wFreeColor(scr, color->pixel);
2822
2823         return REFRESH_WINDOW_TITLE_COLOR;
2824 }
2825
2826 static int setMenuTitleColor(WScreen * scr, WDefaultEntry * entry, XColor * color, long widx)
2827 {
2828         if (scr->menu_title_color[0])
2829                 WMReleaseColor(scr->menu_title_color[0]);
2830
2831         scr->menu_title_color[0] = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2832
2833         wFreeColor(scr, color->pixel);
2834
2835         return REFRESH_MENU_TITLE_COLOR;
2836 }
2837
2838 static int setMenuTextColor(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2839 {
2840         if (scr->mtext_color)
2841                 WMReleaseColor(scr->mtext_color);
2842
2843         scr->mtext_color = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2844
2845         if (WMColorPixel(scr->dtext_color) == WMColorPixel(scr->mtext_color)) {
2846                 WMSetColorAlpha(scr->dtext_color, 0x7fff);
2847         } else {
2848                 WMSetColorAlpha(scr->dtext_color, 0xffff);
2849         }
2850
2851         wFreeColor(scr, color->pixel);
2852
2853         return REFRESH_MENU_COLOR;
2854 }
2855
2856 static int setMenuDisabledColor(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2857 {
2858         if (scr->dtext_color)
2859                 WMReleaseColor(scr->dtext_color);
2860
2861         scr->dtext_color = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2862
2863         if (WMColorPixel(scr->dtext_color) == WMColorPixel(scr->mtext_color)) {
2864                 WMSetColorAlpha(scr->dtext_color, 0x7fff);
2865         } else {
2866                 WMSetColorAlpha(scr->dtext_color, 0xffff);
2867         }
2868
2869         wFreeColor(scr, color->pixel);
2870
2871         return REFRESH_MENU_COLOR;
2872 }
2873
2874 static int setIconTitleColor(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2875 {
2876         if (scr->icon_title_color)
2877                 WMReleaseColor(scr->icon_title_color);
2878         scr->icon_title_color = WMCreateRGBColor(scr->wmscreen, color->red, color->green, color->blue, True);
2879
2880         wFreeColor(scr, color->pixel);
2881
2882         return REFRESH_ICON_TITLE_COLOR;
2883 }
2884
2885 static int setIconTitleBack(WScreen * scr, WDefaultEntry * entry, XColor * color, void *foo)
2886 {
2887         if (scr->icon_title_texture) {
2888                 wTextureDestroy(scr, (WTexture *) scr->icon_title_texture);
2889         }
2890         scr->icon_title_texture = wTextureMakeSolid(scr, color);
2891
2892         return REFRESH_ICON_TITLE_BACK;
2893 }
2894
2895 static void trackDeadProcess(pid_t pid, unsigned char status, WScreen * scr)
2896 {
2897         close(scr->helper_fd);
2898         scr->helper_fd = 0;
2899         scr->helper_pid = 0;
2900         scr->flags.backimage_helper_launched = 0;
2901 }
2902
2903 static int setWorkspaceSpecificBack(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *bar)
2904 {
2905         WMPropList *val;
2906         char *str;
2907         int i;
2908
2909         if (scr->flags.backimage_helper_launched) {
2910                 if (WMGetPropListItemCount(value) == 0) {
2911                         SendHelperMessage(scr, 'C', 0, NULL);
2912                         SendHelperMessage(scr, 'K', 0, NULL);
2913
2914                         WMReleasePropList(value);
2915                         return 0;
2916                 }
2917         } else {
2918                 pid_t pid;
2919                 int filedes[2];
2920
2921                 if (WMGetPropListItemCount(value) == 0)
2922                         return 0;
2923
2924                 if (pipe(filedes) < 0) {
2925                         wsyserror("pipe() failed:can't set workspace specific background image");
2926
2927                         WMReleasePropList(value);
2928                         return 0;
2929                 }
2930
2931                 pid = fork();
2932                 if (pid < 0) {
2933                         wsyserror("fork() failed:can't set workspace specific background image");
2934                         if (close(filedes[0]) < 0)
2935                                 wsyserror("could not close pipe");
2936                         if (close(filedes[1]) < 0)
2937                                 wsyserror("could not close pipe");
2938
2939                 } else if (pid == 0) {
2940                         char *dither;
2941
2942                         SetupEnvironment(scr);
2943
2944                         if (close(0) < 0)
2945                                 wsyserror("could not close pipe");
2946                         if (dup(filedes[0]) < 0) {
2947                                 wsyserror("dup() failed:can't set workspace specific background image");
2948                         }
2949                         dither = wPreferences.no_dithering ? "-m" : "-d";
2950                         if (wPreferences.smooth_workspace_back)
2951                                 execlp("wmsetbg", "wmsetbg", "-helper", "-S", dither, NULL);
2952                         else
2953                                 execlp("wmsetbg", "wmsetbg", "-helper", dither, NULL);
2954                         wsyserror("could not execute wmsetbg");
2955                         exit(1);
2956                 } else {
2957
2958                         if (fcntl(filedes[0], F_SETFD, FD_CLOEXEC) < 0) {
2959                                 wsyserror("error setting close-on-exec flag");
2960                         }
2961                         if (fcntl(filedes[1], F_SETFD, FD_CLOEXEC) < 0) {
2962                                 wsyserror("error setting close-on-exec flag");
2963                         }
2964
2965                         scr->helper_fd = filedes[1];
2966                         scr->helper_pid = pid;
2967                         scr->flags.backimage_helper_launched = 1;
2968
2969                         wAddDeathHandler(pid, (WDeathHandler *) trackDeadProcess, scr);
2970
2971                         SendHelperMessage(scr, 'P', -1, wPreferences.pixmap_path);
2972                 }
2973
2974         }
2975
2976         for (i = 0; i < WMGetPropListItemCount(value); i++) {
2977                 val = WMGetFromPLArray(value, i);
2978                 if (val && WMIsPLArray(val) && WMGetPropListItemCount(val) > 0) {
2979                         str = WMGetPropListDescription(val, False);
2980
2981                         SendHelperMessage(scr, 'S', i + 1, str);
2982
2983                         wfree(str);
2984                 } else {
2985                         SendHelperMessage(scr, 'U', i + 1, NULL);
2986                 }
2987         }
2988         sleep(1);
2989
2990         WMReleasePropList(value);
2991         return 0;
2992 }
2993
2994 static int setWorkspaceBack(WScreen * scr, WDefaultEntry * entry, WMPropList * value, void *bar)
2995 {
2996         if (scr->flags.backimage_helper_launched) {
2997                 char *str;
2998
2999                 if (WMGetPropListItemCount(value) == 0) {
3000                         SendHelperMessage(scr, 'U', 0, NULL);
3001                 } else {
3002                         /* set the default workspace background to this one */
3003                         str = WMGetPropListDescription(value, False);
3004                         if (str) {
3005                                 SendHelperMessage(scr, 'S', 0, str);
3006                                 wfree(str);
3007                                 SendHelperMessage(scr, 'C', scr->current_workspace + 1, NULL);
3008                         } else {
3009                                 SendHelperMessage(scr, 'U', 0, NULL);
3010                         }
3011                 }
3012         } else if (WMGetPropListItemCount(value) > 0) {
3013                 char *command;
3014                 char *text;
3015                 char *dither;
3016                 int len;
3017
3018                 SetupEnvironment(scr);
3019                 text = WMGetPropListDescription(value, False);
3020                 len = strlen(text) + 40;
3021                 command = wmalloc(len);
3022                 dither = wPreferences.no_dithering ? "-m" : "-d";
3023                 if (wPreferences.smooth_workspace_back)
3024                         snprintf(command, len, "wmsetbg %s -S -p '%s' &", dither, text);
3025                 else
3026                         snprintf(command, len, "wmsetbg %s -p '%s' &", dither, text);
3027                 wfree(text);
3028                 system(command);
3029                 wfree(command);
3030         }
3031         WMReleasePropList(value);
3032
3033         return 0;
3034 }
3035
3036 #ifdef VIRTUAL_DESKTOP
3037 static int setVirtualDeskEnable(WScreen * scr, WDefaultEntry * entry, void *foo, void *bar)
3038 {
3039         wWorkspaceUpdateEdge(scr);
3040         return 0;
3041 }
3042 #endif
3043
3044 static int setWidgetColor(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3045 {
3046         if (scr->widget_texture) {
3047                 wTextureDestroy(scr, (WTexture *) scr->widget_texture);
3048         }
3049         scr->widget_texture = *(WTexSolid **) texture;
3050
3051         return 0;
3052 }
3053
3054 static int setFTitleBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3055 {
3056         if (scr->window_title_texture[WS_FOCUSED]) {
3057                 wTextureDestroy(scr, scr->window_title_texture[WS_FOCUSED]);
3058         }
3059         scr->window_title_texture[WS_FOCUSED] = *texture;
3060
3061         return REFRESH_WINDOW_TEXTURES;
3062 }
3063
3064 static int setPTitleBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3065 {
3066         if (scr->window_title_texture[WS_PFOCUSED]) {
3067                 wTextureDestroy(scr, scr->window_title_texture[WS_PFOCUSED]);
3068         }
3069         scr->window_title_texture[WS_PFOCUSED] = *texture;
3070
3071         return REFRESH_WINDOW_TEXTURES;
3072 }
3073
3074 static int setUTitleBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3075 {
3076         if (scr->window_title_texture[WS_UNFOCUSED]) {
3077                 wTextureDestroy(scr, scr->window_title_texture[WS_UNFOCUSED]);
3078         }
3079         scr->window_title_texture[WS_UNFOCUSED] = *texture;
3080
3081         return REFRESH_WINDOW_TEXTURES;
3082 }
3083
3084 static int setResizebarBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3085 {
3086         if (scr->resizebar_texture[0]) {
3087                 wTextureDestroy(scr, scr->resizebar_texture[0]);
3088         }
3089         scr->resizebar_texture[0] = *texture;
3090
3091         return REFRESH_WINDOW_TEXTURES;
3092 }
3093
3094 static int setMenuTitleBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3095 {
3096         if (scr->menu_title_texture[0]) {
3097                 wTextureDestroy(scr, scr->menu_title_texture[0]);
3098         }
3099         scr->menu_title_texture[0] = *texture;
3100
3101         return REFRESH_MENU_TITLE_TEXTURE;
3102 }
3103
3104 static int setMenuTextBack(WScreen * scr, WDefaultEntry * entry, WTexture ** texture, void *foo)
3105 {
3106         if (scr->menu_item_texture) {
3107                 wTextureDestroy(scr, scr->menu_item_texture);
3108                 wTextureDestroy(scr, (WTexture *) scr->menu_item_auxtexture);
3109         }
3110         scr->menu_item_texture = *texture;
3111
3112         scr->menu_item_auxtexture = wTextureMakeSolid(scr, &scr->menu_item_texture->any.color);
3113
3114         return REFRESH_MENU_TEXTURE;
3115 }
3116
3117 static int setKeyGrab(WScreen * scr, WDefaultEntry * entry, WShortKey * shortcut, long widx)
3118 {
3119         WWindow *wwin;
3120         wKeyBindings[widx] = *shortcut;
3121
3122         wwin = scr->focused_window;
3123
3124         while (wwin != NULL) {
3125                 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
3126
3127                 if (!WFLAGP(wwin, no_bind_keys)) {
3128                         wWindowSetKeyGrabs(wwin);
3129                 }
3130                 wwin = wwin->prev;
3131         }
3132
3133         return 0;
3134 }
3135
3136 static int setIconPosition(WScreen * scr, WDefaultEntry * entry, void *bar, void *foo)
3137 {
3138         wScreenUpdateUsableArea(scr);
3139         wArrangeIcons(scr, True);
3140
3141         return 0;
3142 }
3143
3144 static int updateUsableArea(WScreen * scr, WDefaultEntry * entry, void *bar, void *foo)
3145 {
3146         wScreenUpdateUsableArea(scr);
3147
3148         return 0;
3149 }
3150
3151 static int setMenuStyle(WScreen * scr, WDefaultEntry * entry, int *value, void *foo)
3152 {
3153         return REFRESH_MENU_TEXTURE;
3154 }
3155
3156 static RImage *chopOffImage(RImage * image, int x, int y, int w, int h)
3157 {
3158         RImage *img = RCreateImage(w, h, image->format == RRGBAFormat);
3159
3160         RCopyArea(img, image, x, y, w, h, 0, 0);
3161
3162         return img;
3163 }
3164
3165 static int setSwPOptions(WScreen * scr, WDefaultEntry * entry, WMPropList * array, void *foo)
3166 {
3167         char *path;
3168         RImage *bgimage;
3169         int cwidth, cheight;
3170         WPreferences *prefs = (WPreferences *) foo;
3171
3172         if (!WMIsPLArray(array) || WMGetPropListItemCount(array) == 0) {
3173                 if (prefs->swtileImage)
3174                         RReleaseImage(prefs->swtileImage);
3175                 prefs->swtileImage = NULL;
3176
3177                 WMReleasePropList(array);
3178                 return 0;
3179         }
3180
3181         switch (WMGetPropListItemCount(array)) {
3182         case 4:
3183                 if (!WMIsPLString(WMGetFromPLArray(array, 1))) {
3184                         wwarning(_("Invalid arguments for option \"%s\""), entry->key);
3185                         break;
3186                 } else
3187                         path = FindImage(wPreferences.pixmap_path, WMGetFromPLString(WMGetFromPLArray(array, 1)));
3188
3189                 if (!path) {
3190                         wwarning(_("Could not find image \"%s\" for option \"%s\""),
3191                                  WMGetFromPLString(WMGetFromPLArray(array, 1)), entry->key);
3192                 } else {
3193                         bgimage = RLoadImage(scr->rcontext, path, 0);
3194                         if (!bgimage) {
3195                                 wwarning(_("Could not load image \"%s\" for option \"%s\""), path, entry->key);
3196                                 wfree(path);
3197                         } else {
3198                                 wfree(path);
3199
3200                                 cwidth = atoi(WMGetFromPLString(WMGetFromPLArray(array, 2)));
3201                                 cheight = atoi(WMGetFromPLString(WMGetFromPLArray(array, 3)));
3202
3203                                 if (cwidth <= 0 || cheight <= 0 ||
3204                                     cwidth >= bgimage->width - 2 || cheight >= bgimage->height - 2)
3205                                         wwarning(_("Invalid split sizes for SwitchPanel back image."));
3206                                 else {
3207                                         int i;
3208                                         int swidth, theight;
3209                                         for (i = 0; i < 9; i++) {
3210                                                 if (prefs->swbackImage[i])
3211                                                         RReleaseImage(prefs->swbackImage[i]);
3212                                                 prefs->swbackImage[i] = NULL;
3213                                         }
3214                                         swidth = (bgimage->width - cwidth) / 2;
3215                                         theight = (bgimage->height - cheight) / 2;
3216
3217                                         prefs->swbackImage[0] = chopOffImage(bgimage, 0, 0, swidth, theight);
3218                                         prefs->swbackImage[1] = chopOffImage(bgimage, swidth, 0, cwidth, theight);
3219                                         prefs->swbackImage[2] = chopOffImage(bgimage, swidth + cwidth, 0,
3220                                                                              swidth, theight);
3221
3222                                         prefs->swbackImage[3] = chopOffImage(bgimage, 0, theight, swidth, cheight);
3223                                         prefs->swbackImage[4] = chopOffImage(bgimage, swidth, theight,
3224                                                                              cwidth, cheight);
3225                                         prefs->swbackImage[5] = chopOffImage(bgimage, swidth + cwidth, theight,
3226                                                                              swidth, cheight);
3227
3228                                         prefs->swbackImage[6] = chopOffImage(bgimage, 0, theight + cheight,
3229                                                                              swidth, theight);
3230                                         prefs->swbackImage[7] = chopOffImage(bgimage, swidth, theight + cheight,
3231                                                                              cwidth, theight);
3232                                         prefs->swbackImage[8] =
3233                                             chopOffImage(bgimage, swidth + cwidth, theight + cheight, swidth,
3234                                                          theight);
3235
3236                                         // check if anything failed
3237                                         for (i = 0; i < 9; i++) {
3238                                                 if (!prefs->swbackImage[i]) {
3239                                                         for (; i >= 0; --i) {
3240                                                                 RReleaseImage(prefs->swbackImage[i]);
3241                                                                 prefs->swbackImage[i] = NULL;
3242                                                         }
3243                                                         break;
3244                                                 }
3245                                         }
3246                                 }
3247                                 RReleaseImage(bgimage);
3248                         }
3249                 }
3250
3251         case 1:
3252                 if (!WMIsPLString(WMGetFromPLArray(array, 0))) {
3253                         wwarning(_("Invalid arguments for option \"%s\""), entry->key);
3254                         break;
3255                 } else
3256                         path = FindImage(wPreferences.pixmap_path, WMGetFromPLString(WMGetFromPLArray(array, 0)));
3257
3258                 if (!path) {
3259                         wwarning(_("Could not find image \"%s\" for option \"%s\""),
3260                                  WMGetFromPLString(WMGetFromPLArray(array, 0)), entry->key);
3261                 } else {
3262                         if (prefs->swtileImage)
3263                                 RReleaseImage(prefs->swtileImage);
3264
3265                         prefs->swtileImage = RLoadImage(scr->rcontext, path, 0);
3266                         if (!prefs->swtileImage) {
3267                                 wwarning(_("Could not load image \"%s\" for option \"%s\""), path, entry->key);
3268                         }
3269                         wfree(path);
3270                 }
3271                 break;
3272
3273         default:
3274                 wwarning(_("Invalid number of arguments for option \"%s\""), entry->key);
3275                 break;
3276         }
3277
3278         WMReleasePropList(array);
3279
3280         return 0;
3281 }
3282
3283 /*
3284  static int
3285  setButtonImages(WScreen *scr, WDefaultEntry *entry, int *value, void *foo)
3286  {
3287  return REFRESH_BUTTON_IMAGES;
3288  }
3289  */
3290
3291 /*
3292  * Very ugly kluge.
3293  * Need access to the double click variables, so that all widgets in
3294  * wmaker panels will have the same dbl-click values.
3295  * TODO: figure a better way of dealing with it.
3296  */
3297 #include <WINGs/WINGsP.h>
3298
3299 static int setDoubleClick(WScreen * scr, WDefaultEntry * entry, int *value, void *foo)
3300 {
3301         extern _WINGsConfiguration WINGsConfiguration;
3302
3303         if (*value <= 0)
3304                 *(int *)foo = 1;
3305
3306         WINGsConfiguration.doubleClickDelay = *value;
3307
3308         return 0;
3309 }
3310
3311 static int setCursor(WScreen * scr, WDefaultEntry * entry, Cursor * cursor, long widx)
3312 {
3313         if (wCursor[widx] != None) {
3314                 XFreeCursor(dpy, wCursor[widx]);
3315         }
3316
3317         wCursor[widx] = *cursor;
3318
3319         if (widx == WCUR_ROOT && *cursor != None) {
3320                 XDefineCursor(dpy, scr->root_win, *cursor);
3321         }
3322
3323         return 0;
3324 }