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.
32 #include <X11/Xutil.h>
33 #include <X11/keysym.h>
37 #include "WindowMaker.h"
41 #include "workspace.h"
46 #define APPLY_VAL(value, flag, attrib) \
47 if (value) {attr->flag = getBool(attrib, value); \
48 if (mask) mask->flag = 1;}
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
;
84 static WMPropList
*AStartWorkspace
;
85 static WMPropList
*AIgnoreDecorationChanges
;
86 static WMPropList
*AIcon
;
87 static WMPropList
*AnyWindow
;
88 static WMPropList
*No
;
90 static void init_wdefaults(void)
92 AIcon
= WMCreatePLString("Icon");
94 ANoTitlebar
= WMCreatePLString("NoTitlebar");
95 ANoResizebar
= WMCreatePLString("NoResizebar");
96 ANoMiniaturizeButton
= WMCreatePLString("NoMiniaturizeButton");
97 ANoMiniaturizable
= WMCreatePLString("NoMiniaturizable");
98 ANoCloseButton
= WMCreatePLString("NoCloseButton");
99 ANoBorder
= WMCreatePLString("NoBorder");
100 ANoHideOthers
= WMCreatePLString("NoHideOthers");
101 ANoMouseBindings
= WMCreatePLString("NoMouseBindings");
102 ANoKeyBindings
= WMCreatePLString("NoKeyBindings");
103 ANoAppIcon
= WMCreatePLString("NoAppIcon");
104 AKeepOnTop
= WMCreatePLString("KeepOnTop");
105 AKeepOnBottom
= WMCreatePLString("KeepOnBottom");
106 AOmnipresent
= WMCreatePLString("Omnipresent");
107 ASkipWindowList
= WMCreatePLString("SkipWindowList");
108 ASkipSwitchPanel
= WMCreatePLString("SkipSwitchPanel");
109 AKeepInsideScreen
= WMCreatePLString("KeepInsideScreen");
110 AUnfocusable
= WMCreatePLString("Unfocusable");
111 AAlwaysUserIcon
= WMCreatePLString("AlwaysUserIcon");
112 AStartMiniaturized
= WMCreatePLString("StartMiniaturized");
113 AStartHidden
= WMCreatePLString("StartHidden");
114 AStartMaximized
= WMCreatePLString("StartMaximized");
115 ADontSaveSession
= WMCreatePLString("DontSaveSession");
116 AEmulateAppIcon
= WMCreatePLString("EmulateAppIcon");
117 AFocusAcrossWorkspace
= WMCreatePLString("FocusAcrossWorkspace");
118 AFullMaximize
= WMCreatePLString("FullMaximize");
119 ASharedAppIcon
= WMCreatePLString("SharedAppIcon");
120 #ifdef XKB_BUTTON_HINT
121 ANoLanguageButton
= WMCreatePLString("NoLanguageButton");
124 AStartWorkspace
= WMCreatePLString("StartWorkspace");
125 AIgnoreDecorationChanges
= WMCreatePLString("IgnoreDecorationChanges");
127 AnyWindow
= WMCreatePLString("*");
128 No
= WMCreatePLString("No");
131 /* Returns the correct WMPropList, using instance+class or instance, or class, or default */
132 static WMPropList
*get_value(WMPropList
* dict_win
, WMPropList
* dict_class
, WMPropList
* dict_name
,
133 WMPropList
* dict_any
, WMPropList
* option
, WMPropList
* default_value
,
134 Bool useGlobalDefault
)
139 value
= WMGetFromPLDictionary(dict_win
, option
);
145 value
= WMGetFromPLDictionary(dict_name
, option
);
151 value
= WMGetFromPLDictionary(dict_class
, option
);
156 if (!useGlobalDefault
)
160 value
= WMGetFromPLDictionary(dict_any
, option
);
165 return default_value
;
168 static WMPropList
*get_value_from_instanceclass(const char *value
)
170 WMPropList
*key
, *val
= NULL
;
175 key
= WMCreatePLString(value
);
177 WMPLSetCaseSensitive(True
);
179 if (w_global
.domain
.window_attr
->dictionary
)
180 val
= key
? WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
) : NULL
;
183 WMReleasePropList(key
);
185 WMPLSetCaseSensitive(False
);
191 *----------------------------------------------------------------------
192 * wDefaultFillAttributes--
193 * Retrieves attributes for the specified instance/class and
194 * fills attr with it. Values that are actually defined are also
195 * set in mask. If useGlobalDefault is True, the default for
196 * all windows ("*") will be used for when no values are found
197 * for that instance/class.
199 *----------------------------------------------------------------------
201 void wDefaultFillAttributes(const char *instance
, const char *class,
202 WWindowAttributes
*attr
, WWindowAttributes
*mask
,
203 Bool useGlobalDefault
)
205 WMPropList
*value
, *dw
, *dc
, *dn
, *da
;
208 dw
= dc
= dn
= da
= NULL
;
213 if (class && instance
) {
214 buffer
= StrConcatDot(instance
, class);
215 dw
= get_value_from_instanceclass(buffer
);
219 dn
= get_value_from_instanceclass(instance
);
220 dc
= get_value_from_instanceclass(class);
222 WMPLSetCaseSensitive(True
);
224 if ((w_global
.domain
.window_attr
->dictionary
) && (useGlobalDefault
))
225 da
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, AnyWindow
);
228 value
= get_value(dw
, dc
, dn
, da
, ANoTitlebar
, No
, useGlobalDefault
);
229 APPLY_VAL(value
, no_titlebar
, ANoTitlebar
);
231 value
= get_value(dw
, dc
, dn
, da
, ANoResizebar
, No
, useGlobalDefault
);
232 APPLY_VAL(value
, no_resizebar
, ANoResizebar
);
234 value
= get_value(dw
, dc
, dn
, da
, ANoMiniaturizeButton
, No
, useGlobalDefault
);
235 APPLY_VAL(value
, no_miniaturize_button
, ANoMiniaturizeButton
);
237 value
= get_value(dw
, dc
, dn
, da
, ANoMiniaturizable
, No
, useGlobalDefault
);
238 APPLY_VAL(value
, no_miniaturizable
, ANoMiniaturizable
);
240 value
= get_value(dw
, dc
, dn
, da
, ANoCloseButton
, No
, useGlobalDefault
);
241 APPLY_VAL(value
, no_close_button
, ANoCloseButton
);
243 value
= get_value(dw
, dc
, dn
, da
, ANoBorder
, No
, useGlobalDefault
);
244 APPLY_VAL(value
, no_border
, ANoBorder
);
246 value
= get_value(dw
, dc
, dn
, da
, ANoHideOthers
, No
, useGlobalDefault
);
247 APPLY_VAL(value
, no_hide_others
, ANoHideOthers
);
249 value
= get_value(dw
, dc
, dn
, da
, ANoMouseBindings
, No
, useGlobalDefault
);
250 APPLY_VAL(value
, no_bind_mouse
, ANoMouseBindings
);
252 value
= get_value(dw
, dc
, dn
, da
, ANoKeyBindings
, No
, useGlobalDefault
);
253 APPLY_VAL(value
, no_bind_keys
, ANoKeyBindings
);
255 value
= get_value(dw
, dc
, dn
, da
, ANoAppIcon
, No
, useGlobalDefault
);
256 APPLY_VAL(value
, no_appicon
, ANoAppIcon
);
258 value
= get_value(dw
, dc
, dn
, da
, ASharedAppIcon
, No
, useGlobalDefault
);
259 APPLY_VAL(value
, shared_appicon
, ASharedAppIcon
);
261 value
= get_value(dw
, dc
, dn
, da
, AKeepOnTop
, No
, useGlobalDefault
);
262 APPLY_VAL(value
, floating
, AKeepOnTop
);
264 value
= get_value(dw
, dc
, dn
, da
, AKeepOnBottom
, No
, useGlobalDefault
);
265 APPLY_VAL(value
, sunken
, AKeepOnBottom
);
267 value
= get_value(dw
, dc
, dn
, da
, AOmnipresent
, No
, useGlobalDefault
);
268 APPLY_VAL(value
, omnipresent
, AOmnipresent
);
270 value
= get_value(dw
, dc
, dn
, da
, ASkipWindowList
, No
, useGlobalDefault
);
271 APPLY_VAL(value
, skip_window_list
, ASkipWindowList
);
273 value
= get_value(dw
, dc
, dn
, da
, ASkipSwitchPanel
, No
, useGlobalDefault
);
274 APPLY_VAL(value
, skip_switchpanel
, ASkipSwitchPanel
);
276 value
= get_value(dw
, dc
, dn
, da
, AKeepInsideScreen
, No
, useGlobalDefault
);
277 APPLY_VAL(value
, dont_move_off
, AKeepInsideScreen
);
279 value
= get_value(dw
, dc
, dn
, da
, AUnfocusable
, No
, useGlobalDefault
);
280 APPLY_VAL(value
, no_focusable
, AUnfocusable
);
282 value
= get_value(dw
, dc
, dn
, da
, AAlwaysUserIcon
, No
, useGlobalDefault
);
283 APPLY_VAL(value
, always_user_icon
, AAlwaysUserIcon
);
285 value
= get_value(dw
, dc
, dn
, da
, AStartMiniaturized
, No
, useGlobalDefault
);
286 APPLY_VAL(value
, start_miniaturized
, AStartMiniaturized
);
288 value
= get_value(dw
, dc
, dn
, da
, AStartHidden
, No
, useGlobalDefault
);
289 APPLY_VAL(value
, start_hidden
, AStartHidden
);
291 value
= get_value(dw
, dc
, dn
, da
, AStartMaximized
, No
, useGlobalDefault
);
292 APPLY_VAL(value
, start_maximized
, AStartMaximized
);
294 value
= get_value(dw
, dc
, dn
, da
, ADontSaveSession
, No
, useGlobalDefault
);
295 APPLY_VAL(value
, dont_save_session
, ADontSaveSession
);
297 value
= get_value(dw
, dc
, dn
, da
, AEmulateAppIcon
, No
, useGlobalDefault
);
298 APPLY_VAL(value
, emulate_appicon
, AEmulateAppIcon
);
300 value
= get_value(dw
, dc
, dn
, da
, AFocusAcrossWorkspace
, No
, useGlobalDefault
);
301 APPLY_VAL(value
, focus_across_wksp
, AFocusAcrossWorkspace
);
303 value
= get_value(dw
, dc
, dn
, da
, AFullMaximize
, No
, useGlobalDefault
);
304 APPLY_VAL(value
, full_maximize
, AFullMaximize
);
306 value
= get_value(dw
, dc
, dn
, da
, AIgnoreDecorationChanges
, No
, useGlobalDefault
);
307 APPLY_VAL(value
, ignore_decoration_changes
, AIgnoreDecorationChanges
);
309 #ifdef XKB_BUTTON_HINT
310 value
= get_value(dw
, dc
, dn
, da
, ANoLanguageButton
, No
, useGlobalDefault
);
311 APPLY_VAL(value
, no_language_button
, ANoLanguageButton
);
315 WMPLSetCaseSensitive(False
);
318 static WMPropList
*get_generic_value(const char *instance
, const char *class,
319 WMPropList
*option
, Bool default_icon
)
321 WMPropList
*value
, *key
, *dict
;
325 WMPLSetCaseSensitive(True
);
327 /* Search the icon name using class and instance */
328 if (class && instance
) {
331 buffer
= wmalloc(strlen(class) + strlen(instance
) + 2);
332 sprintf(buffer
, "%s.%s", instance
, class);
333 key
= WMCreatePLString(buffer
);
336 dict
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
);
337 WMReleasePropList(key
);
340 value
= WMGetFromPLDictionary(dict
, option
);
343 /* Search the icon name using instance */
344 if (!value
&& instance
) {
345 key
= WMCreatePLString(instance
);
347 dict
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
);
348 WMReleasePropList(key
);
351 value
= WMGetFromPLDictionary(dict
, option
);
354 /* Search the icon name using class */
355 if (!value
&& class) {
356 key
= WMCreatePLString(class);
358 dict
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
);
359 WMReleasePropList(key
);
362 value
= WMGetFromPLDictionary(dict
, option
);
365 /* Search the default icon name - See default_icon argument! */
366 if (!value
&& default_icon
) {
367 /* AnyWindow is "*" - see wdefaults.c */
368 dict
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, AnyWindow
);
371 value
= WMGetFromPLDictionary(dict
, option
);
374 WMPLSetCaseSensitive(False
);
379 /* Get the file name of the image, using instance and class */
380 char *get_icon_filename(const char *winstance
, const char *wclass
, const char *command
,
386 /* Get the file name of the image, using instance and class */
387 file_name
= wDefaultGetIconFile(winstance
, wclass
, default_icon
);
389 /* Check if the file really exists in the disk */
391 file_path
= FindImage(wPreferences
.icon_path
, file_name
);
395 /* If the specific icon filename is not found, and command is specified,
396 * then include the .app icons and re-do the search. */
397 if (!file_path
&& command
) {
398 wApplicationExtractDirPackIcon(command
, winstance
, wclass
);
399 file_name
= wDefaultGetIconFile(winstance
, wclass
, False
);
402 file_path
= FindImage(wPreferences
.icon_path
, file_name
);
404 wwarning(_("icon \"%s\" doesn't exist, check your config files"), file_name
);
406 /* FIXME: Here, if file_path does not exist then the icon is still in the
407 * "icon database" (w_global.domain.window_attr->dictionary), but the file
408 * for the icon is no more on disk. Therefore, we should remove it from the
409 * database. Is possible to do that using wDefaultChangeIcon() */
414 * Don't wfree(file_name) because it is a direct pointer inside the icon
415 * dictionary (w_global.domain.window_attr->dictionary) and not a result
416 * allocated with wstrdup()
419 if (!file_path
&& default_icon
)
420 file_path
= get_default_image_path();
425 /* This function returns the image picture for the file_name file */
426 RImage
*get_rimage_from_file(WScreen
*scr
, const char *file_name
, int max_size
)
428 RImage
*image
= NULL
;
433 image
= RLoadImage(scr
->rcontext
, file_name
, 0);
435 wwarning(_("error loading image file \"%s\": %s"), file_name
,
436 RMessageForError(RErrorCode
));
438 image
= wIconValidateIconSize(image
, max_size
);
443 /* This function returns the default icon's full path
444 * If the path for an icon is not found, returns NULL */
445 char *get_default_image_path(void)
447 char *path
= NULL
, *file
= NULL
;
449 /* Get the default icon */
450 file
= wDefaultGetIconFile(NULL
, NULL
, True
);
452 path
= FindImage(wPreferences
.icon_path
, file
);
457 /* This function creates the RImage using the default icon */
458 RImage
*get_default_image(WScreen
*scr
)
460 RImage
*image
= NULL
;
463 /* Get the filename full path */
464 path
= get_default_image_path();
468 /* Get the default icon */
469 image
= get_rimage_from_file(scr
, path
, wPreferences
.icon_size
);
471 wwarning(_("could not find default icon \"%s\""), path
);
473 /* Resize the icon to the wPreferences.icon_size size
474 * usually this function will return early, because size is right */
475 image
= wIconValidateIconSize(image
, wPreferences
.icon_size
);
480 RImage
*get_icon_image(WScreen
*scr
, const char *winstance
, const char *wclass
, int max_size
)
482 char *file_name
= NULL
;
484 /* Get the file name of the image, using instance and class */
485 file_name
= get_icon_filename(winstance
, wclass
, NULL
, True
);
487 return get_rimage_from_file(scr
, file_name
, max_size
);
490 int wDefaultGetStartWorkspace(WScreen
*scr
, const char *instance
, const char *class)
499 if (!w_global
.domain
.window_attr
->dictionary
)
502 value
= get_generic_value(instance
, class, AStartWorkspace
, True
);
507 tmp
= getString(AStartWorkspace
, value
);
509 if (!tmp
|| strlen(tmp
) == 0)
512 /* Get the workspace number for the workspace name */
513 w
= wGetWorkspaceNumber(scr
, tmp
);
518 /* Get the name of the Icon File. If default_icon is True, then, default value included */
519 char *wDefaultGetIconFile(const char *instance
, const char *class, Bool default_icon
)
527 if (!w_global
.domain
.window_attr
|| !w_global
.domain
.window_attr
->dictionary
)
530 value
= get_generic_value(instance
, class, AIcon
, default_icon
);
535 tmp
= getString(AIcon
, value
);
540 void wDefaultChangeIcon(const char *instance
, const char *class, const char *file
)
542 WDDomain
*db
= w_global
.domain
.window_attr
;
543 WMPropList
*icon_value
= NULL
, *value
, *attr
, *key
, *def_win
, *def_icon
= NULL
;
544 WMPropList
*dict
= db
->dictionary
;
548 dict
= WMCreatePLDictionary(NULL
, NULL
);
550 db
->dictionary
= dict
;
555 WMPLSetCaseSensitive(True
);
557 if (instance
&& class) {
560 buffer
= StrConcatDot(instance
, class);
561 key
= WMCreatePLString(buffer
);
563 } else if (instance
) {
564 key
= WMCreatePLString(instance
);
566 key
= WMCreatePLString(class);
568 key
= WMRetainPropList(AnyWindow
);
572 value
= WMCreatePLString(file
);
573 icon_value
= WMCreatePLDictionary(AIcon
, value
, NULL
);
574 WMReleasePropList(value
);
576 def_win
= WMGetFromPLDictionary(dict
, AnyWindow
);
578 def_icon
= WMGetFromPLDictionary(def_win
, AIcon
);
580 if (def_icon
&& !strcmp(WMGetFromPLString(def_icon
), file
))
584 attr
= WMGetFromPLDictionary(dict
, key
);
586 if (WMIsPLDictionary(attr
)) {
587 if (icon_value
!= NULL
&& !same
)
588 WMMergePLDictionaries(attr
, icon_value
, False
);
590 WMRemoveFromPLDictionary(attr
, AIcon
);
592 } else if (icon_value
!= NULL
&& !same
) {
593 WMPutInPLDictionary(dict
, key
, icon_value
);
596 if (!wPreferences
.flags
.noupdates
)
597 UpdateDomainFile(db
);
599 WMReleasePropList(key
);
601 WMReleasePropList(icon_value
);
603 WMPLSetCaseSensitive(False
);
606 void wDefaultPurgeInfo(const char *instance
, const char *class)
608 WMPropList
*value
, *key
, *dict
;
611 if (!AIcon
) { /* Unnecessary precaution */
615 WMPLSetCaseSensitive(True
);
617 buffer
= wmalloc(strlen(class) + strlen(instance
) + 2);
618 sprintf(buffer
, "%s.%s", instance
, class);
619 key
= WMCreatePLString(buffer
);
621 dict
= WMGetFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
);
624 value
= WMGetFromPLDictionary(dict
, AIcon
);
626 WMRemoveFromPLDictionary(dict
, AIcon
);
628 WMRemoveFromPLDictionary(w_global
.domain
.window_attr
->dictionary
, key
);
629 UpdateDomainFile(w_global
.domain
.window_attr
);
633 WMReleasePropList(key
);
634 WMPLSetCaseSensitive(False
);
637 /* --------------------------- Local ----------------------- */
639 static int getBool(WMPropList
* key
, WMPropList
* value
)
643 if (!WMIsPLString(value
)) {
644 wwarning(_("Wrong option format for key \"%s\". Should be %s."),
645 WMGetFromPLString(key
), "Boolean");
648 val
= WMGetFromPLString(value
);
650 if ((val
[1] == '\0' && (val
[0] == 'y' || val
[0] == 'Y' || val
[0] == 'T' || val
[0] == 't' || val
[0] == '1'))
651 || (strcasecmp(val
, "YES") == 0 || strcasecmp(val
, "TRUE") == 0)) {
654 } else if ((val
[1] == '\0'
655 && (val
[0] == 'n' || val
[0] == 'N' || val
[0] == 'F' || val
[0] == 'f' || val
[0] == '0'))
656 || (strcasecmp(val
, "NO") == 0 || strcasecmp(val
, "FALSE") == 0)) {
660 wwarning(_("can't convert \"%s\" to boolean"), val
);
661 /* We return False if we can't convert to BOOLEAN.
662 * This is because all options defaults to False.
663 * -1 is not checked and thus is interpreted as True,
664 * which is not good.*/
669 /* WARNING: Do not free the value returned by this function!! */
670 static char *getString(WMPropList
* key
, WMPropList
* value
)
672 if (!WMIsPLString(value
)) {
673 wwarning(_("Wrong option format for key \"%s\". Should be %s."), WMGetFromPLString(key
), "String");
677 return WMGetFromPLString(value
);