wmaker: moved the list of Advanced Options into an array, for the Window Inspector
[wmaker-crm.git] / src / winspector.c
blob563eb70510c2a29e40b1d21f4500e0949188a9e8
1 /* winspector.c - window attribute inspector
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
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.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <strings.h>
32 #include "WindowMaker.h"
33 #include "screen.h"
34 #include "wcore.h"
35 #include "framewin.h"
36 #include "window.h"
37 #include "workspace.h"
38 #include "defaults.h"
39 #include "dialog.h"
40 #include "icon.h"
41 #include "stacking.h"
42 #include "application.h"
43 #include "appicon.h"
44 #include "actions.h"
45 #include "winspector.h"
46 #include "dock.h"
47 #include "client.h"
48 #include "wmspec.h"
49 #include "misc.h"
50 #include "switchmenu.h"
52 #include <WINGs/WUtil.h>
54 #define USE_TEXT_FIELD 1
55 #define UPDATE_TEXT_FIELD 2
56 #define REVERT_TO_DEFAULT 4
57 #define PWIDTH 290
58 #define PHEIGHT 360
59 #define UNDEFINED_POS 0xffffff
60 #define UPDATE_DEFAULTS 1
61 #define IS_BOOLEAN 2
64 static const struct {
65 const char *key_name;
66 WWindowAttributes flag;
67 const char *caption;
68 const char *description;
69 } window_attribute[] = {
70 { "NoTitlebar", { .no_titlebar = 1 }, N_("Disable titlebar"),
71 N_("Remove the titlebar of this window.\n"
72 "To access the window commands menu of a window\n"
73 "without it's titlebar, press Control+Esc (or the\n"
74 "equivalent shortcut, if you changed the default\n"
75 "settings).") },
77 { "NoResizebar", { .no_resizebar = 1 }, N_("Disable resizebar"),
78 N_("Remove the resizebar of this window.") },
80 { "NoCloseButton", { .no_close_button = 1 }, N_("Disable close button"),
81 N_("Remove the `close window' button of this window.") },
83 { "NoMiniaturizeButton", { .no_miniaturize_button = 1 }, N_("Disable miniaturize button"),
84 N_("Remove the `miniaturize window' button of the window.") },
86 { "NoBorder", { .no_border = 1 }, N_("Disable border"),
87 N_("Remove the 1 pixel black border around the window.") },
89 { "KeepOnTop", { .floating = 1 }, N_("Keep on top (floating)"),
90 N_("Keep the window over other windows, not allowing\n"
91 "them to cover it.") },
93 { "KeepOnBottom", { .sunken = 1 }, N_("Keep at bottom (sunken)"),
94 N_("Keep the window under all other windows.") },
96 { "Omnipresent", { .omnipresent = 1 }, N_("Omnipresent"),
97 N_("Make window present in all workspaces.") },
99 { "StartMiniaturized", { .start_miniaturized = 1 }, N_("Start miniaturized"),
100 N_("Make the window be automatically miniaturized when it's\n"
101 "first shown.") },
103 { "StartMaximized", { .start_maximized = 1 }, N_("Start maximized"),
104 N_("Make the window be automatically maximized when it's\n"
105 "first shown.") },
107 { "FullMaximize", { .full_maximize = 1 }, N_("Full screen maximization"),
108 N_("Make the window use the whole screen space when it's\n"
109 "maximized. The titlebar and resizebar will be moved\n"
110 "to outside the screen.") }
112 }, advanced_option[] = {
113 { "NoKeyBindings", { .no_bind_keys = 1 }, N_("Do not bind keyboard shortcuts"),
114 N_("Do not bind keyboard shortcuts from Window Maker\n"
115 "when this window is focused. This will allow the\n"
116 "window to receive all key combinations regardless\n"
117 "of your shortcut configuration.") },
119 { "NoMouseBindings", { .no_bind_mouse = 1 }, N_("Do not bind mouse clicks"),
120 N_("Do not bind mouse actions, such as `Alt'+drag\n"
121 "in the window (when Alt is the modifier you have\n"
122 "configured).") },
124 { "SkipWindowList", { .skip_window_list = 1 }, N_("Do not show in the window list"),
125 N_("Do not list the window in the window list menu.") },
127 { "SkipSwitchPanel", { .skip_switchpanel = 1 }, N_("Do not show in the switch panel"),
128 N_("Do not include in switch panel while cycling windows.") },
130 { "Unfocusable", { .no_focusable = 1 }, N_("Do not let it take focus"),
131 N_("Do not let the window take keyboard focus when you\n"
132 "click on it.") },
134 { "KeepInsideScreen", { .dont_move_off = 1 }, N_("Keep inside screen"),
135 N_("Do not allow the window to move itself completely\n"
136 "outside the screen. For bug compatibility.\n") },
138 { "NoHideOthers", { .no_hide_others = 1 }, N_("Ignore 'Hide Others'"),
139 N_("Do not hide the window when issuing the\n"
140 "`HideOthers' command.") },
142 { "DontSaveSession", { .dont_save_session = 1 }, N_("Ignore 'Save Session'"),
143 N_("Do not save the associated application in the\n"
144 "session's state, so that it won't be restarted\n"
145 "together with other applications when Window Maker\n"
146 "starts.") },
148 { "EmulateAppIcon", { .emulate_appicon = 1 }, N_("Emulate application icon"),
149 N_("Make this window act as an application that provides\n"
150 "enough information to Window Maker for a dockable\n"
151 "application icon to be created.") },
153 { "FocusAcrossWorkspace", { .focus_across_wksp = 1 }, N_("Focus across workspaces"),
154 N_("Allow Window Maker to switch workspace to satisfy\n"
155 "a focus request (annoying).") },
157 { "NoMiniaturizable", { .no_miniaturizable = 1 }, N_("Do not let it be minimized"),
158 N_("Do not let the window of this application be\n"
159 "minimized.\n") }
161 #ifdef XKB_BUTTON_HINT
162 ,{ "NoLanguageButton", { .no_language_button = 1 }, N_("Disable language button"),
163 N_("Remove the `toggle language' button of the window.") }
164 #endif
167 typedef struct InspectorPanel {
168 struct InspectorPanel *nextPtr;
170 WWindow *frame;
171 WWindow *inspected; /* the window that's being inspected */
172 WMWindow *win;
173 Window parent;
175 /* common stuff */
176 WMButton *revertBtn;
177 WMButton *applyBtn;
178 WMButton *saveBtn;
179 WMPopUpButton *pagePopUp;
181 /* first page. general stuff */
182 WMFrame *specFrm;
183 WMButton *instRb;
184 WMButton *clsRb;
185 WMButton *bothRb;
186 WMButton *defaultRb;
187 WMButton *selWinB;
188 WMLabel *specLbl;
190 /* second page. attributes */
191 WMFrame *attrFrm;
192 WMButton *attrChk[sizeof(window_attribute) / sizeof(window_attribute[0])];
194 /* 3rd page. more attributes */
195 WMFrame *moreFrm;
196 WMButton *moreChk[sizeof(advanced_option) / sizeof(advanced_option[0])];
198 /* 4th page. icon and workspace */
199 WMFrame *iconFrm;
200 WMLabel *iconLbl;
201 WMLabel *fileLbl;
202 WMTextField *fileText;
203 WMButton *alwChk;
204 WMButton *browseIconBtn;
205 WMFrame *wsFrm;
206 WMPopUpButton *wsP;
208 /* 5th page. application wide attributes */
209 WMFrame *appFrm;
210 WMButton *appChk[3];
212 unsigned int done:1;
213 unsigned int destroyed:1;
214 unsigned int choosingIcon:1;
215 } InspectorPanel;
217 static InspectorPanel *panelList = NULL;
220 * We are supposed to use the 'key_name' from the the 'window_attribute' structure when we want to
221 * save the user choice to the database, but as we will need to convert that name into a Property
222 * List, we use here a Cache of Property Lists, generated only once, which can be reused. It will
223 * also save on memory because of the re-use of the same storage space instead of allocating a new
224 * one everytime.
226 static WMPropList *pl_attribute[sizeof(window_attribute) / sizeof(window_attribute[0])] = { [0] = NULL };
227 static WMPropList *pl_advoptions[sizeof(advanced_option) / sizeof(advanced_option[0])];
229 static WMPropList *ANoAppIcon;
230 static WMPropList *AAlwaysUserIcon;
231 static WMPropList *ASharedAppIcon;
232 static WMPropList *AStartWorkspace;
233 static WMPropList *AIcon;
235 /* application wide options */
236 static WMPropList *AStartHidden;
237 static WMPropList *AnyWindow;
238 static WMPropList *EmptyString;
239 static WMPropList *Yes, *No;
241 static char *spec_text;
242 static void applySettings(WMWidget *button, void *panel);
244 static InspectorPanel *createInspectorForWindow(WWindow *wwin, int xpos, int ypos, Bool showSelectPanel);
246 static void create_tab_window_attributes(WWindow *wwin, InspectorPanel *panel, int frame_width);
247 static void create_tab_window_advanced(WWindow *wwin, InspectorPanel *panel, int frame_width);
248 static void create_tab_icon_workspace(WWindow *wwin, InspectorPanel *panel);
249 static void create_tab_app_specific(WWindow *wwin, InspectorPanel *panel, int frame_width);
252 * These 3 functions sets/clear/read a bit inside a bit-field in a generic manner;
253 * they uses binary operators to be as effiscient as possible, also counting on compiler's
254 * optimisations because the bit-field structure will fit in only 1 or 2 int but it is
255 * depending on the processor architecture.
257 static inline void set_attr_flag(WWindowAttributes *target, const WWindowAttributes *flag)
259 int i;
260 const unsigned char *src;
261 unsigned char *dst;
263 src = (const unsigned char *) flag;
264 dst = (unsigned char *) target;
266 for (i = 0; i < sizeof(*flag); i++)
267 dst[i] |= src[i];
270 static inline void clear_attr_flag(WWindowAttributes *target, const WWindowAttributes *flag)
272 int i;
273 const unsigned char *src;
274 unsigned char *dst;
276 src = (const unsigned char *) flag;
277 dst = (unsigned char *) target;
279 for (i = 0; i < sizeof(*flag); i++)
280 dst[i] &= ~src[i];
283 static inline int get_attr_flag(const WWindowAttributes *from, const WWindowAttributes *flag)
285 int i;
286 const unsigned char *xpect, *field;
288 field = (const unsigned char *) from;
289 xpect = (const unsigned char *) flag;
291 for (i = 0; i < sizeof(*flag); i++)
292 if (field[i] & xpect[i])
293 return 1;
295 return 0;
299 * This function is creating the Property List for the cache mentionned above
301 static void make_keys(void)
303 int i;
305 if (pl_attribute[0] != NULL)
306 return;
308 for (i = 0; i < wlengthof(window_attribute); i++)
309 pl_attribute[i] = WMCreatePLString(window_attribute[i].key_name);
311 for (i = 0; i < wlengthof(advanced_option); i++)
312 pl_advoptions[i] = WMCreatePLString(advanced_option[i].key_name);
314 AIcon = WMCreatePLString("Icon");
315 ANoAppIcon = WMCreatePLString("NoAppIcon");
316 AAlwaysUserIcon = WMCreatePLString("AlwaysUserIcon");
317 AStartHidden = WMCreatePLString("StartHidden");
318 ASharedAppIcon = WMCreatePLString("SharedAppIcon");
320 AStartWorkspace = WMCreatePLString("StartWorkspace");
322 AnyWindow = WMCreatePLString("*");
323 EmptyString = WMCreatePLString("");
324 Yes = WMCreatePLString("Yes");
325 No = WMCreatePLString("No");
328 static void freeInspector(InspectorPanel *panel)
330 panel->destroyed = 1;
332 if (panel->choosingIcon)
333 return;
335 WMDestroyWidget(panel->win);
336 XDestroyWindow(dpy, panel->parent);
337 wfree(panel);
340 static void destroyInspector(WCoreWindow *foo, void *data, XEvent *event)
342 InspectorPanel *panel, *tmp;
344 /* Parameter not used, but tell the compiler that it is ok */
345 (void) foo;
346 (void) event;
348 panel = panelList;
349 while (panel->frame != data)
350 panel = panel->nextPtr;
352 if (panelList == panel) {
353 panelList = panel->nextPtr;
354 } else {
355 tmp = panelList;
356 while (tmp->nextPtr != panel)
357 tmp = tmp->nextPtr;
359 tmp->nextPtr = panel->nextPtr;
361 panel->inspected->flags.inspector_open = 0;
362 panel->inspected->inspector = NULL;
364 WMRemoveNotificationObserver(panel);
366 wWindowUnmap(panel->frame);
367 wUnmanageWindow(panel->frame, True, False);
369 freeInspector(panel);
372 void wDestroyInspectorPanels(void)
374 InspectorPanel *panel;
376 while (panelList != NULL) {
377 panel = panelList;
378 panelList = panelList->nextPtr;
379 wUnmanageWindow(panel->frame, False, False);
380 WMDestroyWidget(panel->win);
382 panel->inspected->flags.inspector_open = 0;
383 panel->inspected->inspector = NULL;
385 wfree(panel);
389 static void changePage(WMWidget *bPtr, void *client_data)
391 InspectorPanel *panel = (InspectorPanel *) client_data;
392 int page;
394 page = WMGetPopUpButtonSelectedItem(bPtr);
396 if (page == 0) {
397 WMMapWidget(panel->specFrm);
398 WMMapWidget(panel->specLbl);
399 } else if (page == 1) {
400 WMMapWidget(panel->attrFrm);
401 } else if (page == 2) {
402 WMMapWidget(panel->moreFrm);
403 } else if (page == 3) {
404 WMMapWidget(panel->iconFrm);
405 WMMapWidget(panel->wsFrm);
406 } else {
407 WMMapWidget(panel->appFrm);
410 if (page != 0) {
411 WMUnmapWidget(panel->specFrm);
412 WMUnmapWidget(panel->specLbl);
414 if (page != 1)
415 WMUnmapWidget(panel->attrFrm);
416 if (page != 2)
417 WMUnmapWidget(panel->moreFrm);
418 if (page != 3) {
419 WMUnmapWidget(panel->iconFrm);
420 WMUnmapWidget(panel->wsFrm);
422 if (page != 4 && panel->appFrm)
423 WMUnmapWidget(panel->appFrm);
426 static int showIconFor(WMScreen *scrPtr, InspectorPanel *panel, const char *wm_instance, const char *wm_class, int flags)
428 WMPixmap *pixmap = (WMPixmap *) NULL;
429 char *file = NULL, *path = NULL;
431 if ((flags & USE_TEXT_FIELD) != 0) {
432 file = WMGetTextFieldText(panel->fileText);
433 if (file && file[0] == 0) {
434 wfree(file);
435 file = NULL;
437 } else if (flags & REVERT_TO_DEFAULT) {
438 const char *db_icon;
440 /* Get the application icon, default NOT included */
441 db_icon = wDefaultGetIconFile(wm_instance, wm_class, False);
442 if (db_icon != NULL) {
443 file = wstrdup(db_icon);
444 flags |= UPDATE_TEXT_FIELD;
448 if ((flags & UPDATE_TEXT_FIELD) != 0)
449 WMSetTextFieldText(panel->fileText, file);
451 if (file) {
452 path = FindImage(wPreferences.icon_path, file);
454 if (!path) {
455 char *buf;
456 int len = strlen(file) + 80;
458 buf = wmalloc(len);
459 snprintf(buf, len, _("Could not find icon \"%s\" specified for this window"), file);
460 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
461 wfree(buf);
462 wfree(file);
463 return -1;
466 pixmap = WMCreatePixmapFromFile(scrPtr, path);
467 wfree(path);
469 if (!pixmap) {
470 char *buf;
471 int len = strlen(file) + 80;
473 buf = wmalloc(len);
474 snprintf(buf, len, _("Could not open specified icon \"%s\":%s"),
475 file, RMessageForError(RErrorCode));
476 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
477 wfree(buf);
478 wfree(file);
479 return -1;
481 wfree(file);
484 WMSetLabelImage(panel->iconLbl, pixmap);
485 if (pixmap)
486 WMReleasePixmap(pixmap);
488 return 0;
491 static int getBool(WMPropList *value)
493 char *val;
495 if (!WMIsPLString(value))
496 return 0;
498 val = WMGetFromPLString(value);
499 if (val == NULL)
500 return 0;
502 if ((val[1] == '\0' &&
503 (val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' ||
504 val[0] == 't' || val[0] == '1')) ||
505 (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
506 return 1;
507 } else if ((val[1] == '\0' &&
508 (val[0] == 'n' || val[0] == 'N' || val[0] == 'F' ||
509 val[0] == 'f' || val[0] == '0')) ||
510 (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
511 return 0;
512 } else {
513 wwarning(_("can't convert \"%s\" to boolean"), val);
514 return 0;
518 /* Will insert the attribute = value; pair in window's list,
519 * if it's different from the defaults.
520 * Defaults means either defaults database, or attributes saved
521 * for the default window "*". This is to let one revert options that are
522 * global because they were saved for all windows ("*"). */
523 static int
524 insertAttribute(WMPropList *dict, WMPropList *window, WMPropList *attr, WMPropList *value, int flags)
526 WMPropList *def_win, *def_value = NULL;
527 int update = 0, modified = 0;
529 if (!(flags & UPDATE_DEFAULTS) && dict) {
530 def_win = WMGetFromPLDictionary(dict, AnyWindow);
531 if (def_win != NULL)
532 def_value = WMGetFromPLDictionary(def_win, attr);
535 /* If we could not find defaults in database, fall to hardcoded values.
536 * Also this is true if we save defaults for all windows */
537 if (!def_value)
538 def_value = ((flags & IS_BOOLEAN) != 0) ? No : EmptyString;
540 if (flags & IS_BOOLEAN)
541 update = (getBool(value) != getBool(def_value));
542 else
543 update = !WMIsPropListEqualTo(value, def_value);
545 if (update) {
546 WMPutInPLDictionary(window, attr, value);
547 modified = 1;
550 return modified;
553 static void saveSettings(WMWidget *button, void *client_data)
555 InspectorPanel *panel = (InspectorPanel *) client_data;
556 WWindow *wwin = panel->inspected;
557 WDDomain *db = w_global.domain.window_attr;
558 WMPropList *dict = NULL;
559 WMPropList *winDic, *appDic, *value, *value1, *key = NULL, *key2;
560 char *icon_file, *buf1, *buf2;
561 int flags = 0, i = 0, different = 0, different2 = 0;
563 /* Save will apply the changes and save them */
564 applySettings(panel->applyBtn, panel);
566 if (WMGetButtonSelected(panel->instRb) != 0) {
567 key = WMCreatePLString(wwin->wm_instance);
568 } else if (WMGetButtonSelected(panel->clsRb) != 0) {
569 key = WMCreatePLString(wwin->wm_class);
570 } else if (WMGetButtonSelected(panel->bothRb) != 0) {
571 buf1 = StrConcatDot(wwin->wm_instance, wwin->wm_class);
572 key = WMCreatePLString(buf1);
573 wfree(buf1);
574 } else if (WMGetButtonSelected(panel->defaultRb) != 0) {
575 key = WMRetainPropList(AnyWindow);
576 flags = UPDATE_DEFAULTS;
579 if (!key)
580 return;
582 dict = db->dictionary;
583 if (!dict) {
584 dict = WMCreatePLDictionary(NULL, NULL);
585 if (dict) {
586 db->dictionary = dict;
587 } else {
588 WMReleasePropList(key);
589 return;
593 if (showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD) < 0)
594 return;
596 WMPLSetCaseSensitive(True);
598 winDic = WMCreatePLDictionary(NULL, NULL);
599 appDic = WMCreatePLDictionary(NULL, NULL);
601 /* Save the icon info */
602 /* The flag "Ignore client suplied icon is not selected" */
603 buf1 = wmalloc(4);
604 snprintf(buf1, 4, "%s", (WMGetButtonSelected(panel->alwChk) != 0) ? "Yes" : "No");
605 value1 = WMCreatePLString(buf1);
606 different |= insertAttribute(dict, winDic, AAlwaysUserIcon, value1, flags);
607 WMReleasePropList(value1);
608 wfree(buf1);
610 /* The icon filename (if exists) */
611 icon_file = WMGetTextFieldText(panel->fileText);
612 if (icon_file != NULL) {
613 if (icon_file[0] != '\0') {
614 value = WMCreatePLString(icon_file);
615 different |= insertAttribute(dict, winDic, AIcon, value, flags);
616 different2 |= insertAttribute(dict, appDic, AIcon, value, flags);
617 WMReleasePropList(value);
619 wfree(icon_file);
622 i = WMGetPopUpButtonSelectedItem(panel->wsP) - 1;
623 if (i >= 0 && i < panel->frame->screen_ptr->workspace_count) {
624 value = WMCreatePLString(panel->frame->screen_ptr->workspaces[i]->name);
625 different |= insertAttribute(dict, winDic, AStartWorkspace, value, flags);
626 WMReleasePropList(value);
629 flags |= IS_BOOLEAN;
631 /* Attributes... --> Window Attributes */
632 for (i = 0; i < wlengthof(window_attribute); i++) {
633 value = (WMGetButtonSelected(panel->attrChk[i]) != 0) ? Yes : No;
634 different |= insertAttribute(dict, winDic, pl_attribute[i], value, flags);
637 /* Attributes... --> Advanced Options */
638 for (i = 0; i < wlengthof(advanced_option); i++) {
639 value = (WMGetButtonSelected(panel->moreChk[i]) != 0) ? Yes : No;
640 different |= insertAttribute(dict, winDic, pl_advoptions[i], value, flags);
643 if (wwin->main_window != None && wApplicationOf(wwin->main_window) != NULL) {
644 value = (WMGetButtonSelected(panel->appChk[0]) != 0) ? Yes : No;
645 different2 |= insertAttribute(dict, appDic, AStartHidden, value, flags);
647 value = (WMGetButtonSelected(panel->appChk[1]) != 0) ? Yes : No;
648 different2 |= insertAttribute(dict, appDic, ANoAppIcon, value, flags);
650 value = (WMGetButtonSelected(panel->appChk[2]) != 0) ? Yes : No;
651 different2 |= insertAttribute(dict, appDic, ASharedAppIcon, value, flags);
654 if (wwin->fake_group) {
655 key2 = WMCreatePLString(wwin->fake_group->identifier);
656 if (WMIsPropListEqualTo(key, key2)) {
657 WMMergePLDictionaries(winDic, appDic, True);
658 different |= different2;
659 } else {
660 WMRemoveFromPLDictionary(dict, key2);
661 if (different2)
662 WMPutInPLDictionary(dict, key2, appDic);
664 WMReleasePropList(key2);
665 } else if (wwin->main_window != wwin->client_win) {
666 WApplication *wapp = wApplicationOf(wwin->main_window);
668 if (wapp) {
669 buf2 = StrConcatDot(wapp->main_window_desc->wm_instance,
670 wapp->main_window_desc->wm_class);
671 key2 = WMCreatePLString(buf2);
672 wfree(buf2);
674 if (WMIsPropListEqualTo(key, key2)) {
675 WMMergePLDictionaries(winDic, appDic, True);
676 different |= different2;
677 } else {
678 WMRemoveFromPLDictionary(dict, key2);
679 if (different2)
680 WMPutInPLDictionary(dict, key2, appDic);
682 WMReleasePropList(key2);
684 } else {
685 WMMergePLDictionaries(winDic, appDic, True);
686 different |= different2;
688 WMReleasePropList(appDic);
690 WMRemoveFromPLDictionary(dict, key);
691 if (different)
692 WMPutInPLDictionary(dict, key, winDic);
694 WMReleasePropList(key);
695 WMReleasePropList(winDic);
697 UpdateDomainFile(db);
699 /* clean up */
700 WMPLSetCaseSensitive(False);
703 static void applySettings(WMWidget *button, void *client_data)
705 InspectorPanel *panel = (InspectorPanel *) client_data;
706 WWindow *wwin = panel->inspected;
707 WApplication *wapp = wApplicationOf(wwin->main_window);
708 int old_skip_window_list, old_omnipresent, old_no_bind_keys, old_no_bind_mouse;
709 int i;
711 old_skip_window_list = WFLAGP(wwin, skip_window_list);
712 old_omnipresent = WFLAGP(wwin, omnipresent);
713 old_no_bind_keys = WFLAGP(wwin, no_bind_keys);
714 old_no_bind_mouse = WFLAGP(wwin, no_bind_mouse);
716 showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD);
718 /* Attributes... --> Window Attributes */
719 for (i = 0; i < wlengthof(window_attribute); i++) {
720 if (WMGetButtonSelected(panel->attrChk[i]))
721 set_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
722 else
723 clear_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
725 set_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
728 /* Attributes... --> Advanced Options */
729 for (i = 0; i < wlengthof(advanced_option); i++) {
730 if (WMGetButtonSelected(panel->moreChk[i]))
731 set_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
732 else
733 clear_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
735 set_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
738 WSETUFLAG(wwin, always_user_icon, WMGetButtonSelected(panel->alwChk));
740 if (WFLAGP(wwin, no_titlebar) && wwin->flags.shaded)
741 wUnshadeWindow(wwin);
743 WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
746 * Update the window level according to AlwaysOnTop/AlwaysOnBotton
747 * if the level did not change, ChangeStackingLevel will do nothing anyway
749 if (WFLAGP(wwin, floating))
750 ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
751 else if (WFLAGP(wwin, sunken))
752 ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
753 else
754 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
756 wwin->flags.omnipresent = 0;
758 if (WFLAGP(wwin, skip_window_list) != old_skip_window_list) {
759 UpdateSwitchMenu(wwin->screen_ptr, wwin, WFLAGP(wwin, skip_window_list)?ACTION_REMOVE:ACTION_ADD);
760 } else {
761 if (WFLAGP(wwin, omnipresent) != old_omnipresent)
762 WMPostNotificationName(WMNChangedState, wwin, "omnipresent");
765 if (WFLAGP(wwin, no_bind_keys) != old_no_bind_keys) {
766 if (WFLAGP(wwin, no_bind_keys))
767 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
768 else
769 wWindowSetKeyGrabs(wwin);
772 if (WFLAGP(wwin, no_bind_mouse) != old_no_bind_mouse)
773 wWindowResetMouseGrabs(wwin);
775 wwin->frame->flags.need_texture_change = 1;
776 wWindowConfigureBorders(wwin);
777 wFrameWindowPaint(wwin->frame);
778 wNETWMUpdateActions(wwin, False);
780 /* Can't apply emulate_appicon because it will probably cause problems. */
781 if (wapp) {
782 /* do application wide stuff */
783 WSETUFLAG(wapp->main_window_desc, start_hidden, WMGetButtonSelected(panel->appChk[0]));
784 WSETUFLAG(wapp->main_window_desc, no_appicon, WMGetButtonSelected(panel->appChk[1]));
785 WSETUFLAG(wapp->main_window_desc, shared_appicon, WMGetButtonSelected(panel->appChk[2]));
787 if (WFLAGP(wapp->main_window_desc, no_appicon))
788 unpaint_app_icon(wapp);
789 else
790 paint_app_icon(wapp);
792 char *file = WMGetTextFieldText(panel->fileText);
793 if (file[0] == 0) {
794 wfree(file);
795 file = NULL;
798 /* If always_user_icon flag is set, but the user icon is not set
799 * we use client supplied icon and we unset the flag */
800 if ((WFLAGP(wwin, always_user_icon) && (!file))) {
801 /* Show the warning */
802 char *buf;
803 int len = 100;
805 buf = wmalloc(len);
806 snprintf(buf, len, _("Ignore client supplied icon is set, but icon filename textbox is empty. Using client supplied icon"));
807 wMessageDialog(panel->frame->screen_ptr, _("Warning"), buf, _("OK"), NULL, NULL);
808 wfree(buf);
809 wfree(file);
811 /* Change the flags */
812 WSETUFLAG(wwin, always_user_icon, 0);
813 WMSetButtonSelected(panel->alwChk, 0);
816 /* After test the always_user_icon flag value before,
817 * the "else" block is used only if the flag is set and
818 * the icon text box has an icon path */
819 if (!WFLAGP(wwin, always_user_icon)) {
820 /* Change App Icon image, using the icon provided by the client */
821 if (wapp->app_icon) {
822 RImage *image = get_rimage_icon_from_wm_hints(wapp->app_icon->icon);
823 if (image) {
824 set_icon_image_from_image(wapp->app_icon->icon, image);
825 update_icon_pixmap(wapp->app_icon->icon);
826 } else {
827 wIconUpdate(wapp->app_icon->icon);
831 /* Change icon image if the app is minimized,
832 * using the icon provided by the client */
833 if (wwin->icon) {
834 RImage *image = get_rimage_icon_from_wm_hints(wwin->icon);
835 if (image) {
836 set_icon_image_from_image(wwin->icon, image);
837 update_icon_pixmap(wwin->icon);
838 } else {
839 wIconUpdate(wwin->icon);
842 } else {
843 /* Change App Icon image */
844 if (wapp->app_icon)
845 wIconChangeImageFile(wapp->app_icon->icon, file);
847 /* Change icon image if the app is minimized */
848 if (wwin->icon)
849 wIconChangeImageFile(wwin->icon, file);
852 if (file)
853 wfree(file);
856 wNETFrameExtents(wwin);
859 static void revertSettings(WMWidget *button, void *client_data)
861 InspectorPanel *panel = (InspectorPanel *) client_data;
862 WWindow *wwin = panel->inspected;
863 WApplication *wapp = wApplicationOf(wwin->main_window);
864 int i, n, workspace, level;
865 char *wm_instance = NULL, *wm_class = NULL;
867 /* Parameter not used, but tell the compiler that it is ok */
868 (void) button;
870 if (panel->instRb && WMGetButtonSelected(panel->instRb) != 0)
871 wm_instance = wwin->wm_instance;
872 else if (panel->clsRb && WMGetButtonSelected(panel->clsRb) != 0)
873 wm_class = wwin->wm_class;
874 else if (panel->bothRb && WMGetButtonSelected(panel->bothRb) != 0) {
875 wm_instance = wwin->wm_instance;
876 wm_class = wwin->wm_class;
879 memset(&wwin->defined_user_flags, 0, sizeof(WWindowAttributes));
880 memset(&wwin->user_flags, 0, sizeof(WWindowAttributes));
881 memset(&wwin->client_flags, 0, sizeof(WWindowAttributes));
883 wWindowSetupInitialAttributes(wwin, &level, &workspace);
885 /* Attributes... --> Window Attributes */
886 for (i = 0; i < wlengthof(window_attribute); i++) {
887 int is_userdef, flag;
889 is_userdef = get_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
890 if (is_userdef)
891 flag = get_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
892 else
893 flag = get_attr_flag(&wwin->client_flags, &window_attribute[i].flag);
895 WMSetButtonSelected(panel->attrChk[i], flag);
898 /* Attributes... --> Advanced Options */
899 for (i = 0; i < wlengthof(advanced_option); i++) {
900 int is_userdef, flag;
902 is_userdef = get_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
903 if (is_userdef)
904 flag = get_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
905 else
906 flag = get_attr_flag(&wwin->client_flags, &advanced_option[i].flag);
908 WMSetButtonSelected(panel->moreChk[i], flag);
910 if (panel->appFrm && wapp) {
911 for (i = 0; i < wlengthof(panel->appChk); i++) {
912 int flag = 0;
914 switch (i) {
915 case 0:
916 flag = WFLAGP(wapp->main_window_desc, start_hidden);
917 break;
918 case 1:
919 flag = WFLAGP(wapp->main_window_desc, no_appicon);
920 break;
921 case 2:
922 flag = WFLAGP(wapp->main_window_desc, shared_appicon);
923 break;
925 WMSetButtonSelected(panel->appChk[i], flag);
928 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
930 showIconFor(WMWidgetScreen(panel->alwChk), panel, wm_instance, wm_class, REVERT_TO_DEFAULT);
932 n = wDefaultGetStartWorkspace(wwin->screen_ptr, wm_instance, wm_class);
934 if (n >= 0 && n < wwin->screen_ptr->workspace_count)
935 WMSetPopUpButtonSelectedItem(panel->wsP, n + 1);
936 else
937 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
939 /* must auto apply, so that there wno't be internal
940 * inconsistencies between the state in the flags and
941 * the actual state of the window */
942 applySettings(panel->applyBtn, panel);
945 static void chooseIconCallback(WMWidget *self, void *clientData)
947 char *file;
948 InspectorPanel *panel = (InspectorPanel *) clientData;
949 int result;
951 panel->choosingIcon = 1;
953 WMSetButtonEnabled(panel->browseIconBtn, False);
955 result = wIconChooserDialog(panel->frame->screen_ptr, &file,
956 panel->inspected->wm_instance,
957 panel->inspected->wm_class);
959 panel->choosingIcon = 0;
961 if (!panel->destroyed) { /* kluge */
962 if (result) {
963 WMSetTextFieldText(panel->fileText, file);
964 showIconFor(WMWidgetScreen(self), panel, NULL, NULL, USE_TEXT_FIELD);
966 WMSetButtonEnabled(panel->browseIconBtn, True);
967 } else {
968 freeInspector(panel);
970 if (result)
971 wfree(file);
974 static void textEditedObserver(void *observerData, WMNotification *notification)
976 InspectorPanel *panel = (InspectorPanel *) observerData;
978 if ((long)WMGetNotificationClientData(notification) != WMReturnTextMovement)
979 return;
981 showIconFor(WMWidgetScreen(panel->win), panel, NULL, NULL, USE_TEXT_FIELD);
984 static void selectSpecification(WMWidget *bPtr, void *data)
986 InspectorPanel *panel = (InspectorPanel *) data;
987 char str[256];
988 WWindow *wwin = panel->inspected;
990 if (bPtr == panel->defaultRb && (wwin->wm_instance || wwin->wm_class))
991 WMSetButtonEnabled(panel->applyBtn, False);
992 else
993 WMSetButtonEnabled(panel->applyBtn, True);
995 snprintf(str, sizeof(str),
996 _("Inspecting %s.%s"),
997 wwin->wm_instance ? wwin->wm_instance : "?",
998 wwin->wm_class ? wwin->wm_class : "?");
1000 wFrameWindowChangeTitle(panel->frame->frame, str);
1003 static void selectWindow(WMWidget *bPtr, void *data)
1005 InspectorPanel *panel = (InspectorPanel *) data;
1006 WWindow *wwin = panel->inspected;
1007 WScreen *scr = wwin->screen_ptr;
1008 XEvent event;
1009 WWindow *iwin;
1011 /* Parameter not used, but tell the compiler that it is ok */
1012 (void) bPtr;
1014 if (XGrabPointer(dpy, scr->root_win, True,
1015 ButtonPressMask, GrabModeAsync, GrabModeAsync, None,
1016 wPreferences.cursor[WCUR_SELECT], CurrentTime) != GrabSuccess) {
1017 wwarning("could not grab mouse pointer");
1018 return;
1021 WMSetLabelText(panel->specLbl, _("Click in the window you wish to inspect."));
1022 WMMaskEvent(dpy, ButtonPressMask, &event);
1023 XUngrabPointer(dpy, CurrentTime);
1025 iwin = wWindowFor(event.xbutton.subwindow);
1026 if (iwin && !iwin->flags.internal_window && iwin != wwin && !iwin->flags.inspector_open) {
1027 iwin->flags.inspector_open = 1;
1028 iwin->inspector = createInspectorForWindow(iwin,
1029 panel->frame->frame_x, panel->frame->frame_y, True);
1030 wCloseInspectorForWindow(wwin);
1031 } else {
1032 WMSetLabelText(panel->specLbl, spec_text);
1036 static InspectorPanel *createInspectorForWindow(WWindow *wwin, int xpos, int ypos, Bool showSelectPanel)
1038 WScreen *scr = wwin->screen_ptr;
1039 InspectorPanel *panel;
1040 Window parent;
1041 char *str = NULL, *tmp = NULL;
1042 int x, y, btn_width, frame_width;
1043 WMButton *selectedBtn = NULL;
1045 spec_text = _("The configuration will apply to all\n"
1046 "windows that have their WM_CLASS\n"
1047 "property set to the above selected\n" "name, when saved.");
1049 panel = wmalloc(sizeof(InspectorPanel));
1050 memset(panel, 0, sizeof(InspectorPanel));
1052 panel->destroyed = 0;
1053 panel->inspected = wwin;
1054 panel->nextPtr = panelList;
1055 panelList = panel;
1056 panel->win = WMCreateWindow(scr->wmscreen, "windowInspector");
1057 WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
1059 /**** create common stuff ****/
1060 /* command buttons */
1061 btn_width = (PWIDTH - (2 * 15) - (2 * 10)) / 3;
1062 panel->saveBtn = WMCreateCommandButton(panel->win);
1063 WMSetButtonAction(panel->saveBtn, saveSettings, panel);
1064 WMMoveWidget(panel->saveBtn, (2 * (btn_width + 10)) + 15, PHEIGHT - 40);
1065 WMSetButtonText(panel->saveBtn, _("Save"));
1066 WMResizeWidget(panel->saveBtn, btn_width, 28);
1067 if (wPreferences.flags.noupdates || !(wwin->wm_class || wwin->wm_instance))
1068 WMSetButtonEnabled(panel->saveBtn, False);
1070 panel->applyBtn = WMCreateCommandButton(panel->win);
1071 WMSetButtonAction(panel->applyBtn, applySettings, panel);
1072 WMMoveWidget(panel->applyBtn, btn_width + 10 + 15, PHEIGHT - 40);
1073 WMSetButtonText(panel->applyBtn, _("Apply"));
1074 WMResizeWidget(panel->applyBtn, btn_width, 28);
1076 panel->revertBtn = WMCreateCommandButton(panel->win);
1077 WMSetButtonAction(panel->revertBtn, revertSettings, panel);
1078 WMMoveWidget(panel->revertBtn, 15, PHEIGHT - 40);
1079 WMSetButtonText(panel->revertBtn, _("Reload"));
1080 WMResizeWidget(panel->revertBtn, btn_width, 28);
1082 /* page selection popup button */
1083 panel->pagePopUp = WMCreatePopUpButton(panel->win);
1084 WMSetPopUpButtonAction(panel->pagePopUp, changePage, panel);
1085 WMMoveWidget(panel->pagePopUp, 25, 15);
1086 WMResizeWidget(panel->pagePopUp, PWIDTH - 50, 20);
1088 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Specification"));
1089 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Attributes"));
1090 WMAddPopUpButtonItem(panel->pagePopUp, _("Advanced Options"));
1091 WMAddPopUpButtonItem(panel->pagePopUp, _("Icon and Initial Workspace"));
1092 WMAddPopUpButtonItem(panel->pagePopUp, _("Application Specific"));
1094 /**** window spec ****/
1095 frame_width = PWIDTH - (2 * 15);
1097 panel->specFrm = WMCreateFrame(panel->win);
1098 WMSetFrameTitle(panel->specFrm, _("Window Specification"));
1099 WMMoveWidget(panel->specFrm, 15, 65);
1100 WMResizeWidget(panel->specFrm, frame_width, 145);
1102 panel->defaultRb = WMCreateRadioButton(panel->specFrm);
1103 WMMoveWidget(panel->defaultRb, 10, 78);
1104 WMResizeWidget(panel->defaultRb, frame_width - (2 * 10), 20);
1105 WMSetButtonText(panel->defaultRb, _("Defaults for all windows"));
1106 WMSetButtonSelected(panel->defaultRb, False);
1107 WMSetButtonAction(panel->defaultRb, selectSpecification, panel);
1109 if (wwin->wm_class && wwin->wm_instance) {
1110 tmp = wstrconcat(wwin->wm_instance, ".");
1111 str = wstrconcat(tmp, wwin->wm_class);
1113 panel->bothRb = WMCreateRadioButton(panel->specFrm);
1114 WMMoveWidget(panel->bothRb, 10, 18);
1115 WMResizeWidget(panel->bothRb, frame_width - (2 * 10), 20);
1116 WMSetButtonText(panel->bothRb, str);
1117 wfree(tmp);
1118 wfree(str);
1119 WMGroupButtons(panel->defaultRb, panel->bothRb);
1121 if (!selectedBtn)
1122 selectedBtn = panel->bothRb;
1124 WMSetButtonAction(panel->bothRb, selectSpecification, panel);
1127 if (wwin->wm_instance) {
1128 panel->instRb = WMCreateRadioButton(panel->specFrm);
1129 WMMoveWidget(panel->instRb, 10, 38);
1130 WMResizeWidget(panel->instRb, frame_width - (2 * 10), 20);
1131 WMSetButtonText(panel->instRb, wwin->wm_instance);
1132 WMGroupButtons(panel->defaultRb, panel->instRb);
1134 if (!selectedBtn)
1135 selectedBtn = panel->instRb;
1137 WMSetButtonAction(panel->instRb, selectSpecification, panel);
1140 if (wwin->wm_class) {
1141 panel->clsRb = WMCreateRadioButton(panel->specFrm);
1142 WMMoveWidget(panel->clsRb, 10, 58);
1143 WMResizeWidget(panel->clsRb, frame_width - (2 * 10), 20);
1144 WMSetButtonText(panel->clsRb, wwin->wm_class);
1145 WMGroupButtons(panel->defaultRb, panel->clsRb);
1147 if (!selectedBtn)
1148 selectedBtn = panel->clsRb;
1150 WMSetButtonAction(panel->clsRb, selectSpecification, panel);
1153 panel->selWinB = WMCreateCommandButton(panel->specFrm);
1154 WMMoveWidget(panel->selWinB, 20, 145 - 24 - 10);
1155 WMResizeWidget(panel->selWinB, frame_width - 2 * 10 - 20, 24);
1156 WMSetButtonText(panel->selWinB, _("Select window"));
1157 WMSetButtonAction(panel->selWinB, selectWindow, panel);
1159 panel->specLbl = WMCreateLabel(panel->win);
1160 WMMoveWidget(panel->specLbl, 15, 210);
1161 WMResizeWidget(panel->specLbl, frame_width, 100);
1162 WMSetLabelText(panel->specLbl, spec_text);
1163 WMSetLabelWraps(panel->specLbl, True);
1165 WMSetLabelTextAlignment(panel->specLbl, WALeft);
1167 /**** attributes ****/
1168 create_tab_window_attributes(wwin, panel, frame_width);
1169 create_tab_window_advanced(wwin, panel, frame_width);
1170 create_tab_icon_workspace(wwin, panel);
1171 create_tab_app_specific(wwin, panel, frame_width);
1173 /* if the window is a transient, don't let it have a miniaturize button */
1174 if (wwin->transient_for != None && wwin->transient_for != scr->root_win)
1175 WMSetButtonEnabled(panel->attrChk[3], False);
1176 else
1177 WMSetButtonEnabled(panel->attrChk[3], True);
1179 if (!wwin->wm_class && !wwin->wm_instance)
1180 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 0, False);
1182 WMRealizeWidget(panel->win);
1184 WMMapSubwidgets(panel->win);
1185 WMMapSubwidgets(panel->specFrm);
1186 WMMapSubwidgets(panel->attrFrm);
1187 WMMapSubwidgets(panel->moreFrm);
1188 WMMapSubwidgets(panel->iconFrm);
1189 WMMapSubwidgets(panel->wsFrm);
1190 if (panel->appFrm)
1191 WMMapSubwidgets(panel->appFrm);
1193 if (showSelectPanel) {
1194 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 0);
1195 changePage(panel->pagePopUp, panel);
1196 } else {
1197 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 1);
1198 changePage(panel->pagePopUp, panel);
1201 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, PWIDTH, PHEIGHT, 0, 0, 0);
1202 XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
1203 panel->parent = parent;
1204 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1206 WMMapWidget(panel->win);
1208 XSetTransientForHint(dpy, parent, wwin->client_win);
1210 if (xpos == UNDEFINED_POS) {
1211 x = wwin->frame_x + wwin->frame->core->width / 2;
1212 y = wwin->frame_y + wwin->frame->top_width * 2;
1213 if (y + PHEIGHT > scr->scr_height)
1214 y = scr->scr_height - PHEIGHT - 30;
1215 if (x + PWIDTH > scr->scr_width)
1216 x = scr->scr_width - PWIDTH;
1217 } else {
1218 x = xpos;
1219 y = ypos;
1222 panel->frame = wManageInternalWindow(scr, parent, wwin->client_win, "Inspector", x, y, PWIDTH, PHEIGHT);
1224 if (!selectedBtn)
1225 selectedBtn = panel->defaultRb;
1227 WMSetButtonSelected(selectedBtn, True);
1228 selectSpecification(selectedBtn, panel);
1230 /* kluge to know who should get the key events */
1231 panel->frame->client_leader = WMWidgetXID(panel->win);
1233 WSETUFLAG(panel->frame, no_closable, 0);
1234 WSETUFLAG(panel->frame, no_close_button, 0);
1235 wWindowUpdateButtonImages(panel->frame);
1236 wFrameWindowShowButton(panel->frame->frame, WFF_RIGHT_BUTTON);
1237 panel->frame->frame->on_click_right = destroyInspector;
1239 wWindowMap(panel->frame);
1241 showIconFor(WMWidgetScreen(panel->alwChk), panel, wwin->wm_instance, wwin->wm_class, UPDATE_TEXT_FIELD);
1243 return panel;
1246 void wShowInspectorForWindow(WWindow *wwin)
1248 if (wwin->flags.inspector_open)
1249 return;
1251 WMSetBalloonEnabled(wwin->screen_ptr->wmscreen, wPreferences.help_balloon);
1253 make_keys();
1254 wwin->flags.inspector_open = 1;
1255 wwin->inspector = createInspectorForWindow(wwin, UNDEFINED_POS, UNDEFINED_POS, False);
1258 void wHideInspectorForWindow(WWindow *wwin)
1260 WWindow *pwin = wwin->inspector->frame;
1262 wWindowUnmap(pwin);
1263 pwin->flags.hidden = 1;
1265 wClientSetState(pwin, IconicState, None);
1268 void wUnhideInspectorForWindow(WWindow *wwin)
1270 WWindow *pwin = wwin->inspector->frame;
1272 pwin->flags.hidden = 0;
1273 pwin->flags.mapped = 1;
1274 XMapWindow(dpy, pwin->client_win);
1275 XMapWindow(dpy, pwin->frame->core->window);
1276 wClientSetState(pwin, NormalState, None);
1279 WWindow *wGetWindowOfInspectorForWindow(WWindow *wwin)
1281 if (!wwin->inspector)
1282 return NULL;
1284 assert(wwin->flags.inspector_open != 0);
1285 return wwin->inspector->frame;
1288 void wCloseInspectorForWindow(WWindow *wwin)
1290 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1292 (*pwin->frame->on_click_right) (NULL, pwin, NULL);
1295 static void create_tab_window_attributes(WWindow *wwin, InspectorPanel *panel, int frame_width)
1297 int i = 0;
1299 panel->attrFrm = WMCreateFrame(panel->win);
1300 WMSetFrameTitle(panel->attrFrm, _("Attributes"));
1301 WMMoveWidget(panel->attrFrm, 15, 45);
1302 WMResizeWidget(panel->attrFrm, frame_width, 250);
1304 for (i = 0; i < wlengthof(window_attribute); i++) {
1305 int is_userdef, flag;
1307 is_userdef = get_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
1308 if (is_userdef)
1309 flag = get_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
1310 else
1311 flag = get_attr_flag(&wwin->client_flags, &window_attribute[i].flag);
1313 panel->attrChk[i] = WMCreateSwitchButton(panel->attrFrm);
1314 WMMoveWidget(panel->attrChk[i], 10, 20 * (i + 1));
1315 WMResizeWidget(panel->attrChk[i], frame_width - 15, 20);
1316 WMSetButtonSelected(panel->attrChk[i], flag);
1317 WMSetButtonText(panel->attrChk[i], _(window_attribute[i].caption));
1319 WMSetBalloonTextForView(_(window_attribute[i].description), WMWidgetView(panel->attrChk[i]));
1323 static void create_tab_window_advanced(WWindow *wwin, InspectorPanel *panel, int frame_width)
1325 int i = 0;
1327 panel->moreFrm = WMCreateFrame(panel->win);
1328 WMSetFrameTitle(panel->moreFrm, _("Advanced"));
1329 WMMoveWidget(panel->moreFrm, 15, 45);
1330 WMResizeWidget(panel->moreFrm, frame_width, 265);
1332 for (i = 0; i < wlengthof(advanced_option); i++) {
1333 int is_userdef, flag;
1335 is_userdef = get_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
1336 if (is_userdef)
1337 flag = get_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
1338 else
1339 flag = get_attr_flag(&wwin->client_flags, &advanced_option[i].flag);
1341 panel->moreChk[i] = WMCreateSwitchButton(panel->moreFrm);
1342 WMMoveWidget(panel->moreChk[i], 10, 20 * (i + 1) - 4);
1343 WMResizeWidget(panel->moreChk[i], frame_width - 15, 20);
1344 WMSetButtonSelected(panel->moreChk[i], flag);
1345 WMSetButtonText(panel->moreChk[i], _(advanced_option[i].caption));
1347 WMSetBalloonTextForView(_(advanced_option[i].description), WMWidgetView(panel->moreChk[i]));
1351 static void create_tab_icon_workspace(WWindow *wwin, InspectorPanel *panel)
1353 WScreen *scr = wwin->screen_ptr;
1354 int i = 0;
1356 /* miniwindow/workspace */
1357 panel->iconFrm = WMCreateFrame(panel->win);
1358 WMMoveWidget(panel->iconFrm, 15, 50);
1359 WMResizeWidget(panel->iconFrm, PWIDTH - (2 * 15), 170);
1360 WMSetFrameTitle(panel->iconFrm, _("Miniwindow Image"));
1362 panel->iconLbl = WMCreateLabel(panel->iconFrm);
1363 WMMoveWidget(panel->iconLbl, PWIDTH - (2 * 15) - 22 - 64, 20);
1364 WMResizeWidget(panel->iconLbl, 64, 64);
1365 WMSetLabelRelief(panel->iconLbl, WRGroove);
1366 WMSetLabelImagePosition(panel->iconLbl, WIPImageOnly);
1368 panel->browseIconBtn = WMCreateCommandButton(panel->iconFrm);
1369 WMSetButtonAction(panel->browseIconBtn, chooseIconCallback, panel);
1370 WMMoveWidget(panel->browseIconBtn, 22, 32);
1371 WMResizeWidget(panel->browseIconBtn, 120, 26);
1372 WMSetButtonText(panel->browseIconBtn, _("Browse..."));
1374 panel->fileLbl = WMCreateLabel(panel->iconFrm);
1375 WMMoveWidget(panel->fileLbl, 20, 85);
1376 WMResizeWidget(panel->fileLbl, PWIDTH - (2 * 15) - (2 * 20), 14);
1377 WMSetLabelText(panel->fileLbl, _("Icon filename:"));
1379 panel->fileText = WMCreateTextField(panel->iconFrm);
1380 WMMoveWidget(panel->fileText, 20, 105);
1381 WMResizeWidget(panel->fileText, PWIDTH - (2 * 20) - (2 * 15), 20);
1382 WMSetTextFieldText(panel->fileText, NULL);
1383 WMAddNotificationObserver(textEditedObserver, panel, WMTextDidEndEditingNotification, panel->fileText);
1385 panel->alwChk = WMCreateSwitchButton(panel->iconFrm);
1386 WMMoveWidget(panel->alwChk, 20, 130);
1387 WMResizeWidget(panel->alwChk, PWIDTH - (2 * 15) - (2 * 15), 30);
1388 WMSetButtonText(panel->alwChk, _("Ignore client supplied icon"));
1389 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
1391 panel->wsFrm = WMCreateFrame(panel->win);
1392 WMMoveWidget(panel->wsFrm, 15, 225);
1393 WMResizeWidget(panel->wsFrm, PWIDTH - (2 * 15), 70);
1394 WMSetFrameTitle(panel->wsFrm, _("Initial Workspace"));
1396 WMSetBalloonTextForView(_("The workspace to place the window when it's"
1397 " first shown."), WMWidgetView(panel->wsFrm));
1399 panel->wsP = WMCreatePopUpButton(panel->wsFrm);
1400 WMMoveWidget(panel->wsP, 20, 30);
1401 WMResizeWidget(panel->wsP, PWIDTH - (2 * 15) - (2 * 20), 20);
1402 WMAddPopUpButtonItem(panel->wsP, _("Nowhere in particular"));
1404 for (i = 0; i < wwin->screen_ptr->workspace_count; i++)
1405 WMAddPopUpButtonItem(panel->wsP, scr->workspaces[i]->name);
1407 i = wDefaultGetStartWorkspace(wwin->screen_ptr, wwin->wm_instance, wwin->wm_class);
1408 if (i >= 0 && i <= wwin->screen_ptr->workspace_count)
1409 WMSetPopUpButtonSelectedItem(panel->wsP, i + 1);
1410 else
1411 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
1414 static void create_tab_app_specific(WWindow *wwin, InspectorPanel *panel, int frame_width)
1416 WScreen *scr = wwin->screen_ptr;
1417 int i = 0, flag = 0, tmp;
1418 char *caption = NULL, *descr = NULL;
1421 if (wwin->main_window != None) {
1422 WApplication *wapp = wApplicationOf(wwin->main_window);
1424 panel->appFrm = WMCreateFrame(panel->win);
1425 WMSetFrameTitle(panel->appFrm, _("Application Attributes"));
1426 WMMoveWidget(panel->appFrm, 15, 50);
1427 WMResizeWidget(panel->appFrm, frame_width, 240);
1429 for (i = 0; i < wlengthof(panel->appChk); i++) {
1430 switch (i) {
1431 case 0:
1432 caption = _("Start hidden");
1433 flag = WFLAGP(wapp->main_window_desc, start_hidden);
1434 descr = _("Automatically hide application when it's started.");
1435 break;
1436 case 1:
1437 caption = _("No application icon");
1438 flag = WFLAGP(wapp->main_window_desc, no_appicon);
1439 descr = _("Disable the application icon for the application.\n"
1440 "Note that you won't be able to dock it anymore,\n"
1441 "and any icons that are already docked will stop\n"
1442 "working correctly.");
1443 break;
1444 case 2:
1445 caption = _("Shared application icon");
1446 flag = WFLAGP(wapp->main_window_desc, shared_appicon);
1447 descr = _("Use a single shared application icon for all of\n"
1448 "the instances of this application.\n");
1449 break;
1451 panel->appChk[i] = WMCreateSwitchButton(panel->appFrm);
1452 WMMoveWidget(panel->appChk[i], 10, 20 * (i + 1));
1453 WMResizeWidget(panel->appChk[i], 205, 20);
1454 WMSetButtonSelected(panel->appChk[i], flag);
1455 WMSetButtonText(panel->appChk[i], caption);
1456 WMSetBalloonTextForView(descr, WMWidgetView(panel->appChk[i]));
1459 if (WFLAGP(wwin, emulate_appicon)) {
1460 WMSetButtonEnabled(panel->appChk[1], False);
1461 WMSetButtonEnabled(panel->moreChk[7], True);
1462 } else {
1463 WMSetButtonEnabled(panel->appChk[1], True);
1464 WMSetButtonEnabled(panel->moreChk[7], False);
1466 } else {
1467 if ((wwin->transient_for != None && wwin->transient_for != scr->root_win)
1468 || !wwin->wm_class || !wwin->wm_instance)
1469 tmp = False;
1470 else
1471 tmp = True;
1473 WMSetButtonEnabled(panel->moreChk[7], tmp);
1475 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 4, False);
1476 panel->appFrm = NULL;