wmaker: replace and be replaced (ICCCM protocol)
[wmaker-crm.git] / src / winspector.c
blobe947a14ce0ce2c0090a99a6539d75b181efd96b6
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
166 }, application_attr[] = {
167 { "StartHidden", { .start_hidden = 1 }, N_("Start hidden"),
168 N_("Automatically hide application when it's started.") },
170 { "NoAppIcon", { .no_appicon = 1 }, N_("No application icon"),
171 N_("Disable the application icon for the application.\n"
172 "Note that you won't be able to dock it anymore,\n"
173 "and any icons that are already docked will stop\n"
174 "working correctly.") },
176 { "SharedAppIcon", { .shared_appicon = 1 }, N_("Shared application icon"),
177 N_("Use a single shared application icon for all of\n"
178 "the instances of this application.\n") }
181 typedef struct InspectorPanel {
182 struct InspectorPanel *nextPtr;
184 WWindow *frame;
185 WWindow *inspected; /* the window that's being inspected */
186 WMWindow *win;
187 Window parent;
189 /* common stuff */
190 WMButton *revertBtn;
191 WMButton *applyBtn;
192 WMButton *saveBtn;
193 WMPopUpButton *pagePopUp;
195 /* first page. general stuff */
196 WMFrame *specFrm;
197 WMButton *instRb;
198 WMButton *clsRb;
199 WMButton *bothRb;
200 WMButton *defaultRb;
201 WMButton *selWinB;
202 WMLabel *specLbl;
204 /* second page. attributes */
205 WMFrame *attrFrm;
206 WMButton *attrClient[sizeof(window_attribute) / sizeof(window_attribute[0])];
207 WMButton *attrChk[sizeof(window_attribute) / sizeof(window_attribute[0])];
209 /* 3rd page. more attributes */
210 WMFrame *moreFrm;
211 WMButton *moreChk[sizeof(advanced_option) / sizeof(advanced_option[0])];
213 /* 4th page. icon and workspace */
214 WMFrame *iconFrm;
215 WMLabel *iconLbl;
216 WMLabel *fileLbl;
217 WMTextField *fileText;
218 WMButton *alwChk;
219 WMButton *browseIconBtn;
220 WMFrame *wsFrm;
221 WMPopUpButton *wsP;
223 /* 5th page. application wide attributes */
224 WMFrame *appFrm;
225 WMButton *appChk[sizeof(application_attr) / sizeof(application_attr[0])];
227 unsigned int done:1;
228 unsigned int destroyed:1;
229 unsigned int choosingIcon:1;
230 } InspectorPanel;
232 static InspectorPanel *panelList = NULL;
235 * We are supposed to use the 'key_name' from the the 'window_attribute' structure when we want to
236 * save the user choice to the database, but as we will need to convert that name into a Property
237 * List, we use here a Cache of Property Lists, generated only once, which can be reused. It will
238 * also save on memory because of the re-use of the same storage space instead of allocating a new
239 * one everytime.
241 static WMPropList *pl_attribute[sizeof(window_attribute) / sizeof(window_attribute[0])] = { [0] = NULL };
242 static WMPropList *pl_advoptions[sizeof(advanced_option) / sizeof(advanced_option[0])];
243 static WMPropList *pl_appattrib[sizeof(application_attr) / sizeof(application_attr[0])];
245 static WMPropList *AAlwaysUserIcon;
246 static WMPropList *AStartWorkspace;
247 static WMPropList *AIcon;
249 /* application wide options */
250 static WMPropList *AnyWindow;
251 static WMPropList *EmptyString;
252 static WMPropList *Yes, *No;
254 static char *spec_text;
255 static void applySettings(WMWidget *button, void *panel);
257 static InspectorPanel *createInspectorForWindow(WWindow *wwin, int xpos, int ypos, Bool showSelectPanel);
259 static void create_tab_window_attributes(WWindow *wwin, InspectorPanel *panel, int frame_width);
260 static void create_tab_window_advanced(WWindow *wwin, InspectorPanel *panel, int frame_width);
261 static void create_tab_icon_workspace(WWindow *wwin, InspectorPanel *panel);
262 static void create_tab_app_specific(WWindow *wwin, InspectorPanel *panel, int frame_width);
265 * These 3 functions sets/clear/read a bit inside a bit-field in a generic manner;
266 * they uses binary operators to be as effiscient as possible, also counting on compiler's
267 * optimisations because the bit-field structure will fit in only 1 or 2 int but it is
268 * depending on the processor architecture.
270 static inline void set_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 void clear_attr_flag(WWindowAttributes *target, const WWindowAttributes *flag)
285 int i;
286 const unsigned char *src;
287 unsigned char *dst;
289 src = (const unsigned char *) flag;
290 dst = (unsigned char *) target;
292 for (i = 0; i < sizeof(*flag); i++)
293 dst[i] &= ~src[i];
296 static inline int get_attr_flag(const WWindowAttributes *from, const WWindowAttributes *flag)
298 int i;
299 const unsigned char *xpect, *field;
301 field = (const unsigned char *) from;
302 xpect = (const unsigned char *) flag;
304 for (i = 0; i < sizeof(*flag); i++)
305 if (field[i] & xpect[i])
306 return 1;
308 return 0;
312 * This function is creating the Property List for the cache mentionned above
314 static void make_keys(void)
316 int i;
318 if (pl_attribute[0] != NULL)
319 return;
321 for (i = 0; i < wlengthof(window_attribute); i++)
322 pl_attribute[i] = WMCreatePLString(window_attribute[i].key_name);
324 for (i = 0; i < wlengthof(advanced_option); i++)
325 pl_advoptions[i] = WMCreatePLString(advanced_option[i].key_name);
327 for (i = 0; i < wlengthof(application_attr); i++)
328 pl_appattrib[i] = WMCreatePLString(application_attr[i].key_name);
330 AIcon = WMCreatePLString("Icon");
331 AAlwaysUserIcon = WMCreatePLString("AlwaysUserIcon");
333 AStartWorkspace = WMCreatePLString("StartWorkspace");
335 AnyWindow = WMCreatePLString("*");
336 EmptyString = WMCreatePLString("");
337 Yes = WMCreatePLString("Yes");
338 No = WMCreatePLString("No");
341 static void freeInspector(InspectorPanel *panel)
343 panel->destroyed = 1;
345 if (panel->choosingIcon)
346 return;
348 WMDestroyWidget(panel->win);
349 XDestroyWindow(dpy, panel->parent);
350 wfree(panel);
353 static void destroyInspector(WCoreWindow *foo, void *data, XEvent *event)
355 InspectorPanel *panel, *tmp;
357 /* Parameter not used, but tell the compiler that it is ok */
358 (void) foo;
359 (void) event;
361 panel = panelList;
362 while (panel->frame != data)
363 panel = panel->nextPtr;
365 if (panelList == panel) {
366 panelList = panel->nextPtr;
367 } else {
368 tmp = panelList;
369 while (tmp->nextPtr != panel)
370 tmp = tmp->nextPtr;
372 tmp->nextPtr = panel->nextPtr;
374 panel->inspected->flags.inspector_open = 0;
375 panel->inspected->inspector = NULL;
377 WMRemoveNotificationObserver(panel);
379 wWindowUnmap(panel->frame);
380 wUnmanageWindow(panel->frame, True, False);
382 freeInspector(panel);
385 void wDestroyInspectorPanels(void)
387 InspectorPanel *panel;
389 while (panelList != NULL) {
390 panel = panelList;
391 panelList = panelList->nextPtr;
392 wUnmanageWindow(panel->frame, False, False);
393 WMDestroyWidget(panel->win);
395 panel->inspected->flags.inspector_open = 0;
396 panel->inspected->inspector = NULL;
398 wfree(panel);
402 static void changePage(WMWidget *bPtr, void *client_data)
404 InspectorPanel *panel = (InspectorPanel *) client_data;
405 int page;
407 page = WMGetPopUpButtonSelectedItem(bPtr);
409 if (page == 0) {
410 WMMapWidget(panel->specFrm);
411 WMMapWidget(panel->specLbl);
412 } else if (page == 1) {
413 WMMapWidget(panel->attrFrm);
414 } else if (page == 2) {
415 WMMapWidget(panel->moreFrm);
416 } else if (page == 3) {
417 WMMapWidget(panel->iconFrm);
418 WMMapWidget(panel->wsFrm);
419 } else {
420 WMMapWidget(panel->appFrm);
423 if (page != 0) {
424 WMUnmapWidget(panel->specFrm);
425 WMUnmapWidget(panel->specLbl);
427 if (page != 1)
428 WMUnmapWidget(panel->attrFrm);
429 if (page != 2)
430 WMUnmapWidget(panel->moreFrm);
431 if (page != 3) {
432 WMUnmapWidget(panel->iconFrm);
433 WMUnmapWidget(panel->wsFrm);
435 if (page != 4 && panel->appFrm)
436 WMUnmapWidget(panel->appFrm);
439 static int showIconFor(WMScreen *scrPtr, InspectorPanel *panel, const char *wm_instance, const char *wm_class, int flags)
441 WMPixmap *pixmap = (WMPixmap *) NULL;
442 char *file = NULL, *path = NULL;
444 if ((flags & USE_TEXT_FIELD) != 0) {
445 file = WMGetTextFieldText(panel->fileText);
446 if (file && file[0] == 0) {
447 wfree(file);
448 file = NULL;
450 } else if (flags & REVERT_TO_DEFAULT) {
451 const char *db_icon;
453 /* Get the application icon, default NOT included */
454 db_icon = wDefaultGetIconFile(wm_instance, wm_class, False);
455 if (db_icon != NULL) {
456 file = wstrdup(db_icon);
457 flags |= UPDATE_TEXT_FIELD;
461 if ((flags & UPDATE_TEXT_FIELD) != 0)
462 WMSetTextFieldText(panel->fileText, file);
464 if (file) {
465 path = FindImage(wPreferences.icon_path, file);
467 if (!path) {
468 char *buf;
469 int len = strlen(file) + 80;
471 buf = wmalloc(len);
472 snprintf(buf, len, _("Could not find icon \"%s\" specified for this window"), file);
473 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
474 wfree(buf);
475 wfree(file);
476 return -1;
479 pixmap = WMCreatePixmapFromFile(scrPtr, path);
480 wfree(path);
482 if (!pixmap) {
483 char *buf;
484 int len = strlen(file) + 80;
486 buf = wmalloc(len);
487 snprintf(buf, len, _("Could not open specified icon \"%s\":%s"),
488 file, RMessageForError(RErrorCode));
489 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
490 wfree(buf);
491 wfree(file);
492 return -1;
494 wfree(file);
497 WMSetLabelImage(panel->iconLbl, pixmap);
498 if (pixmap)
499 WMReleasePixmap(pixmap);
501 return 0;
504 static int getBool(WMPropList *value)
506 char *val;
508 if (!WMIsPLString(value))
509 return 0;
511 val = WMGetFromPLString(value);
512 if (val == NULL)
513 return 0;
515 if ((val[1] == '\0' &&
516 (val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' ||
517 val[0] == 't' || val[0] == '1')) ||
518 (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
519 return 1;
520 } else if ((val[1] == '\0' &&
521 (val[0] == 'n' || val[0] == 'N' || val[0] == 'F' ||
522 val[0] == 'f' || val[0] == '0')) ||
523 (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
524 return 0;
525 } else {
526 wwarning(_("can't convert \"%s\" to boolean"), val);
527 return 0;
531 /* Will insert the attribute = value; pair in window's list,
532 * if it's different from the defaults.
533 * Defaults means either defaults database, or attributes saved
534 * for the default window "*". This is to let one revert options that are
535 * global because they were saved for all windows ("*"). */
536 static int
537 insertAttribute(WMPropList *dict, WMPropList *window, WMPropList *attr, WMPropList *value, int flags)
539 WMPropList *def_win, *def_value = NULL;
540 int update = 0, modified = 0;
542 if (!(flags & UPDATE_DEFAULTS) && dict) {
543 def_win = WMGetFromPLDictionary(dict, AnyWindow);
544 if (def_win != NULL)
545 def_value = WMGetFromPLDictionary(def_win, attr);
548 /* If we could not find defaults in database, fall to hardcoded values.
549 * Also this is true if we save defaults for all windows */
550 if (!def_value)
551 def_value = ((flags & IS_BOOLEAN) != 0) ? No : EmptyString;
553 if (flags & IS_BOOLEAN)
554 update = (getBool(value) != getBool(def_value));
555 else
556 update = !WMIsPropListEqualTo(value, def_value);
558 if (update) {
559 WMPutInPLDictionary(window, attr, value);
560 modified = 1;
563 return modified;
566 static void saveSettings(WMWidget *button, void *client_data)
568 InspectorPanel *panel = (InspectorPanel *) client_data;
569 WWindow *wwin = panel->inspected;
570 WDDomain *db = w_global.domain.window_attr;
571 WMPropList *dict = NULL;
572 WMPropList *winDic, *appDic, *value, *value1, *key = NULL, *key2;
573 char *icon_file, *buf1, *buf2;
574 int flags = 0, i = 0, different = 0, different2 = 0;
576 /* Save will apply the changes and save them */
577 applySettings(panel->applyBtn, panel);
579 if (WMGetButtonSelected(panel->instRb) != 0) {
580 key = WMCreatePLString(wwin->wm_instance);
581 } else if (WMGetButtonSelected(panel->clsRb) != 0) {
582 key = WMCreatePLString(wwin->wm_class);
583 } else if (WMGetButtonSelected(panel->bothRb) != 0) {
584 buf1 = StrConcatDot(wwin->wm_instance, wwin->wm_class);
585 key = WMCreatePLString(buf1);
586 wfree(buf1);
587 } else if (WMGetButtonSelected(panel->defaultRb) != 0) {
588 key = WMRetainPropList(AnyWindow);
589 flags = UPDATE_DEFAULTS;
592 if (!key)
593 return;
595 dict = db->dictionary;
596 if (!dict) {
597 dict = WMCreatePLDictionary(NULL, NULL);
598 if (dict) {
599 db->dictionary = dict;
600 } else {
601 WMReleasePropList(key);
602 return;
606 if (showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD) < 0)
607 return;
609 WMPLSetCaseSensitive(True);
611 winDic = WMCreatePLDictionary(NULL, NULL);
612 appDic = WMCreatePLDictionary(NULL, NULL);
614 /* Save the icon info */
615 /* The flag "Ignore client suplied icon is not selected" */
616 buf1 = wmalloc(4);
617 snprintf(buf1, 4, "%s", (WMGetButtonSelected(panel->alwChk) != 0) ? "Yes" : "No");
618 value1 = WMCreatePLString(buf1);
619 different |= insertAttribute(dict, winDic, AAlwaysUserIcon, value1, flags);
620 WMReleasePropList(value1);
621 wfree(buf1);
623 /* The icon filename (if exists) */
624 icon_file = WMGetTextFieldText(panel->fileText);
625 if (icon_file != NULL) {
626 if (icon_file[0] != '\0') {
627 value = WMCreatePLString(icon_file);
628 different |= insertAttribute(dict, winDic, AIcon, value, flags);
629 different2 |= insertAttribute(dict, appDic, AIcon, value, flags);
630 WMReleasePropList(value);
632 wfree(icon_file);
635 i = WMGetPopUpButtonSelectedItem(panel->wsP) - 1;
636 if (i >= 0 && i < panel->frame->screen_ptr->workspace_count) {
637 value = WMCreatePLString(panel->frame->screen_ptr->workspaces[i]->name);
638 different |= insertAttribute(dict, winDic, AStartWorkspace, value, flags);
639 WMReleasePropList(value);
642 flags |= IS_BOOLEAN;
644 /* Attributes... --> Window Attributes */
645 for (i = 0; i < wlengthof(window_attribute); i++) {
646 WMPropList *old_value;
647 int state;
649 old_value = WMGetFromPLDictionary(winDic, pl_attribute[i]);
650 state = WMGetButtonSelected(panel->attrChk[i]);
651 if (state > 0) {
652 if ((old_value == NULL) || !getBool(old_value)) {
653 WMPutInPLDictionary(winDic, pl_attribute[i], Yes);
654 different |= 1;
656 } else if (state == 0) {
657 if ((old_value == NULL) || getBool(old_value)) {
658 WMPutInPLDictionary(winDic, pl_attribute[i], No);
659 different |= 1;
661 } else { /* (state < 0) */
662 if (old_value != NULL) {
663 WMRemoveFromPLDictionary(winDic, pl_attribute[i]);
664 different |= 1;
669 /* Attributes... --> Advanced Options */
670 for (i = 0; i < wlengthof(advanced_option); i++) {
671 value = (WMGetButtonSelected(panel->moreChk[i]) != 0) ? Yes : No;
672 different |= insertAttribute(dict, winDic, pl_advoptions[i], value, flags);
675 /* Attributes... --> Application Specific */
676 if (wwin->main_window != None && wApplicationOf(wwin->main_window) != NULL) {
677 for (i = 0; i < wlengthof(application_attr); i++) {
678 value = (WMGetButtonSelected(panel->appChk[i]) != 0) ? Yes : No;
679 different2 |= insertAttribute(dict, appDic, pl_appattrib[i], value, flags);
683 if (wwin->fake_group) {
684 key2 = WMCreatePLString(wwin->fake_group->identifier);
685 if (WMIsPropListEqualTo(key, key2)) {
686 WMMergePLDictionaries(winDic, appDic, True);
687 different |= different2;
688 } else {
689 WMRemoveFromPLDictionary(dict, key2);
690 if (different2)
691 WMPutInPLDictionary(dict, key2, appDic);
693 WMReleasePropList(key2);
694 } else if (wwin->main_window != wwin->client_win) {
695 WApplication *wapp = wApplicationOf(wwin->main_window);
697 if (wapp) {
698 buf2 = StrConcatDot(wapp->main_window_desc->wm_instance,
699 wapp->main_window_desc->wm_class);
700 key2 = WMCreatePLString(buf2);
701 wfree(buf2);
703 if (WMIsPropListEqualTo(key, key2)) {
704 WMMergePLDictionaries(winDic, appDic, True);
705 different |= different2;
706 } else {
707 WMRemoveFromPLDictionary(dict, key2);
708 if (different2)
709 WMPutInPLDictionary(dict, key2, appDic);
711 WMReleasePropList(key2);
713 } else {
714 WMMergePLDictionaries(winDic, appDic, True);
715 different |= different2;
717 WMReleasePropList(appDic);
719 WMRemoveFromPLDictionary(dict, key);
720 if (different)
721 WMPutInPLDictionary(dict, key, winDic);
723 WMReleasePropList(key);
724 WMReleasePropList(winDic);
726 UpdateDomainFile(db);
728 /* clean up */
729 WMPLSetCaseSensitive(False);
732 static void applySettings(WMWidget *button, void *client_data)
734 InspectorPanel *panel = (InspectorPanel *) client_data;
735 WWindow *wwin = panel->inspected;
736 WApplication *wapp = wApplicationOf(wwin->main_window);
737 int old_skip_window_list, old_omnipresent, old_no_bind_keys, old_no_bind_mouse;
738 int i;
740 old_skip_window_list = WFLAGP(wwin, skip_window_list);
741 old_omnipresent = WFLAGP(wwin, omnipresent);
742 old_no_bind_keys = WFLAGP(wwin, no_bind_keys);
743 old_no_bind_mouse = WFLAGP(wwin, no_bind_mouse);
745 showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD);
747 /* Attributes... --> Window Attributes */
748 for (i = 0; i < wlengthof(window_attribute); i++) {
749 int state;
751 state = WMGetButtonSelected(panel->attrChk[i]);
753 if (state > 0)
754 set_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
755 else
756 clear_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
758 if (state < 0)
759 clear_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
760 else
761 set_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
764 /* Attributes... --> Advanced Options */
765 for (i = 0; i < wlengthof(advanced_option); i++) {
766 if (WMGetButtonSelected(panel->moreChk[i]))
767 set_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
768 else
769 clear_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
771 set_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
774 WSETUFLAG(wwin, always_user_icon, WMGetButtonSelected(panel->alwChk));
776 if (WFLAGP(wwin, no_titlebar) && wwin->flags.shaded)
777 wUnshadeWindow(wwin);
779 WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
782 * Update the window level according to AlwaysOnTop/AlwaysOnBotton
783 * if the level did not change, ChangeStackingLevel will do nothing anyway
785 if (WFLAGP(wwin, floating))
786 ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
787 else if (WFLAGP(wwin, sunken))
788 ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
789 else
790 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
792 wwin->flags.omnipresent = 0;
794 if (WFLAGP(wwin, skip_window_list) != old_skip_window_list) {
795 UpdateSwitchMenu(wwin->screen_ptr, wwin, WFLAGP(wwin, skip_window_list)?ACTION_REMOVE:ACTION_ADD);
796 } else {
797 if (WFLAGP(wwin, omnipresent) != old_omnipresent)
798 WMPostNotificationName(WMNChangedState, wwin, "omnipresent");
801 if (WFLAGP(wwin, no_bind_keys) != old_no_bind_keys) {
802 if (WFLAGP(wwin, no_bind_keys))
803 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
804 else
805 wWindowSetKeyGrabs(wwin);
808 if (WFLAGP(wwin, no_bind_mouse) != old_no_bind_mouse)
809 wWindowResetMouseGrabs(wwin);
811 wwin->frame->flags.need_texture_change = 1;
812 wWindowConfigureBorders(wwin);
813 wFrameWindowPaint(wwin->frame);
814 wNETWMUpdateActions(wwin, False);
816 /* Can't apply emulate_appicon because it will probably cause problems. */
817 if (wapp) {
818 /* do application wide stuff */
819 for (i = 0; i < wlengthof(application_attr); i++) {
820 if (WMGetButtonSelected(panel->appChk[i]))
821 set_attr_flag(&wapp->main_window_desc->user_flags, &application_attr[i].flag);
822 else
823 clear_attr_flag(&wapp->main_window_desc->user_flags, &application_attr[i].flag);
825 set_attr_flag(&wapp->main_window_desc->defined_user_flags, &application_attr[i].flag);
828 if (WFLAGP(wapp->main_window_desc, no_appicon))
829 unpaint_app_icon(wapp);
830 else
831 paint_app_icon(wapp);
833 char *file = WMGetTextFieldText(panel->fileText);
834 if (file[0] == 0) {
835 wfree(file);
836 file = NULL;
839 /* If always_user_icon flag is set, but the user icon is not set
840 * we use client supplied icon and we unset the flag */
841 if ((WFLAGP(wwin, always_user_icon) && (!file))) {
842 /* Show the warning */
843 char *buf;
844 int len = 100;
846 buf = wmalloc(len);
847 snprintf(buf, len, _("Ignore client supplied icon is set, but icon filename textbox is empty. Using client supplied icon"));
848 wMessageDialog(panel->frame->screen_ptr, _("Warning"), buf, _("OK"), NULL, NULL);
849 wfree(buf);
850 wfree(file);
852 /* Change the flags */
853 WSETUFLAG(wwin, always_user_icon, 0);
854 WMSetButtonSelected(panel->alwChk, 0);
857 /* After test the always_user_icon flag value before,
858 * the "else" block is used only if the flag is set and
859 * the icon text box has an icon path */
860 if (!WFLAGP(wwin, always_user_icon)) {
861 /* Change App Icon image, using the icon provided by the client */
862 if (wapp->app_icon) {
863 RImage *image = get_rimage_icon_from_wm_hints(wapp->app_icon->icon);
864 if (image) {
865 set_icon_image_from_image(wapp->app_icon->icon, image);
866 update_icon_pixmap(wapp->app_icon->icon);
867 } else {
868 wIconUpdate(wapp->app_icon->icon);
872 /* Change icon image if the app is minimized,
873 * using the icon provided by the client */
874 if (wwin->icon) {
875 RImage *image = get_rimage_icon_from_wm_hints(wwin->icon);
876 if (image) {
877 set_icon_image_from_image(wwin->icon, image);
878 update_icon_pixmap(wwin->icon);
879 } else {
880 wIconUpdate(wwin->icon);
883 } else {
884 /* Change App Icon image */
885 if (wapp->app_icon)
886 wIconChangeImageFile(wapp->app_icon->icon, file);
888 /* Change icon image if the app is minimized */
889 if (wwin->icon)
890 wIconChangeImageFile(wwin->icon, file);
893 if (file)
894 wfree(file);
897 wNETFrameExtents(wwin);
900 static void revertSettings(WMWidget *button, void *client_data)
902 InspectorPanel *panel = (InspectorPanel *) client_data;
903 WWindow *wwin = panel->inspected;
904 WApplication *wapp = wApplicationOf(wwin->main_window);
905 int i, n, workspace, level;
906 char *wm_instance = NULL, *wm_class = NULL;
908 /* Parameter not used, but tell the compiler that it is ok */
909 (void) button;
911 if (panel->instRb && WMGetButtonSelected(panel->instRb) != 0)
912 wm_instance = wwin->wm_instance;
913 else if (panel->clsRb && WMGetButtonSelected(panel->clsRb) != 0)
914 wm_class = wwin->wm_class;
915 else if (panel->bothRb && WMGetButtonSelected(panel->bothRb) != 0) {
916 wm_instance = wwin->wm_instance;
917 wm_class = wwin->wm_class;
920 memset(&wwin->defined_user_flags, 0, sizeof(WWindowAttributes));
921 memset(&wwin->user_flags, 0, sizeof(WWindowAttributes));
922 memset(&wwin->client_flags, 0, sizeof(WWindowAttributes));
924 wWindowSetupInitialAttributes(wwin, &level, &workspace);
926 /* Attributes... --> Window Attributes */
927 for (i = 0; i < wlengthof(window_attribute); i++) {
928 int is_userdef, flag;
930 is_userdef = get_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
931 if (is_userdef)
932 flag = get_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
933 else
934 flag = -1;
936 WMSetButtonSelected(panel->attrChk[i], flag);
939 /* Attributes... --> Advanced Options */
940 for (i = 0; i < wlengthof(advanced_option); i++) {
941 int is_userdef, flag;
943 is_userdef = get_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
944 if (is_userdef)
945 flag = get_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
946 else
947 flag = get_attr_flag(&wwin->client_flags, &advanced_option[i].flag);
949 WMSetButtonSelected(panel->moreChk[i], flag);
952 /* Attributes... --> Application Specific */
953 if (panel->appFrm && wapp) {
954 for (i = 0; i < wlengthof(application_attr); i++) {
955 int is_userdef, flag = 0;
957 is_userdef = get_attr_flag(&wapp->main_window_desc->defined_user_flags, &application_attr[i].flag);
958 if (is_userdef)
959 flag = get_attr_flag(&wapp->main_window_desc->user_flags, &application_attr[i].flag);
960 else
961 flag = get_attr_flag(&wapp->main_window_desc->client_flags, &application_attr[i].flag);
963 WMSetButtonSelected(panel->appChk[i], flag);
966 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
968 showIconFor(WMWidgetScreen(panel->alwChk), panel, wm_instance, wm_class, REVERT_TO_DEFAULT);
970 n = wDefaultGetStartWorkspace(wwin->screen_ptr, wm_instance, wm_class);
972 if (n >= 0 && n < wwin->screen_ptr->workspace_count)
973 WMSetPopUpButtonSelectedItem(panel->wsP, n + 1);
974 else
975 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
977 /* must auto apply, so that there wno't be internal
978 * inconsistencies between the state in the flags and
979 * the actual state of the window */
980 applySettings(panel->applyBtn, panel);
983 static void chooseIconCallback(WMWidget *self, void *clientData)
985 char *file;
986 InspectorPanel *panel = (InspectorPanel *) clientData;
987 int result;
989 panel->choosingIcon = 1;
991 WMSetButtonEnabled(panel->browseIconBtn, False);
993 result = wIconChooserDialog(panel->frame->screen_ptr, &file,
994 panel->inspected->wm_instance,
995 panel->inspected->wm_class);
997 panel->choosingIcon = 0;
999 if (!panel->destroyed) { /* kluge */
1000 if (result) {
1001 WMSetTextFieldText(panel->fileText, file);
1002 showIconFor(WMWidgetScreen(self), panel, NULL, NULL, USE_TEXT_FIELD);
1004 WMSetButtonEnabled(panel->browseIconBtn, True);
1005 } else {
1006 freeInspector(panel);
1008 if (result)
1009 wfree(file);
1012 static void textEditedObserver(void *observerData, WMNotification *notification)
1014 InspectorPanel *panel = (InspectorPanel *) observerData;
1016 if ((long)WMGetNotificationClientData(notification) != WMReturnTextMovement)
1017 return;
1019 showIconFor(WMWidgetScreen(panel->win), panel, NULL, NULL, USE_TEXT_FIELD);
1022 static void selectSpecification(WMWidget *bPtr, void *data)
1024 InspectorPanel *panel = (InspectorPanel *) data;
1025 char str[256];
1026 WWindow *wwin = panel->inspected;
1028 if (bPtr == panel->defaultRb && (wwin->wm_instance || wwin->wm_class))
1029 WMSetButtonEnabled(panel->applyBtn, False);
1030 else
1031 WMSetButtonEnabled(panel->applyBtn, True);
1033 snprintf(str, sizeof(str),
1034 _("Inspecting %s.%s"),
1035 wwin->wm_instance ? wwin->wm_instance : "?",
1036 wwin->wm_class ? wwin->wm_class : "?");
1038 wFrameWindowChangeTitle(panel->frame->frame, str);
1041 static void selectWindow(WMWidget *bPtr, void *data)
1043 InspectorPanel *panel = (InspectorPanel *) data;
1044 WWindow *wwin = panel->inspected;
1045 WScreen *scr = wwin->screen_ptr;
1046 XEvent event;
1047 WWindow *iwin;
1049 /* Parameter not used, but tell the compiler that it is ok */
1050 (void) bPtr;
1052 if (XGrabPointer(dpy, scr->root_win, True,
1053 ButtonPressMask, GrabModeAsync, GrabModeAsync, None,
1054 wPreferences.cursor[WCUR_SELECT], CurrentTime) != GrabSuccess) {
1055 wwarning("could not grab mouse pointer");
1056 return;
1059 WMSetLabelText(panel->specLbl, _("Click in the window you wish to inspect."));
1060 WMMaskEvent(dpy, ButtonPressMask, &event);
1061 XUngrabPointer(dpy, CurrentTime);
1063 iwin = wWindowFor(event.xbutton.subwindow);
1064 if (iwin && !iwin->flags.internal_window && iwin != wwin && !iwin->flags.inspector_open) {
1065 iwin->flags.inspector_open = 1;
1066 iwin->inspector = createInspectorForWindow(iwin,
1067 panel->frame->frame_x, panel->frame->frame_y, True);
1068 wCloseInspectorForWindow(wwin);
1069 } else {
1070 WMSetLabelText(panel->specLbl, spec_text);
1074 static InspectorPanel *createInspectorForWindow(WWindow *wwin, int xpos, int ypos, Bool showSelectPanel)
1076 WScreen *scr = wwin->screen_ptr;
1077 InspectorPanel *panel;
1078 Window parent;
1079 char *str = NULL, *tmp = NULL;
1080 int x, y, btn_width, frame_width;
1081 WMButton *selectedBtn = NULL;
1083 spec_text = _("The configuration will apply to all\n"
1084 "windows that have their WM_CLASS\n"
1085 "property set to the above selected\n" "name, when saved.");
1087 panel = wmalloc(sizeof(InspectorPanel));
1088 memset(panel, 0, sizeof(InspectorPanel));
1090 panel->destroyed = 0;
1091 panel->inspected = wwin;
1092 panel->nextPtr = panelList;
1093 panelList = panel;
1094 panel->win = WMCreateWindow(scr->wmscreen, "windowInspector");
1095 WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
1097 /**** create common stuff ****/
1098 /* command buttons */
1099 btn_width = (PWIDTH - (2 * 15) - (2 * 10)) / 3;
1100 panel->saveBtn = WMCreateCommandButton(panel->win);
1101 WMSetButtonAction(panel->saveBtn, saveSettings, panel);
1102 WMMoveWidget(panel->saveBtn, (2 * (btn_width + 10)) + 15, PHEIGHT - 40);
1103 WMSetButtonText(panel->saveBtn, _("Save"));
1104 WMResizeWidget(panel->saveBtn, btn_width, 28);
1105 if (wPreferences.flags.noupdates || !(wwin->wm_class || wwin->wm_instance))
1106 WMSetButtonEnabled(panel->saveBtn, False);
1108 panel->applyBtn = WMCreateCommandButton(panel->win);
1109 WMSetButtonAction(panel->applyBtn, applySettings, panel);
1110 WMMoveWidget(panel->applyBtn, btn_width + 10 + 15, PHEIGHT - 40);
1111 WMSetButtonText(panel->applyBtn, _("Apply"));
1112 WMResizeWidget(panel->applyBtn, btn_width, 28);
1114 panel->revertBtn = WMCreateCommandButton(panel->win);
1115 WMSetButtonAction(panel->revertBtn, revertSettings, panel);
1116 WMMoveWidget(panel->revertBtn, 15, PHEIGHT - 40);
1117 WMSetButtonText(panel->revertBtn, _("Reload"));
1118 WMResizeWidget(panel->revertBtn, btn_width, 28);
1120 /* page selection popup button */
1121 panel->pagePopUp = WMCreatePopUpButton(panel->win);
1122 WMSetPopUpButtonAction(panel->pagePopUp, changePage, panel);
1123 WMMoveWidget(panel->pagePopUp, 25, 15);
1124 WMResizeWidget(panel->pagePopUp, PWIDTH - 50, 20);
1126 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Specification"));
1127 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Attributes"));
1128 WMAddPopUpButtonItem(panel->pagePopUp, _("Advanced Options"));
1129 WMAddPopUpButtonItem(panel->pagePopUp, _("Icon and Initial Workspace"));
1130 WMAddPopUpButtonItem(panel->pagePopUp, _("Application Specific"));
1132 /**** window spec ****/
1133 frame_width = PWIDTH - (2 * 15);
1135 panel->specFrm = WMCreateFrame(panel->win);
1136 WMSetFrameTitle(panel->specFrm, _("Window Specification"));
1137 WMMoveWidget(panel->specFrm, 15, 65);
1138 WMResizeWidget(panel->specFrm, frame_width, 145);
1140 panel->defaultRb = WMCreateRadioButton(panel->specFrm);
1141 WMMoveWidget(panel->defaultRb, 10, 78);
1142 WMResizeWidget(panel->defaultRb, frame_width - (2 * 10), 20);
1143 WMSetButtonText(panel->defaultRb, _("Defaults for all windows"));
1144 WMSetButtonSelected(panel->defaultRb, False);
1145 WMSetButtonAction(panel->defaultRb, selectSpecification, panel);
1147 if (wwin->wm_class && wwin->wm_instance) {
1148 tmp = wstrconcat(wwin->wm_instance, ".");
1149 str = wstrconcat(tmp, wwin->wm_class);
1151 panel->bothRb = WMCreateRadioButton(panel->specFrm);
1152 WMMoveWidget(panel->bothRb, 10, 18);
1153 WMResizeWidget(panel->bothRb, frame_width - (2 * 10), 20);
1154 WMSetButtonText(panel->bothRb, str);
1155 wfree(tmp);
1156 wfree(str);
1157 WMGroupButtons(panel->defaultRb, panel->bothRb);
1159 if (!selectedBtn)
1160 selectedBtn = panel->bothRb;
1162 WMSetButtonAction(panel->bothRb, selectSpecification, panel);
1165 if (wwin->wm_instance) {
1166 panel->instRb = WMCreateRadioButton(panel->specFrm);
1167 WMMoveWidget(panel->instRb, 10, 38);
1168 WMResizeWidget(panel->instRb, frame_width - (2 * 10), 20);
1169 WMSetButtonText(panel->instRb, wwin->wm_instance);
1170 WMGroupButtons(panel->defaultRb, panel->instRb);
1172 if (!selectedBtn)
1173 selectedBtn = panel->instRb;
1175 WMSetButtonAction(panel->instRb, selectSpecification, panel);
1178 if (wwin->wm_class) {
1179 panel->clsRb = WMCreateRadioButton(panel->specFrm);
1180 WMMoveWidget(panel->clsRb, 10, 58);
1181 WMResizeWidget(panel->clsRb, frame_width - (2 * 10), 20);
1182 WMSetButtonText(panel->clsRb, wwin->wm_class);
1183 WMGroupButtons(panel->defaultRb, panel->clsRb);
1185 if (!selectedBtn)
1186 selectedBtn = panel->clsRb;
1188 WMSetButtonAction(panel->clsRb, selectSpecification, panel);
1191 panel->selWinB = WMCreateCommandButton(panel->specFrm);
1192 WMMoveWidget(panel->selWinB, 20, 145 - 24 - 10);
1193 WMResizeWidget(panel->selWinB, frame_width - 2 * 10 - 20, 24);
1194 WMSetButtonText(panel->selWinB, _("Select window"));
1195 WMSetButtonAction(panel->selWinB, selectWindow, panel);
1197 panel->specLbl = WMCreateLabel(panel->win);
1198 WMMoveWidget(panel->specLbl, 15, 210);
1199 WMResizeWidget(panel->specLbl, frame_width, 100);
1200 WMSetLabelText(panel->specLbl, spec_text);
1201 WMSetLabelWraps(panel->specLbl, True);
1203 WMSetLabelTextAlignment(panel->specLbl, WALeft);
1205 /**** attributes ****/
1206 create_tab_window_attributes(wwin, panel, frame_width);
1207 create_tab_window_advanced(wwin, panel, frame_width);
1208 create_tab_icon_workspace(wwin, panel);
1209 create_tab_app_specific(wwin, panel, frame_width);
1211 /* if the window is a transient, don't let it have a miniaturize button */
1212 if (wwin->transient_for != None && wwin->transient_for != scr->root_win)
1213 WMSetButtonEnabled(panel->attrChk[3], False);
1214 else
1215 WMSetButtonEnabled(panel->attrChk[3], True);
1217 if (!wwin->wm_class && !wwin->wm_instance)
1218 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 0, False);
1220 WMRealizeWidget(panel->win);
1222 WMMapSubwidgets(panel->win);
1223 WMMapSubwidgets(panel->specFrm);
1224 WMMapSubwidgets(panel->attrFrm);
1225 WMMapSubwidgets(panel->moreFrm);
1226 WMMapSubwidgets(panel->iconFrm);
1227 WMMapSubwidgets(panel->wsFrm);
1228 if (panel->appFrm)
1229 WMMapSubwidgets(panel->appFrm);
1231 if (showSelectPanel) {
1232 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 0);
1233 changePage(panel->pagePopUp, panel);
1234 } else {
1235 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 1);
1236 changePage(panel->pagePopUp, panel);
1239 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, PWIDTH, PHEIGHT, 0, 0, 0);
1240 XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
1241 panel->parent = parent;
1242 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1244 WMMapWidget(panel->win);
1246 XSetTransientForHint(dpy, parent, wwin->client_win);
1248 if (xpos == UNDEFINED_POS) {
1249 x = wwin->frame_x + wwin->frame->core->width / 2;
1250 y = wwin->frame_y + wwin->frame->top_width * 2;
1251 if (y + PHEIGHT > scr->scr_height)
1252 y = scr->scr_height - PHEIGHT - 30;
1253 if (x + PWIDTH > scr->scr_width)
1254 x = scr->scr_width - PWIDTH;
1255 } else {
1256 x = xpos;
1257 y = ypos;
1260 panel->frame = wManageInternalWindow(scr, parent, wwin->client_win, "Inspector", x, y, PWIDTH, PHEIGHT);
1262 if (!selectedBtn)
1263 selectedBtn = panel->defaultRb;
1265 WMSetButtonSelected(selectedBtn, True);
1266 selectSpecification(selectedBtn, panel);
1268 /* kluge to know who should get the key events */
1269 panel->frame->client_leader = WMWidgetXID(panel->win);
1271 panel->frame->client_flags.no_closable = 0;
1272 panel->frame->client_flags.no_close_button = 0;
1273 wWindowUpdateButtonImages(panel->frame);
1274 wFrameWindowShowButton(panel->frame->frame, WFF_RIGHT_BUTTON);
1275 panel->frame->frame->on_click_right = destroyInspector;
1277 wWindowMap(panel->frame);
1279 showIconFor(WMWidgetScreen(panel->alwChk), panel, wwin->wm_instance, wwin->wm_class, UPDATE_TEXT_FIELD);
1281 return panel;
1284 void wShowInspectorForWindow(WWindow *wwin)
1286 if (wwin->flags.inspector_open)
1287 return;
1289 WMSetBalloonEnabled(wwin->screen_ptr->wmscreen, wPreferences.help_balloon);
1291 make_keys();
1292 wwin->flags.inspector_open = 1;
1293 wwin->inspector = createInspectorForWindow(wwin, UNDEFINED_POS, UNDEFINED_POS, False);
1296 void wHideInspectorForWindow(WWindow *wwin)
1298 WWindow *pwin = wwin->inspector->frame;
1300 wWindowUnmap(pwin);
1301 pwin->flags.hidden = 1;
1303 wClientSetState(pwin, IconicState, None);
1306 void wUnhideInspectorForWindow(WWindow *wwin)
1308 WWindow *pwin = wwin->inspector->frame;
1310 pwin->flags.hidden = 0;
1311 pwin->flags.mapped = 1;
1312 XMapWindow(dpy, pwin->client_win);
1313 XMapWindow(dpy, pwin->frame->core->window);
1314 wClientSetState(pwin, NormalState, None);
1317 WWindow *wGetWindowOfInspectorForWindow(WWindow *wwin)
1319 if (!wwin->inspector)
1320 return NULL;
1322 assert(wwin->flags.inspector_open != 0);
1323 return wwin->inspector->frame;
1326 void wCloseInspectorForWindow(WWindow *wwin)
1328 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1330 (*pwin->frame->on_click_right) (NULL, pwin, NULL);
1333 static void create_tab_window_attributes(WWindow *wwin, InspectorPanel *panel, int frame_width)
1335 int i = 0;
1337 panel->attrFrm = WMCreateFrame(panel->win);
1338 WMSetFrameTitle(panel->attrFrm, _("Attributes"));
1339 WMMoveWidget(panel->attrFrm, 15, 45);
1340 WMResizeWidget(panel->attrFrm, frame_width, 250);
1342 for (i = 0; i < wlengthof(window_attribute); i++) {
1343 int is_userdef, flag;
1345 /* Read-only button to display the state requested by the application */
1346 flag = get_attr_flag(&wwin->client_flags, &window_attribute[i].flag);
1348 panel->attrClient[i] = WMCreateSwitchButton(panel->attrFrm);
1349 WMMoveWidget(panel->attrClient[i], 10, 20 * (i + 1));
1350 WMResizeWidget(panel->attrClient[i], 20, 20);
1351 WMSetButtonText(panel->attrClient[i], NULL);
1352 WMSetButtonSelected(panel->attrClient[i], flag);
1353 WMSetButtonEnabled(panel->attrClient[i], False);
1355 WMSetBalloonTextForView(_("Show the state that was asked by the application.\n"
1356 "You can use the checkbox on the right to change this setting;\n"
1357 "when it is grayed it means to follow application's choice."),
1358 WMWidgetView(panel->attrClient[i]));
1360 /* Button to let user override this choice */
1361 is_userdef = get_attr_flag(&wwin->defined_user_flags, &window_attribute[i].flag);
1362 if (is_userdef)
1363 flag = get_attr_flag(&wwin->user_flags, &window_attribute[i].flag);
1364 else
1365 flag = -1;
1367 panel->attrChk[i] = WMCreateButton(panel->attrFrm, WBTTriState);
1368 WMMoveWidget(panel->attrChk[i], 30, 20 * (i + 1));
1369 WMResizeWidget(panel->attrChk[i], frame_width - 45, 20);
1370 WMSetButtonSelected(panel->attrChk[i], flag);
1371 WMSetButtonText(panel->attrChk[i], _(window_attribute[i].caption));
1373 WMSetBalloonTextForView(_(window_attribute[i].description), WMWidgetView(panel->attrChk[i]));
1377 static void create_tab_window_advanced(WWindow *wwin, InspectorPanel *panel, int frame_width)
1379 int i = 0;
1381 panel->moreFrm = WMCreateFrame(panel->win);
1382 WMSetFrameTitle(panel->moreFrm, _("Advanced"));
1383 WMMoveWidget(panel->moreFrm, 15, 45);
1384 WMResizeWidget(panel->moreFrm, frame_width, 265);
1386 for (i = 0; i < wlengthof(advanced_option); i++) {
1387 int is_userdef, flag;
1389 is_userdef = get_attr_flag(&wwin->defined_user_flags, &advanced_option[i].flag);
1390 if (is_userdef)
1391 flag = get_attr_flag(&wwin->user_flags, &advanced_option[i].flag);
1392 else
1393 flag = get_attr_flag(&wwin->client_flags, &advanced_option[i].flag);
1395 panel->moreChk[i] = WMCreateSwitchButton(panel->moreFrm);
1396 WMMoveWidget(panel->moreChk[i], 10, 20 * (i + 1) - 4);
1397 WMResizeWidget(panel->moreChk[i], frame_width - 15, 20);
1398 WMSetButtonSelected(panel->moreChk[i], flag);
1399 WMSetButtonText(panel->moreChk[i], _(advanced_option[i].caption));
1401 WMSetBalloonTextForView(_(advanced_option[i].description), WMWidgetView(panel->moreChk[i]));
1405 static void create_tab_icon_workspace(WWindow *wwin, InspectorPanel *panel)
1407 WScreen *scr = wwin->screen_ptr;
1408 int i = 0;
1410 /* miniwindow/workspace */
1411 panel->iconFrm = WMCreateFrame(panel->win);
1412 WMMoveWidget(panel->iconFrm, 15, 50);
1413 WMResizeWidget(panel->iconFrm, PWIDTH - (2 * 15), 170);
1414 WMSetFrameTitle(panel->iconFrm, _("Miniwindow Image"));
1416 panel->iconLbl = WMCreateLabel(panel->iconFrm);
1417 WMMoveWidget(panel->iconLbl, PWIDTH - (2 * 15) - 22 - 64, 20);
1418 WMResizeWidget(panel->iconLbl, 64, 64);
1419 WMSetLabelRelief(panel->iconLbl, WRGroove);
1420 WMSetLabelImagePosition(panel->iconLbl, WIPImageOnly);
1422 panel->browseIconBtn = WMCreateCommandButton(panel->iconFrm);
1423 WMSetButtonAction(panel->browseIconBtn, chooseIconCallback, panel);
1424 WMMoveWidget(panel->browseIconBtn, 22, 32);
1425 WMResizeWidget(panel->browseIconBtn, 120, 26);
1426 WMSetButtonText(panel->browseIconBtn, _("Browse..."));
1428 panel->fileLbl = WMCreateLabel(panel->iconFrm);
1429 WMMoveWidget(panel->fileLbl, 20, 85);
1430 WMResizeWidget(panel->fileLbl, PWIDTH - (2 * 15) - (2 * 20), 14);
1431 WMSetLabelText(panel->fileLbl, _("Icon filename:"));
1433 panel->fileText = WMCreateTextField(panel->iconFrm);
1434 WMMoveWidget(panel->fileText, 20, 105);
1435 WMResizeWidget(panel->fileText, PWIDTH - (2 * 20) - (2 * 15), 20);
1436 WMSetTextFieldText(panel->fileText, NULL);
1437 WMAddNotificationObserver(textEditedObserver, panel, WMTextDidEndEditingNotification, panel->fileText);
1439 panel->alwChk = WMCreateSwitchButton(panel->iconFrm);
1440 WMMoveWidget(panel->alwChk, 20, 130);
1441 WMResizeWidget(panel->alwChk, PWIDTH - (2 * 15) - (2 * 15), 30);
1442 WMSetButtonText(panel->alwChk, _("Ignore client supplied icon"));
1443 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
1445 panel->wsFrm = WMCreateFrame(panel->win);
1446 WMMoveWidget(panel->wsFrm, 15, 225);
1447 WMResizeWidget(panel->wsFrm, PWIDTH - (2 * 15), 70);
1448 WMSetFrameTitle(panel->wsFrm, _("Initial Workspace"));
1450 WMSetBalloonTextForView(_("The workspace to place the window when it's"
1451 " first shown."), WMWidgetView(panel->wsFrm));
1453 panel->wsP = WMCreatePopUpButton(panel->wsFrm);
1454 WMMoveWidget(panel->wsP, 20, 30);
1455 WMResizeWidget(panel->wsP, PWIDTH - (2 * 15) - (2 * 20), 20);
1456 WMAddPopUpButtonItem(panel->wsP, _("Nowhere in particular"));
1458 for (i = 0; i < wwin->screen_ptr->workspace_count; i++)
1459 WMAddPopUpButtonItem(panel->wsP, scr->workspaces[i]->name);
1461 i = wDefaultGetStartWorkspace(wwin->screen_ptr, wwin->wm_instance, wwin->wm_class);
1462 if (i >= 0 && i <= wwin->screen_ptr->workspace_count)
1463 WMSetPopUpButtonSelectedItem(panel->wsP, i + 1);
1464 else
1465 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
1468 static void create_tab_app_specific(WWindow *wwin, InspectorPanel *panel, int frame_width)
1470 WScreen *scr = wwin->screen_ptr;
1471 int i = 0, tmp;
1473 if (wwin->main_window != None) {
1474 WApplication *wapp = wApplicationOf(wwin->main_window);
1476 panel->appFrm = WMCreateFrame(panel->win);
1477 WMSetFrameTitle(panel->appFrm, _("Application Attributes"));
1478 WMMoveWidget(panel->appFrm, 15, 50);
1479 WMResizeWidget(panel->appFrm, frame_width, 240);
1481 for (i = 0; i < wlengthof(application_attr); i++) {
1482 int is_userdef, flag;
1484 is_userdef = get_attr_flag(&wapp->main_window_desc->defined_user_flags, &application_attr[i].flag);
1485 if (is_userdef)
1486 flag = get_attr_flag(&wapp->main_window_desc->user_flags, &application_attr[i].flag);
1487 else
1488 flag = get_attr_flag(&wapp->main_window_desc->client_flags, &application_attr[i].flag);
1490 panel->appChk[i] = WMCreateSwitchButton(panel->appFrm);
1491 WMMoveWidget(panel->appChk[i], 10, 20 * (i + 1));
1492 WMResizeWidget(panel->appChk[i], 205, 20);
1493 WMSetButtonSelected(panel->appChk[i], flag);
1494 WMSetButtonText(panel->appChk[i], _(application_attr[i].caption));
1496 WMSetBalloonTextForView(_(application_attr[i].description),
1497 WMWidgetView(panel->appChk[i]));
1500 if (WFLAGP(wwin, emulate_appicon)) {
1501 WMSetButtonEnabled(panel->appChk[1], False);
1502 WMSetButtonEnabled(panel->moreChk[7], True);
1503 } else {
1504 WMSetButtonEnabled(panel->appChk[1], True);
1505 WMSetButtonEnabled(panel->moreChk[7], False);
1507 } else {
1508 if ((wwin->transient_for != None && wwin->transient_for != scr->root_win)
1509 || !wwin->wm_class || !wwin->wm_instance)
1510 tmp = False;
1511 else
1512 tmp = True;
1514 WMSetButtonEnabled(panel->moreChk[7], tmp);
1516 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 4, False);
1517 panel->appFrm = NULL;