WINGs: do not crash on NULL title in WMSetWindowTitle (Coverity #50046)
[wmaker-crm.git] / src / wdefaults.c
blob24d2598b10edd7aa712e90502ce1a7ef34610689
1 /* wdefaults.c - window specific defaults
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
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.
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.
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.
22 #include "wconfig.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <ctype.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/keysym.h>
35 #include <wraster.h>
37 #include "WindowMaker.h"
38 #include "window.h"
39 #include "appicon.h"
40 #include "screen.h"
41 #include "workspace.h"
42 #include "defaults.h"
43 #include "icon.h"
44 #include "misc.h"
46 #define APPLY_VAL(value, flag, attrib) \
47 if (value) {attr->flag = getBool(attrib, value); \
48 if (mask) mask->flag = 1;}
50 /* Local stuff */
52 /* type converters */
53 static int getBool(WMPropList *, WMPropList *);
54 static char *getString(WMPropList *, WMPropList *);
55 static WMPropList *ANoTitlebar = NULL;
56 static WMPropList *ANoResizebar;
57 static WMPropList *ANoMiniaturizeButton;
58 static WMPropList *ANoMiniaturizable;
59 static WMPropList *ANoCloseButton;
60 static WMPropList *ANoBorder;
61 static WMPropList *ANoHideOthers;
62 static WMPropList *ANoMouseBindings;
63 static WMPropList *ANoKeyBindings;
64 static WMPropList *ANoAppIcon; /* app */
65 static WMPropList *AKeepOnTop;
66 static WMPropList *AKeepOnBottom;
67 static WMPropList *AOmnipresent;
68 static WMPropList *ASkipWindowList;
69 static WMPropList *ASkipSwitchPanel;
70 static WMPropList *AKeepInsideScreen;
71 static WMPropList *AUnfocusable;
72 static WMPropList *AAlwaysUserIcon;
73 static WMPropList *AStartMiniaturized;
74 static WMPropList *AStartMaximized;
75 static WMPropList *AStartHidden; /* app */
76 static WMPropList *ADontSaveSession; /* app */
77 static WMPropList *AEmulateAppIcon;
78 static WMPropList *AFocusAcrossWorkspace;
79 static WMPropList *AFullMaximize;
80 static WMPropList *ASharedAppIcon; /* app */
81 #ifdef XKB_BUTTON_HINT
82 static WMPropList *ANoLanguageButton;
83 #endif
84 static WMPropList *AStartWorkspace;
85 static WMPropList *AIcon;
86 static WMPropList *AnyWindow;
87 static WMPropList *No;
89 static void init_wdefaults(void)
91 AIcon = WMCreatePLString("Icon");
93 ANoTitlebar = WMCreatePLString("NoTitlebar");
94 ANoResizebar = WMCreatePLString("NoResizebar");
95 ANoMiniaturizeButton = WMCreatePLString("NoMiniaturizeButton");
96 ANoMiniaturizable = WMCreatePLString("NoMiniaturizable");
97 ANoCloseButton = WMCreatePLString("NoCloseButton");
98 ANoBorder = WMCreatePLString("NoBorder");
99 ANoHideOthers = WMCreatePLString("NoHideOthers");
100 ANoMouseBindings = WMCreatePLString("NoMouseBindings");
101 ANoKeyBindings = WMCreatePLString("NoKeyBindings");
102 ANoAppIcon = WMCreatePLString("NoAppIcon");
103 AKeepOnTop = WMCreatePLString("KeepOnTop");
104 AKeepOnBottom = WMCreatePLString("KeepOnBottom");
105 AOmnipresent = WMCreatePLString("Omnipresent");
106 ASkipWindowList = WMCreatePLString("SkipWindowList");
107 ASkipSwitchPanel = WMCreatePLString("SkipSwitchPanel");
108 AKeepInsideScreen = WMCreatePLString("KeepInsideScreen");
109 AUnfocusable = WMCreatePLString("Unfocusable");
110 AAlwaysUserIcon = WMCreatePLString("AlwaysUserIcon");
111 AStartMiniaturized = WMCreatePLString("StartMiniaturized");
112 AStartHidden = WMCreatePLString("StartHidden");
113 AStartMaximized = WMCreatePLString("StartMaximized");
114 ADontSaveSession = WMCreatePLString("DontSaveSession");
115 AEmulateAppIcon = WMCreatePLString("EmulateAppIcon");
116 AFocusAcrossWorkspace = WMCreatePLString("FocusAcrossWorkspace");
117 AFullMaximize = WMCreatePLString("FullMaximize");
118 ASharedAppIcon = WMCreatePLString("SharedAppIcon");
119 #ifdef XKB_BUTTON_HINT
120 ANoLanguageButton = WMCreatePLString("NoLanguageButton");
121 #endif
123 AStartWorkspace = WMCreatePLString("StartWorkspace");
125 AnyWindow = WMCreatePLString("*");
126 No = WMCreatePLString("No");
129 /* Returns the correct WMPropList, using instance+class or instance, or class, or default */
130 static WMPropList *get_value(WMPropList * dict_win, WMPropList * dict_class, WMPropList * dict_name,
131 WMPropList * dict_any, WMPropList * option, WMPropList * default_value,
132 Bool useGlobalDefault)
134 WMPropList *value;
136 if (dict_win) {
137 value = WMGetFromPLDictionary(dict_win, option);
138 if (value)
139 return value;
142 if (dict_name) {
143 value = WMGetFromPLDictionary(dict_name, option);
144 if (value)
145 return value;
148 if (dict_class) {
149 value = WMGetFromPLDictionary(dict_class, option);
150 if (value)
151 return value;
154 if (!useGlobalDefault)
155 return NULL;
157 if (dict_any) {
158 value = WMGetFromPLDictionary(dict_any, option);
159 if (value)
160 return value;
163 return default_value;
166 static WMPropList *get_value_from_instanceclass(const char *value)
168 WMPropList *key, *val = NULL;
170 if (!value)
171 return NULL;
173 key = WMCreatePLString(value);
175 WMPLSetCaseSensitive(True);
177 if (w_global.domain.window_attr->dictionary)
178 val = key ? WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key) : NULL;
180 if (key)
181 WMReleasePropList(key);
183 WMPLSetCaseSensitive(False);
185 return val;
189 *----------------------------------------------------------------------
190 * wDefaultFillAttributes--
191 * Retrieves attributes for the specified instance/class and
192 * fills attr with it. Values that are actually defined are also
193 * set in mask. If useGlobalDefault is True, the default for
194 * all windows ("*") will be used for when no values are found
195 * for that instance/class.
197 *----------------------------------------------------------------------
199 void wDefaultFillAttributes(const char *instance, const char *class,
200 WWindowAttributes *attr, WWindowAttributes *mask,
201 Bool useGlobalDefault)
203 WMPropList *value, *dw, *dc, *dn, *da;
204 char *buffer;
206 dw = dc = dn = da = NULL;
208 if (!ANoTitlebar)
209 init_wdefaults();
211 if (class && instance) {
212 buffer = StrConcatDot(instance, class);
213 dw = get_value_from_instanceclass(buffer);
214 wfree(buffer);
217 dn = get_value_from_instanceclass(instance);
218 dc = get_value_from_instanceclass(class);
220 WMPLSetCaseSensitive(True);
222 if ((w_global.domain.window_attr->dictionary) && (useGlobalDefault))
223 da = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, AnyWindow);
225 /* get the data */
226 value = get_value(dw, dc, dn, da, ANoTitlebar, No, useGlobalDefault);
227 APPLY_VAL(value, no_titlebar, ANoTitlebar);
229 value = get_value(dw, dc, dn, da, ANoResizebar, No, useGlobalDefault);
230 APPLY_VAL(value, no_resizebar, ANoResizebar);
232 value = get_value(dw, dc, dn, da, ANoMiniaturizeButton, No, useGlobalDefault);
233 APPLY_VAL(value, no_miniaturize_button, ANoMiniaturizeButton);
235 value = get_value(dw, dc, dn, da, ANoMiniaturizable, No, useGlobalDefault);
236 APPLY_VAL(value, no_miniaturizable, ANoMiniaturizable);
238 value = get_value(dw, dc, dn, da, ANoCloseButton, No, useGlobalDefault);
239 APPLY_VAL(value, no_close_button, ANoCloseButton);
241 value = get_value(dw, dc, dn, da, ANoBorder, No, useGlobalDefault);
242 APPLY_VAL(value, no_border, ANoBorder);
244 value = get_value(dw, dc, dn, da, ANoHideOthers, No, useGlobalDefault);
245 APPLY_VAL(value, no_hide_others, ANoHideOthers);
247 value = get_value(dw, dc, dn, da, ANoMouseBindings, No, useGlobalDefault);
248 APPLY_VAL(value, no_bind_mouse, ANoMouseBindings);
250 value = get_value(dw, dc, dn, da, ANoKeyBindings, No, useGlobalDefault);
251 APPLY_VAL(value, no_bind_keys, ANoKeyBindings);
253 value = get_value(dw, dc, dn, da, ANoAppIcon, No, useGlobalDefault);
254 APPLY_VAL(value, no_appicon, ANoAppIcon);
256 value = get_value(dw, dc, dn, da, ASharedAppIcon, No, useGlobalDefault);
257 APPLY_VAL(value, shared_appicon, ASharedAppIcon);
259 value = get_value(dw, dc, dn, da, AKeepOnTop, No, useGlobalDefault);
260 APPLY_VAL(value, floating, AKeepOnTop);
262 value = get_value(dw, dc, dn, da, AKeepOnBottom, No, useGlobalDefault);
263 APPLY_VAL(value, sunken, AKeepOnBottom);
265 value = get_value(dw, dc, dn, da, AOmnipresent, No, useGlobalDefault);
266 APPLY_VAL(value, omnipresent, AOmnipresent);
268 value = get_value(dw, dc, dn, da, ASkipWindowList, No, useGlobalDefault);
269 APPLY_VAL(value, skip_window_list, ASkipWindowList);
271 value = get_value(dw, dc, dn, da, ASkipSwitchPanel, No, useGlobalDefault);
272 APPLY_VAL(value, skip_switchpanel, ASkipSwitchPanel);
274 value = get_value(dw, dc, dn, da, AKeepInsideScreen, No, useGlobalDefault);
275 APPLY_VAL(value, dont_move_off, AKeepInsideScreen);
277 value = get_value(dw, dc, dn, da, AUnfocusable, No, useGlobalDefault);
278 APPLY_VAL(value, no_focusable, AUnfocusable);
280 value = get_value(dw, dc, dn, da, AAlwaysUserIcon, No, useGlobalDefault);
281 APPLY_VAL(value, always_user_icon, AAlwaysUserIcon);
283 value = get_value(dw, dc, dn, da, AStartMiniaturized, No, useGlobalDefault);
284 APPLY_VAL(value, start_miniaturized, AStartMiniaturized);
286 value = get_value(dw, dc, dn, da, AStartHidden, No, useGlobalDefault);
287 APPLY_VAL(value, start_hidden, AStartHidden);
289 value = get_value(dw, dc, dn, da, AStartMaximized, No, useGlobalDefault);
290 APPLY_VAL(value, start_maximized, AStartMaximized);
292 value = get_value(dw, dc, dn, da, ADontSaveSession, No, useGlobalDefault);
293 APPLY_VAL(value, dont_save_session, ADontSaveSession);
295 value = get_value(dw, dc, dn, da, AEmulateAppIcon, No, useGlobalDefault);
296 APPLY_VAL(value, emulate_appicon, AEmulateAppIcon);
298 value = get_value(dw, dc, dn, da, AFocusAcrossWorkspace, No, useGlobalDefault);
299 APPLY_VAL(value, focus_across_wksp, AFocusAcrossWorkspace);
301 value = get_value(dw, dc, dn, da, AFullMaximize, No, useGlobalDefault);
302 APPLY_VAL(value, full_maximize, AFullMaximize);
304 #ifdef XKB_BUTTON_HINT
305 value = get_value(dw, dc, dn, da, ANoLanguageButton, No, useGlobalDefault);
306 APPLY_VAL(value, no_language_button, ANoLanguageButton);
307 #endif
309 /* clean up */
310 WMPLSetCaseSensitive(False);
313 static WMPropList *get_generic_value(const char *instance, const char *class,
314 WMPropList *option, Bool default_icon)
316 WMPropList *value, *key, *dict;
318 value = NULL;
320 WMPLSetCaseSensitive(True);
322 /* Search the icon name using class and instance */
323 if (class && instance) {
324 char *buffer;
326 buffer = wmalloc(strlen(class) + strlen(instance) + 2);
327 sprintf(buffer, "%s.%s", instance, class);
328 key = WMCreatePLString(buffer);
329 wfree(buffer);
331 dict = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key);
332 WMReleasePropList(key);
334 if (dict)
335 value = WMGetFromPLDictionary(dict, option);
338 /* Search the icon name using instance */
339 if (!value && instance) {
340 key = WMCreatePLString(instance);
342 dict = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key);
343 WMReleasePropList(key);
345 if (dict)
346 value = WMGetFromPLDictionary(dict, option);
349 /* Search the icon name using class */
350 if (!value && class) {
351 key = WMCreatePLString(class);
353 dict = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key);
354 WMReleasePropList(key);
356 if (dict)
357 value = WMGetFromPLDictionary(dict, option);
360 /* Search the default icon name - See default_icon argument! */
361 if (!value && default_icon) {
362 /* AnyWindow is "*" - see wdefaults.c */
363 dict = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, AnyWindow);
365 if (dict)
366 value = WMGetFromPLDictionary(dict, option);
369 WMPLSetCaseSensitive(False);
371 return value;
374 /* Get the file name of the image, using instance and class */
375 char *get_icon_filename(const char *winstance, const char *wclass, const char *command,
376 Bool default_icon)
378 char *file_name = NULL;
379 char *file_path = NULL;
381 /* Get the file name of the image, using instance and class */
382 file_name = wDefaultGetIconFile(winstance, wclass, default_icon);
384 /* Check if the file really exists in the disk */
385 if (file_name)
386 file_path = FindImage(wPreferences.icon_path, file_name);
388 /* If the specific icon filename is not found, and command is specified,
389 * then include the .app icons and re-do the search. */
390 if ((!file_name || !file_path ) && command) {
391 wApplicationExtractDirPackIcon(command, winstance, wclass);
392 file_name = wDefaultGetIconFile(winstance, wclass, False);
395 /* Get the full path for the image file */
396 if (file_name) {
397 file_path = FindImage(wPreferences.icon_path, file_name);
399 if (!file_path)
400 wwarning(_("icon \"%s\" doesn't exist, check your config files"), file_name);
402 /* FIXME: Here, if file_path don't exists, then the icon is in the
403 * "icon database" (w_global.domain.window_attr->dictionary), but the icon
404 * is not en disk. Therefore, we should remove it from the icon
405 * database. Is possible to do that using wDefaultChangeIcon() */
407 /* Don't wfree(file_name) here, because is a pointer to the icon
408 * dictionary (w_global.domain.window_attr->dictionary) value. */
411 if (!file_path && default_icon)
412 file_path = get_default_image_path();
414 return file_path;
417 /* This function returns the image picture for the file_name file */
418 RImage *get_rimage_from_file(WScreen *scr, const char *file_name, int max_size)
420 RImage *image = NULL;
422 if (!file_name)
423 return NULL;
425 image = RLoadImage(scr->rcontext, file_name, 0);
426 if (!image)
427 wwarning(_("error loading image file \"%s\": %s"), file_name,
428 RMessageForError(RErrorCode));
430 image = wIconValidateIconSize(image, max_size);
432 return image;
435 /* This function returns the default icon's full path
436 * If the path for an icon is not found, returns NULL */
437 char *get_default_image_path(void)
439 char *path = NULL, *file = NULL;
441 /* Get the default icon */
442 file = wDefaultGetIconFile(NULL, NULL, True);
443 if (file)
444 path = FindImage(wPreferences.icon_path, file);
446 return path;
449 /* This function creates the RImage using the default icon */
450 RImage *get_default_image(WScreen *scr)
452 RImage *image = NULL;
453 char *path = NULL;
455 /* Get the filename full path */
456 path = get_default_image_path();
457 if (!path)
458 return NULL;
460 /* Get the default icon */
461 image = get_rimage_from_file(scr, path, wPreferences.icon_size);
462 if (!image)
463 wwarning(_("could not find default icon \"%s\""), path);
465 /* Resize the icon to the wPreferences.icon_size size
466 * usually this function will return early, because size is right */
467 image = wIconValidateIconSize(image, wPreferences.icon_size);
469 return image;
472 RImage *get_icon_image(WScreen *scr, const char *winstance, const char *wclass, int max_size)
474 char *file_name = NULL;
476 /* Get the file name of the image, using instance and class */
477 file_name = get_icon_filename(winstance, wclass, NULL, True);
479 return get_rimage_from_file(scr, file_name, max_size);
482 int wDefaultGetStartWorkspace(const char *instance, const char *class)
484 WMPropList *value;
485 int w;
486 char *tmp;
488 if (!ANoTitlebar)
489 init_wdefaults();
491 if (!w_global.domain.window_attr->dictionary)
492 return -1;
494 value = get_generic_value(instance, class, AStartWorkspace, True);
496 if (!value)
497 return -1;
499 tmp = getString(AStartWorkspace, value);
501 if (!tmp || strlen(tmp) == 0)
502 return -1;
504 /* Get the workspace number for the workspace name */
505 w = wGetWorkspaceNumber(tmp);
507 return w;
510 /* Get the name of the Icon File. If default_icon is True, then, default value included */
511 char *wDefaultGetIconFile(const char *instance, const char *class, Bool default_icon)
513 WMPropList *value;
514 char *tmp;
516 if (!ANoTitlebar)
517 init_wdefaults();
519 if (!w_global.domain.window_attr || !w_global.domain.window_attr->dictionary)
520 return NULL;
522 value = get_generic_value(instance, class, AIcon, default_icon);
524 if (!value)
525 return NULL;
527 tmp = getString(AIcon, value);
529 return tmp;
532 void wDefaultChangeIcon(const char *instance, const char *class, const char *file)
534 WDDomain *db = w_global.domain.window_attr;
535 WMPropList *icon_value = NULL, *value, *attr, *key, *def_win, *def_icon = NULL;
536 WMPropList *dict = db->dictionary;
537 int same = 0;
539 if (!dict) {
540 dict = WMCreatePLDictionary(NULL, NULL);
541 if (dict)
542 db->dictionary = dict;
543 else
544 return;
547 WMPLSetCaseSensitive(True);
549 if (instance && class) {
550 char *buffer;
552 buffer = StrConcatDot(instance, class);
553 key = WMCreatePLString(buffer);
554 wfree(buffer);
555 } else if (instance) {
556 key = WMCreatePLString(instance);
557 } else if (class) {
558 key = WMCreatePLString(class);
559 } else {
560 key = WMRetainPropList(AnyWindow);
563 if (file) {
564 value = WMCreatePLString(file);
565 icon_value = WMCreatePLDictionary(AIcon, value, NULL);
566 WMReleasePropList(value);
568 if ((def_win = WMGetFromPLDictionary(dict, AnyWindow)) != NULL)
569 def_icon = WMGetFromPLDictionary(def_win, AIcon);
571 if (def_icon && !strcmp(WMGetFromPLString(def_icon), file))
572 same = 1;
575 if ((attr = WMGetFromPLDictionary(dict, key)) != NULL) {
576 if (WMIsPLDictionary(attr)) {
577 if (icon_value != NULL && !same)
578 WMMergePLDictionaries(attr, icon_value, False);
579 else
580 WMRemoveFromPLDictionary(attr, AIcon);
582 } else if (icon_value != NULL && !same) {
583 WMPutInPLDictionary(dict, key, icon_value);
586 if (!wPreferences.flags.noupdates)
587 UpdateDomainFile(db);
589 WMReleasePropList(key);
590 if (icon_value)
591 WMReleasePropList(icon_value);
593 WMPLSetCaseSensitive(False);
596 void wDefaultPurgeInfo(const char *instance, const char *class)
598 WMPropList *value, *key, *dict;
599 char *buffer;
601 if (!AIcon) { /* Unnecessary precaution */
602 init_wdefaults();
605 WMPLSetCaseSensitive(True);
607 buffer = wmalloc(strlen(class) + strlen(instance) + 2);
608 sprintf(buffer, "%s.%s", instance, class);
609 key = WMCreatePLString(buffer);
611 dict = WMGetFromPLDictionary(w_global.domain.window_attr->dictionary, key);
613 if (dict) {
614 value = WMGetFromPLDictionary(dict, AIcon);
615 if (value) {
616 WMRemoveFromPLDictionary(dict, AIcon);
618 WMRemoveFromPLDictionary(w_global.domain.window_attr->dictionary, key);
619 UpdateDomainFile(w_global.domain.window_attr);
622 wfree(buffer);
623 WMReleasePropList(key);
624 WMPLSetCaseSensitive(False);
627 /* --------------------------- Local ----------------------- */
629 static int getBool(WMPropList * key, WMPropList * value)
631 char *val;
633 if (!WMIsPLString(value)) {
634 wwarning(_("Wrong option format for key \"%s\". Should be %s."),
635 WMGetFromPLString(key), "Boolean");
636 return 0;
638 val = WMGetFromPLString(value);
640 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' || val[0] == 't' || val[0] == '1'))
641 || (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
643 return 1;
644 } else if ((val[1] == '\0'
645 && (val[0] == 'n' || val[0] == 'N' || val[0] == 'F' || val[0] == 'f' || val[0] == '0'))
646 || (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
648 return 0;
649 } else {
650 wwarning(_("can't convert \"%s\" to boolean"), val);
651 /* We return False if we can't convert to BOOLEAN.
652 * This is because all options defaults to False.
653 * -1 is not checked and thus is interpreted as True,
654 * which is not good.*/
655 return 0;
659 /* WARNING: Do not free the value returned by this function!! */
660 static char *getString(WMPropList * key, WMPropList * value)
662 if (!WMIsPLString(value)) {
663 wwarning(_("Wrong option format for key \"%s\". Should be %s."), WMGetFromPLString(key), "String");
664 return NULL;
667 return WMGetFromPLString(value);