1 /* WPrefs.c- main window and other basic stuff
2  *
3  *  WPrefs - Window Maker Preferences Program
4  *
5  *  Copyright (c) 1998-2003 Alfredo K. Kojima
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License along
18  *  with this program; if not, write to the Free Software Foundation, Inc.,
19  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include "config.h"
23 
24 #include "WPrefs.h"
25 #include <assert.h>
26 
27 #ifdef HAVE_STDNORETURN
28 #include <stdnoreturn.h>
29 #endif
30 
31 
32 #define MAX_SECTIONS 16
33 
34 typedef struct _WPrefs {
35 	WMWindow *win;
36 
37 	WMScrollView *scrollV;
38 	WMFrame *buttonF;
39 	WMButton *sectionB[MAX_SECTIONS];
40 
41 	int sectionCount;
42 
43 	WMButton *saveBtn;
44 	WMButton *closeBtn;
45 	WMButton *undoBtn;
46 	WMButton *undosBtn;
47 
48 	WMButton *balloonBtn;
49 
50 	WMFrame *banner;
51 	WMLabel *nameL;
52 	WMLabel *versionL;
53 	WMLabel *statusL;
54 
55 	Panel *currentPanel;
56 } _WPrefs;
57 
58 static _WPrefs WPrefs;
59 
60 /* system wide defaults dictionary. Read-only */
61 static WMPropList *GlobalDB = NULL;
62 /* user defaults dictionary */
63 static WMPropList *WindowMakerDB = NULL;
64 static char *WindowMakerDBPath = NULL;
65 
66 static Bool TIFFOK = False;
67 
68 #define INITIALIZED_PANEL	(1<<0)
69 
70 static void loadConfigurations(WMScreen * scr, WMWindow * mainw);
71 
72 static void savePanelData(Panel * panel);
73 
74 static void prepareForClose(void);
75 
quit(WMWidget * w,void * data)76 static noreturn void quit(WMWidget *w, void *data)
77 {
78 	/* Parameter not used, but tell the compiler that it is ok */
79 	(void) w;
80 	(void) data;
81 
82 	prepareForClose();
83 
84 	WMReleaseApplication();
85 	exit(0);
86 }
87 
save(WMWidget * w,void * data)88 static void save(WMWidget * w, void *data)
89 {
90 	int i;
91 	WMPropList *p1, *p2;
92 	WMPropList *keyList;
93 	WMPropList *key;
94 	XEvent ev;
95 
96 	/* Parameter not used, but tell the compiler that it is ok */
97 	(void) data;
98 
99 	/*    puts("gathering data"); */
100 	for (i = 0; i < WPrefs.sectionCount; i++) {
101 		PanelRec *rec = WMGetHangedData(WPrefs.sectionB[i]);
102 		if ((rec->callbacks.flags & INITIALIZED_PANEL))
103 			savePanelData((Panel *) rec);
104 	}
105 	/*    puts("compressing data"); */
106 	/* compare the user dictionary with the global and remove redundant data */
107 	keyList = WMGetPLDictionaryKeys(GlobalDB);
108 	/*    puts(WMGetPropListDescription(WindowMakerDB, False)); */
109 	for (i = 0; i < WMGetPropListItemCount(keyList); i++) {
110 		key = WMGetFromPLArray(keyList, i);
111 
112 		/* We don't have this value anyway, so no problem.
113 		 * Probably  a new option */
114 		p1 = WMGetFromPLDictionary(WindowMakerDB, key);
115 		if (!p1)
116 			continue;
117 		/* The global doesn't have it, so no problem either. */
118 		p2 = WMGetFromPLDictionary(GlobalDB, key);
119 		if (!p2)
120 			continue;
121 		/* If both values are the same, don't save. */
122 		if (WMIsPropListEqualTo(p1, p2))
123 			WMRemoveFromPLDictionary(WindowMakerDB, key);
124 	}
125 	/*    puts(WMGetPropListDescription(WindowMakerDB, False)); */
126 	WMReleasePropList(keyList);
127 	/*    puts("storing data"); */
128 
129 	WMWritePropListToFile(WindowMakerDB, WindowMakerDBPath);
130 
131 	memset(&ev, 0, sizeof(XEvent));
132 
133 	ev.xclient.type = ClientMessage;
134 	ev.xclient.message_type = XInternAtom(WMScreenDisplay(WMWidgetScreen(w)), "_WINDOWMAKER_COMMAND", False);
135 	ev.xclient.window = DefaultRootWindow(WMScreenDisplay(WMWidgetScreen(w)));
136 	ev.xclient.format = 8;
137 	strncpy(ev.xclient.data.b, "Reconfigure", sizeof(ev.xclient.data.b));
138 
139 	XSendEvent(WMScreenDisplay(WMWidgetScreen(w)),
140 		   DefaultRootWindow(WMScreenDisplay(WMWidgetScreen(w))), False, SubstructureRedirectMask, &ev);
141 	XFlush(WMScreenDisplay(WMWidgetScreen(w)));
142 }
143 
undo(WMWidget * w,void * data)144 static void undo(WMWidget * w, void *data)
145 {
146 	PanelRec *rec = (PanelRec *) WPrefs.currentPanel;
147 
148 	/* Parameter not used, but tell the compiler that it is ok */
149 	(void) w;
150 	(void) data;
151 
152 	if (!rec)
153 		return;
154 
155 	if (rec->callbacks.undoChanges && (rec->callbacks.flags & INITIALIZED_PANEL)) {
156 		(*rec->callbacks.undoChanges) (WPrefs.currentPanel);
157 	}
158 }
159 
undoAll(WMWidget * w,void * data)160 static void undoAll(WMWidget * w, void *data)
161 {
162 	int i;
163 
164 	/* Parameter not used, but tell the compiler that it is ok */
165 	(void) w;
166 	(void) data;
167 
168 	for (i = 0; i < WPrefs.sectionCount; i++) {
169 		PanelRec *rec = WMGetHangedData(WPrefs.sectionB[i]);
170 
171 		if (rec->callbacks.undoChanges && (rec->callbacks.flags & INITIALIZED_PANEL))
172 			(*rec->callbacks.undoChanges) ((Panel *) rec);
173 	}
174 }
175 
prepareForClose(void)176 static void prepareForClose(void)
177 {
178 	int i;
179 
180 	for (i = 0; i < WPrefs.sectionCount; i++) {
181 		PanelRec *rec = WMGetHangedData(WPrefs.sectionB[i]);
182 
183 		if (rec->callbacks.prepareForClose && (rec->callbacks.flags & INITIALIZED_PANEL))
184 			(*rec->callbacks.prepareForClose) ((Panel *) rec);
185 	}
186 }
187 
toggleBalloons(WMWidget * w,void * data)188 static void toggleBalloons(WMWidget *w, void *data)
189 {
190 	WMUserDefaults *udb = WMGetStandardUserDefaults();
191 	Bool flag;
192 
193 	/* Parameter not used, but tell the compiler that it is ok */
194 	(void) w;
195 	(void) data;
196 
197 	flag = WMGetButtonSelected(WPrefs.balloonBtn);
198 
199 	WMSetBalloonEnabled(WMWidgetScreen(WPrefs.win), flag);
200 
201 	WMSetUDBoolForKey(udb, flag, "BalloonHelp");
202 }
203 
createMainWindow(WMScreen * scr)204 static void createMainWindow(WMScreen * scr)
205 {
206 	WMScroller *scroller;
207 	WMFont *font;
208 	char buffer[128];
209 
210 	WPrefs.win = WMCreateWindow(scr, "wprefs");
211 	WMResizeWidget(WPrefs.win, 520, 390);
212 	WMSetWindowTitle(WPrefs.win, _("Window Maker Preferences"));
213 	WMSetWindowCloseAction(WPrefs.win, quit, NULL);
214 	WMSetWindowMaxSize(WPrefs.win, 520, 390);
215 	WMSetWindowMinSize(WPrefs.win, 520, 390);
216 	WMSetWindowMiniwindowTitle(WPrefs.win, _("Preferences"));
217 
218 	WPrefs.scrollV = WMCreateScrollView(WPrefs.win);
219 	WMResizeWidget(WPrefs.scrollV, 500, 87);
220 	WMMoveWidget(WPrefs.scrollV, 10, 10);
221 	WMSetScrollViewRelief(WPrefs.scrollV, WRSunken);
222 	WMSetScrollViewHasHorizontalScroller(WPrefs.scrollV, True);
223 	WMSetScrollViewHasVerticalScroller(WPrefs.scrollV, False);
224 	scroller = WMGetScrollViewHorizontalScroller(WPrefs.scrollV);
225 	WMSetScrollerArrowsPosition(scroller, WSANone);
226 
227 	WPrefs.buttonF = WMCreateFrame(WPrefs.win);
228 	WMSetFrameRelief(WPrefs.buttonF, WRFlat);
229 
230 	WMSetScrollViewContentView(WPrefs.scrollV, WMWidgetView(WPrefs.buttonF));
231 
232 	WPrefs.undosBtn = WMCreateCommandButton(WPrefs.win);
233 	WMResizeWidget(WPrefs.undosBtn, 90, 28);
234 	WMMoveWidget(WPrefs.undosBtn, 135, 350);
235 	WMSetButtonText(WPrefs.undosBtn, _("Revert Page"));
236 	WMSetButtonAction(WPrefs.undosBtn, undo, NULL);
237 
238 	WPrefs.undoBtn = WMCreateCommandButton(WPrefs.win);
239 	WMResizeWidget(WPrefs.undoBtn, 90, 28);
240 	WMMoveWidget(WPrefs.undoBtn, 235, 350);
241 	WMSetButtonText(WPrefs.undoBtn, _("Revert All"));
242 	WMSetButtonAction(WPrefs.undoBtn, undoAll, NULL);
243 
244 	WPrefs.saveBtn = WMCreateCommandButton(WPrefs.win);
245 	WMResizeWidget(WPrefs.saveBtn, 80, 28);
246 	WMMoveWidget(WPrefs.saveBtn, 335, 350);
247 	WMSetButtonText(WPrefs.saveBtn, _("Save"));
248 	WMSetButtonAction(WPrefs.saveBtn, save, NULL);
249 
250 	WPrefs.closeBtn = WMCreateCommandButton(WPrefs.win);
251 	WMResizeWidget(WPrefs.closeBtn, 80, 28);
252 	WMMoveWidget(WPrefs.closeBtn, 425, 350);
253 	WMSetButtonText(WPrefs.closeBtn, _("Close"));
254 	WMSetButtonAction(WPrefs.closeBtn, quit, NULL);
255 
256 	WPrefs.balloonBtn = WMCreateSwitchButton(WPrefs.win);
257 	WMResizeWidget(WPrefs.balloonBtn, 200, 28);
258 	WMMoveWidget(WPrefs.balloonBtn, 15, 350);
259 	WMSetButtonText(WPrefs.balloonBtn, _("Balloon Help"));
260 	WMSetButtonAction(WPrefs.balloonBtn, toggleBalloons, NULL);
261 	{
262 		WMUserDefaults *udb = WMGetStandardUserDefaults();
263 		Bool flag = WMGetUDBoolForKey(udb, "BalloonHelp");
264 
265 		WMSetButtonSelected(WPrefs.balloonBtn, flag);
266 		WMSetBalloonEnabled(scr, flag);
267 	}
268 
269 	/* banner */
270 	WPrefs.banner = WMCreateFrame(WPrefs.win);
271 	WMResizeWidget(WPrefs.banner, FRAME_WIDTH, FRAME_HEIGHT);
272 	WMMoveWidget(WPrefs.banner, FRAME_LEFT, FRAME_TOP);
273 	WMSetFrameRelief(WPrefs.banner, WRFlat);
274 
275 	font = WMCreateFont(scr, "Lucida Sans,URW Gothic L,Times New Roman,serif"
276 			    ":bold:pixelsize=26:antialias=true");
277 	WPrefs.nameL = WMCreateLabel(WPrefs.banner);
278 	WMSetLabelTextAlignment(WPrefs.nameL, WACenter);
279 	WMResizeWidget(WPrefs.nameL, FRAME_WIDTH - 20, 60);
280 	WMMoveWidget(WPrefs.nameL, 10, 50);
281 	WMSetLabelFont(WPrefs.nameL, font);
282 	WMSetLabelText(WPrefs.nameL, _("Window Maker Preferences"));
283 	WMReleaseFont(font);
284 
285 	WPrefs.versionL = WMCreateLabel(WPrefs.banner);
286 	WMResizeWidget(WPrefs.versionL, FRAME_WIDTH - 20, 20);
287 	WMMoveWidget(WPrefs.versionL, 10, 120);
288 	WMSetLabelTextAlignment(WPrefs.versionL, WACenter);
289 	sprintf(buffer, _("Version %s"), VERSION);
290 	WMSetLabelText(WPrefs.versionL, buffer);
291 
292 	WPrefs.statusL = WMCreateLabel(WPrefs.banner);
293 	WMResizeWidget(WPrefs.statusL, FRAME_WIDTH - 20, 60);
294 	WMMoveWidget(WPrefs.statusL, 10, 150);
295 	WMSetLabelTextAlignment(WPrefs.statusL, WACenter);
296 	WMSetLabelText(WPrefs.statusL, _("Starting..."));
297 
298 	WMMapSubwidgets(WPrefs.win);
299 
300 	WMUnmapWidget(WPrefs.undosBtn);
301 	WMUnmapWidget(WPrefs.undoBtn);
302 	WMUnmapWidget(WPrefs.saveBtn);
303 }
304 
showPanel(Panel * panel)305 static void showPanel(Panel * panel)
306 {
307 	PanelRec *rec = (PanelRec *) panel;
308 
309 	if (!(rec->callbacks.flags & INITIALIZED_PANEL)) {
310 		(*rec->callbacks.createWidgets) (panel);
311 		rec->callbacks.flags |= INITIALIZED_PANEL;
312 	}
313 
314 	WMSetWindowTitle(WPrefs.win, rec->sectionName);
315 
316 	if (rec->callbacks.showPanel)
317 		(*rec->callbacks.showPanel) (panel);
318 
319 	WMMapWidget(rec->box);
320 }
321 
hidePanel(Panel * panel)322 static void hidePanel(Panel * panel)
323 {
324 	PanelRec *rec = (PanelRec *) panel;
325 
326 	WMUnmapWidget(rec->box);
327 
328 	if (rec->callbacks.hidePanel)
329 		(*rec->callbacks.hidePanel) (panel);
330 }
331 
savePanelData(Panel * panel)332 static void savePanelData(Panel * panel)
333 {
334 	PanelRec *rec = (PanelRec *) panel;
335 
336 	if (rec->callbacks.updateDomain) {
337 		(*rec->callbacks.updateDomain) (panel);
338 	}
339 }
340 
changeSection(WMWidget * self,void * data)341 static void changeSection(WMWidget * self, void *data)
342 {
343 	/* Parameter not used, but tell the compiler that it is ok */
344 	(void) self;
345 
346 	if (WPrefs.currentPanel == data)
347 		return;
348 
349 	if (WPrefs.currentPanel == NULL) {
350 		WMDestroyWidget(WPrefs.nameL);
351 		WMDestroyWidget(WPrefs.versionL);
352 		WMDestroyWidget(WPrefs.statusL);
353 
354 		WMSetFrameRelief(WPrefs.banner, WRGroove);
355 
356 		/*      WMMapWidget(WPrefs.undosBtn);
357 		   WMMapWidget(WPrefs.undoBtn);
358 		 */
359 		WMMapWidget(WPrefs.saveBtn);
360 	}
361 
362 	showPanel(data);
363 
364 	if (WPrefs.currentPanel)
365 		hidePanel(WPrefs.currentPanel);
366 	WPrefs.currentPanel = data;
367 }
368 
LocateImage(const char * name)369 char *LocateImage(const char *name)
370 {
371 	char *path;
372 	char *tmp = wmalloc(strlen(name) + 8);
373 
374 	if (TIFFOK) {
375 		sprintf(tmp, "%s.tiff", name);
376 		path = WMPathForResourceOfType(tmp, "tiff");
377 	} else {
378 		sprintf(tmp, "%s.xpm", name);
379 		path = WMPathForResourceOfType(tmp, "xpm");
380 	}
381 	wfree(tmp);
382 	if (!path) {
383 		wwarning(_("could not locate image file %s"), name);
384 	}
385 
386 	return path;
387 }
388 
CreateImages(WMScreen * scr,RContext * rc,RImage * xis,const char * file,WMPixmap ** icon_normal,WMPixmap ** icon_greyed)389 void CreateImages(WMScreen *scr, RContext *rc, RImage *xis, const char *file,
390 		WMPixmap **icon_normal, WMPixmap **icon_greyed)
391 {
392 	RImage *icon;
393 	char *path;
394 	RColor gray = { 0xae, 0xaa, 0xae, 0 };
395 
396 	path = LocateImage(file);
397 	if (!path)
398 	{
399 		*icon_normal = NULL;
400 		if (icon_greyed)
401 			*icon_greyed = NULL;
402 		return;
403 	}
404 
405 	*icon_normal = WMCreatePixmapFromFile(scr, path);
406 	if (!*icon_normal)
407 	{
408 		wwarning(_("could not load icon %s"), path);
409 		if (icon_greyed)
410 			*icon_greyed = NULL;
411 		wfree(path);
412 		return;
413 	}
414 
415 	if (!icon_greyed) // Greyed-out version not requested, we are done
416 	{
417 		wfree(path);
418 		return;
419 	}
420 
421 	icon = RLoadImage(rc, path, 0);
422 	if (!icon)
423 	{
424 		wwarning(_("could not load icon %s"), path);
425 		*icon_greyed = NULL;
426 		wfree(path);
427 		return;
428 	}
429 	RCombineImageWithColor(icon, &gray);
430 	if (xis)
431 	{
432 		RCombineImagesWithOpaqueness(icon, xis, 180);
433 	}
434 	*icon_greyed = WMCreatePixmapFromRImage(scr, icon, 127);
435 	if (!*icon_greyed)
436 	{
437 		wwarning(_("could not process icon %s: %s"), path, RMessageForError(RErrorCode));
438 	}
439 	RReleaseImage(icon);
440 	wfree(path);
441 }
442 
443 
SetButtonAlphaImage(WMScreen * scr,WMButton * bPtr,const char * file)444 void SetButtonAlphaImage(WMScreen *scr, WMButton *bPtr, const char *file)
445 {
446 	WMPixmap *icon;
447 	RColor color;
448 	char *iconPath;
449 
450 	iconPath = LocateImage(file);
451 
452 	color.red = 0xae;
453 	color.green = 0xaa;
454 	color.blue = 0xae;
455 	color.alpha = 0;
456 	if (iconPath) {
457 		icon = WMCreateBlendedPixmapFromFile(scr, iconPath, &color);
458 		if (!icon)
459 			wwarning(_("could not load icon file %s"), iconPath);
460 	} else {
461 		icon = NULL;
462 	}
463 
464 	WMSetButtonImage(bPtr, icon);
465 
466 	color.red = 0xff;
467 	color.green = 0xff;
468 	color.blue = 0xff;
469 	color.alpha = 0;
470 	if (iconPath) {
471 		icon = WMCreateBlendedPixmapFromFile(scr, iconPath, &color);
472 		if (!icon)
473 			wwarning(_("could not load icon file %s"), iconPath);
474 	} else {
475 		icon = NULL;
476 	}
477 
478 	WMSetButtonAltImage(bPtr, icon);
479 
480 	if (icon)
481 		WMReleasePixmap(icon);
482 
483 	if (iconPath)
484 		wfree(iconPath);
485 }
486 
AddSection(Panel * panel,const char * iconFile)487 void AddSection(Panel * panel, const char *iconFile)
488 {
489 	WMButton *bPtr;
490 
491 	assert(WPrefs.sectionCount < MAX_SECTIONS);
492 
493 	bPtr = WMCreateCustomButton(WPrefs.buttonF, WBBStateLightMask | WBBStateChangeMask);
494 	WMResizeWidget(bPtr, 64, 64);
495 	WMMoveWidget(bPtr, WPrefs.sectionCount * 64, 0);
496 	WMSetButtonImagePosition(bPtr, WIPImageOnly);
497 	WMSetButtonAction(bPtr, changeSection, panel);
498 	WMHangData(bPtr, panel);
499 
500 	WMSetBalloonTextForView(((PanelRec *) panel)->description, WMWidgetView(bPtr));
501 	SetButtonAlphaImage(WMWidgetScreen(bPtr), bPtr, iconFile);
502 	WMMapWidget(bPtr);
503 
504 	WPrefs.sectionB[WPrefs.sectionCount] = bPtr;
505 
506 	if (WPrefs.sectionCount > 0)
507 		WMGroupButtons(WPrefs.sectionB[0], bPtr);
508 
509 	WPrefs.sectionCount++;
510 
511 	WMResizeWidget(WPrefs.buttonF, WPrefs.sectionCount * 64, 64);
512 }
513 
Initialize(WMScreen * scr)514 void Initialize(WMScreen * scr)
515 {
516 	char **list;
517 	int i;
518 	char *path;
519 
520 	list = RSupportedFileFormats();
521 	for (i = 0; list[i] != NULL; i++) {
522 		if (strcmp(list[i], "TIFF") == 0) {
523 			TIFFOK = True;
524 			break;
525 		}
526 	}
527 
528 	if (TIFFOK)
529 		path = WMPathForResourceOfType("WPrefs.tiff", NULL);
530 	else
531 		path = WMPathForResourceOfType("WPrefs.xpm", NULL);
532 	if (path) {
533 		RImage *tmp;
534 
535 		tmp = RLoadImage(WMScreenRContext(scr), path, 0);
536 		if (!tmp) {
537 			wwarning(_("could not load image file %s:%s"), path, RMessageForError(RErrorCode));
538 		} else {
539 			WMSetApplicationIconImage(scr, tmp);
540 			RReleaseImage(tmp);
541 		}
542 		wfree(path);
543 	}
544 
545 	memset(&WPrefs, 0, sizeof(_WPrefs));
546 	createMainWindow(scr);
547 
548 	WMRealizeWidget(WPrefs.win);
549 
550 	WMSetWindowMiniwindowImage(WPrefs.win, WMGetApplicationIconImage(scr));
551 
552 	WMMapWidget(WPrefs.win);
553 	XFlush(WMScreenDisplay(scr));
554 	WMSetLabelText(WPrefs.statusL, _("Loading Window Maker configuration files..."));
555 	XFlush(WMScreenDisplay(scr));
556 	loadConfigurations(scr, WPrefs.win);
557 
558 	WMSetLabelText(WPrefs.statusL, _("Initializing configuration panels..."));
559 
560 	InitFocus(WPrefs.banner);
561 	InitWindowHandling(WPrefs.banner);
562 
563 	InitMenuPreferences(WPrefs.banner);
564 	InitIcons(WPrefs.banner);
565 	InitPreferences(WPrefs.banner);
566 
567 	InitPaths(WPrefs.banner);
568 	InitDocks(WPrefs.banner);
569 	InitWorkspace(WPrefs.banner);
570 	InitConfigurations(WPrefs.banner);
571 
572 	InitMenu(WPrefs.banner);
573 
574 #ifdef not_yet_fully_implemented
575 	InitKeyboardSettings(WPrefs.banner);
576 #endif
577 	InitKeyboardShortcuts(WPrefs.banner);
578 	InitMouseSettings(WPrefs.banner);
579 
580 	InitAppearance(WPrefs.banner);
581 
582 	InitFontSimple(WPrefs.banner);
583 
584 #ifdef not_yet_fully_implemented
585 	InitThemes(WPrefs.banner);
586 #endif
587 	InitExpert(WPrefs.banner);
588 
589 	WMRealizeWidget(WPrefs.scrollV);
590 
591 	WMSetLabelText(WPrefs.statusL, "");
592 }
593 
GetWindow(void)594 WMWindow *GetWindow(void)
595 {
596 	return WPrefs.win;
597 }
598 
loadConfigurations(WMScreen * scr,WMWindow * mainw)599 static void loadConfigurations(WMScreen * scr, WMWindow * mainw)
600 {
601 	WMPropList *db, *gdb;
602 	char *path;
603 	FILE *file;
604 	char buffer[1024];
605 	char mbuf[1069]; /* Size of buffer and extra characters for the sprintfs */
606 	int v1, v2, v3;
607 
608 	path = wdefaultspathfordomain("WindowMaker");
609 	WindowMakerDBPath = path;
610 
611 	db = WMReadPropListFromFile(path);
612 	if (db) {
613 		if (!WMIsPLDictionary(db)) {
614 			WMReleasePropList(db);
615 			db = NULL;
616 			sprintf(mbuf, _("Window Maker domain (%s) is corrupted!"), path);
617 			WMRunAlertPanel(scr, mainw, _("Error"), mbuf, _("OK"), NULL, NULL);
618 		}
619 	} else {
620 		sprintf(mbuf, _("Could not load Window Maker domain (%s) from defaults database."), path);
621 		WMRunAlertPanel(scr, mainw, _("Error"), mbuf, _("OK"), NULL, NULL);
622 	}
623 
624 	path = getenv("WMAKER_BIN_NAME");
625 	if (!path)
626 		path = "wmaker";
627 	{
628 		char *command;
629 
630 		command = wstrconcat(path, " --version");
631 		file = popen(command, "r");
632 		wfree(command);
633 	}
634 	if (!file || !fgets(buffer, 1023, file)) {
635 		werror(_("could not extract version information from Window Maker"));
636 		wfatal(_("Make sure wmaker is in your search path."));
637 
638 		WMRunAlertPanel(scr, mainw, _("Error"),
639 				_
640 				("Could not extract version from Window Maker. Make sure it is correctly installed and is in your PATH environment variable."),
641 				_("OK"), NULL, NULL);
642 		exit(1);
643 	}
644 	if (file)
645 		pclose(file);
646 
647 	if (sscanf(buffer, "Window Maker %i.%i.%i", &v1, &v2, &v3) != 3
648 	    && sscanf(buffer, "WindowMaker %i.%i.%i", &v1, &v2, &v3) != 3) {
649 		WMRunAlertPanel(scr, mainw, _("Error"),
650 				_("Could not extract version from Window Maker. "
651 				  "Make sure it is correctly installed and the path "
652 				  "where it installed is in the PATH environment "
653 				  "variable."), _("OK"), NULL, NULL);
654 		exit(1);
655 	}
656 	if (v1 == 0 && (v2 < 18 || v3 < 0)) {
657 		sprintf(mbuf, _("WPrefs only supports Window Maker 0.18.0 or newer.\n"
658 				"The version installed is %i.%i.%i\n"), v1, v2, v3);
659 		WMRunAlertPanel(scr, mainw, _("Error"), mbuf, _("OK"), NULL, NULL);
660 		exit(1);
661 
662 	}
663 	if (v1 > 1 || (v1 == 1 && (v2 > 0))) {
664 		sprintf(mbuf,
665 			_
666 			("Window Maker %i.%i.%i, which is installed in your system, is not fully supported by this version of WPrefs."),
667 			v1, v2, v3);
668 		WMRunAlertPanel(scr, mainw, _("Warning"), mbuf, _("OK"), NULL, NULL);
669 	}
670 
671 	{
672 		char *command;
673 
674 		command = wstrconcat(path, " --global_defaults_path");
675 		file = popen(command, "r");
676 		wfree(command);
677 	}
678 	if (!file || !fgets(buffer, 1023, file)) {
679 		werror(_("could not run \"%s --global_defaults_path\"."), path);
680 		exit(1);
681 	} else {
682 		char *ptr;
683 		ptr = strchr(buffer, '\n');
684 		if (ptr)
685 			*ptr = 0;
686 		strcat(buffer, "/WindowMaker");
687 	}
688 
689 	if (file)
690 		pclose(file);
691 
692 	gdb = WMReadPropListFromFile(buffer);
693 
694 	if (gdb) {
695 		if (!WMIsPLDictionary(gdb)) {
696 			WMReleasePropList(gdb);
697 			gdb = NULL;
698 			sprintf(mbuf, _("Window Maker domain (%s) is corrupted!"), buffer);
699 			WMRunAlertPanel(scr, mainw, _("Error"), mbuf, _("OK"), NULL, NULL);
700 		}
701 	} else {
702 		sprintf(mbuf, _("Could not load global Window Maker domain (%s)."), buffer);
703 		WMRunAlertPanel(scr, mainw, _("Error"), mbuf, _("OK"), NULL, NULL);
704 	}
705 
706 	if (!db) {
707 		db = WMCreatePLDictionary(NULL, NULL);
708 	}
709 	if (!gdb) {
710 		gdb = WMCreatePLDictionary(NULL, NULL);
711 	}
712 
713 	GlobalDB = gdb;
714 
715 	WindowMakerDB = db;
716 }
717 
GetObjectForKey(const char * defaultName)718 WMPropList *GetObjectForKey(const char *defaultName)
719 {
720 	WMPropList *object = NULL;
721 	WMPropList *key = WMCreatePLString(defaultName);
722 
723 	object = WMGetFromPLDictionary(WindowMakerDB, key);
724 	if (!object)
725 		object = WMGetFromPLDictionary(GlobalDB, key);
726 
727 	WMReleasePropList(key);
728 
729 	return object;
730 }
731 
SetObjectForKey(WMPropList * object,const char * defaultName)732 void SetObjectForKey(WMPropList * object, const char *defaultName)
733 {
734 	WMPropList *key = WMCreatePLString(defaultName);
735 
736 	WMPutInPLDictionary(WindowMakerDB, key, object);
737 	WMReleasePropList(key);
738 }
739 
RemoveObjectForKey(const char * defaultName)740 void RemoveObjectForKey(const char *defaultName)
741 {
742 	WMPropList *key = WMCreatePLString(defaultName);
743 
744 	WMRemoveFromPLDictionary(WindowMakerDB, key);
745 
746 	WMReleasePropList(key);
747 }
748 
GetStringForKey(const char * defaultName)749 char *GetStringForKey(const char *defaultName)
750 {
751 	WMPropList *val;
752 
753 	val = GetObjectForKey(defaultName);
754 
755 	if (!val)
756 		return NULL;
757 
758 	if (!WMIsPLString(val))
759 		return NULL;
760 
761 	return WMGetFromPLString(val);
762 }
763 
GetArrayForKey(const char * defaultName)764 WMPropList *GetArrayForKey(const char *defaultName)
765 {
766 	WMPropList *val;
767 
768 	val = GetObjectForKey(defaultName);
769 
770 	if (!val)
771 		return NULL;
772 
773 	if (!WMIsPLArray(val))
774 		return NULL;
775 
776 	return val;
777 }
778 
GetDictionaryForKey(const char * defaultName)779 WMPropList *GetDictionaryForKey(const char *defaultName)
780 {
781 	WMPropList *val;
782 
783 	val = GetObjectForKey(defaultName);
784 
785 	if (!val)
786 		return NULL;
787 
788 	if (!WMIsPLDictionary(val))
789 		return NULL;
790 
791 	return val;
792 }
793 
GetIntegerForKey(const char * defaultName)794 int GetIntegerForKey(const char *defaultName)
795 {
796 	WMPropList *val;
797 	char *str;
798 	int value;
799 
800 	val = GetObjectForKey(defaultName);
801 
802 	if (!val)
803 		return 0;
804 
805 	if (!WMIsPLString(val))
806 		return 0;
807 
808 	str = WMGetFromPLString(val);
809 	if (!str)
810 		return 0;
811 
812 	if (sscanf(str, "%i", &value) != 1)
813 		return 0;
814 
815 	return value;
816 }
817 
GetBoolForKey(const char * defaultName)818 Bool GetBoolForKey(const char *defaultName)
819 {
820 	int value;
821 	char *str;
822 
823 	str = GetStringForKey(defaultName);
824 
825 	if (!str)
826 		return False;
827 
828 	if (sscanf(str, "%i", &value) == 1 && value != 0)
829 		return True;
830 
831 	if (strcasecmp(str, "YES") == 0)
832 		return True;
833 
834 	if (strcasecmp(str, "Y") == 0)
835 		return True;
836 
837 	return False;
838 }
839 
SetIntegerForKey(int value,const char * defaultName)840 void SetIntegerForKey(int value, const char *defaultName)
841 {
842 	WMPropList *object;
843 	char buffer[128];
844 
845 	sprintf(buffer, "%i", value);
846 	object = WMCreatePLString(buffer);
847 
848 	SetObjectForKey(object, defaultName);
849 	WMReleasePropList(object);
850 }
851 
SetStringForKey(const char * value,const char * defaultName)852 void SetStringForKey(const char *value, const char *defaultName)
853 {
854 	WMPropList *object;
855 
856 	object = WMCreatePLString(value);
857 
858 	SetObjectForKey(object, defaultName);
859 	WMReleasePropList(object);
860 }
861 
SetBoolForKey(Bool value,const char * defaultName)862 void SetBoolForKey(Bool value, const char *defaultName)
863 {
864 	static WMPropList *yes = NULL, *no = NULL;
865 
866 	if (!yes) {
867 		yes = WMCreatePLString("YES");
868 		no = WMCreatePLString("NO");
869 	}
870 
871 	SetObjectForKey(value ? yes : no, defaultName);
872 }
873 
SetSpeedForKey(int speed,const char * defaultName)874 void SetSpeedForKey(int speed, const char *defaultName)
875 {
876 	char *str;
877 
878 	switch (speed) {
879 	case 0:
880 		str = "ultraslow";
881 		break;
882 	case 1:
883 		str = "slow";
884 		break;
885 	case 2:
886 		str = "medium";
887 		break;
888 	case 3:
889 		str = "fast";
890 		break;
891 	case 4:
892 		str = "ultrafast";
893 		break;
894 	default:
895 		str = NULL;
896 	}
897 
898 	if (str)
899 		SetStringForKey(str, defaultName);
900 }
901 
GetSpeedForKey(const char * defaultName)902 int GetSpeedForKey(const char *defaultName)
903 {
904 	char *str;
905 	int i;
906 
907 	str = GetStringForKey(defaultName);
908 	if (!str)
909 		return 2;
910 
911 	if (strcasecmp(str, "ultraslow") == 0)
912 		i = 0;
913 	else if (strcasecmp(str, "slow") == 0)
914 		i = 1;
915 	else if (strcasecmp(str, "medium") == 0)
916 		i = 2;
917 	else if (strcasecmp(str, "fast") == 0)
918 		i = 3;
919 	else if (strcasecmp(str, "ultrafast") == 0)
920 		i = 4;
921 	else {
922 		wwarning(_("bad speed value for option %s; using default Medium"), defaultName);
923 		i = 2;
924 	}
925 	return i;
926 }
927