Fixed possible off-by-one loops
[wmaker-crm.git] / src / winspector.c
bloba58571049d8afca30c60d72defdbcd094f78e4ac
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 "funcs.h"
39 #include "defaults.h"
40 #include "dialog.h"
41 #include "icon.h"
42 #include "stacking.h"
43 #include "application.h"
44 #include "appicon.h"
45 #include "actions.h"
46 #include "winspector.h"
47 #include "dock.h"
48 #include "client.h"
49 #include "wmspec.h"
50 #include "xinerama.h"
52 #include <WINGs/WUtil.h>
54 typedef struct InspectorPanel {
55 struct InspectorPanel *nextPtr;
57 WWindow *frame;
59 WWindow *inspected; /* the window that's being inspected */
61 WMWindow *win;
63 Window parent;
65 /* common stuff */
66 WMButton *revertBtn;
67 WMButton *applyBtn;
68 WMButton *saveBtn;
70 WMPopUpButton *pagePopUp;
72 /* first page. general stuff */
74 WMFrame *specFrm;
75 WMButton *instRb;
76 WMButton *clsRb;
77 WMButton *bothRb;
78 WMButton *defaultRb;
80 WMButton *selWinB;
82 WMLabel *specLbl;
84 /* second page. attributes */
86 WMFrame *attrFrm;
87 WMButton *attrChk[11];
89 /* 3rd page. more attributes */
90 WMFrame *moreFrm;
91 #ifdef XKB_BUTTON_HINT
92 WMButton *moreChk[12];
93 #else
94 WMButton *moreChk[11];
95 #endif
97 /* 4th page. icon and workspace */
98 WMFrame *iconFrm;
99 WMLabel *iconLbl;
100 WMLabel *fileLbl;
101 WMTextField *fileText;
102 WMButton *alwChk;
104 WMButton *updateIconBtn;
106 WMButton *browseIconBtn;
108 WMFrame *wsFrm;
109 WMPopUpButton *wsP;
111 /* 5th page. application wide attributes */
112 WMFrame *appFrm;
113 WMButton *appChk[3];
115 unsigned int done:1;
116 unsigned int destroyed:1;
117 unsigned int choosingIcon:1;
118 } InspectorPanel;
120 extern Cursor wCursor[WCUR_LAST];
121 extern WDDomain *WDWindowAttributes;
122 extern WPreferences wPreferences;
124 static InspectorPanel *panelList = NULL;
125 static WMPropList *ANoTitlebar = NULL;
126 static WMPropList *ANoResizebar;
127 static WMPropList *ANoMiniaturizeButton;
128 static WMPropList *ANoCloseButton;
129 static WMPropList *ANoBorder;
130 static WMPropList *ANoHideOthers;
131 static WMPropList *ANoMouseBindings;
132 static WMPropList *ANoKeyBindings;
133 static WMPropList *ANoAppIcon;
134 static WMPropList *AKeepOnTop;
135 static WMPropList *AKeepOnBottom;
136 static WMPropList *AOmnipresent;
137 static WMPropList *ASkipWindowList;
138 static WMPropList *ASkipSwitchPanel;
139 static WMPropList *AKeepInsideScreen;
140 static WMPropList *AUnfocusable;
141 static WMPropList *AFocusAcrossWorkspace;
142 static WMPropList *AAlwaysUserIcon;
143 static WMPropList *AStartMiniaturized;
144 static WMPropList *AStartMaximized;
145 static WMPropList *ADontSaveSession;
146 static WMPropList *AEmulateAppIcon;
147 static WMPropList *AFullMaximize;
148 static WMPropList *ASharedAppIcon;
149 static WMPropList *ANoMiniaturizable;
150 #ifdef XKB_BUTTON_HINT
151 static WMPropList *ANoLanguageButton;
152 #endif
153 static WMPropList *AStartWorkspace;
154 static WMPropList *AIcon;
156 /* application wide options */
157 static WMPropList *AStartHidden;
158 static WMPropList *AnyWindow;
159 static WMPropList *EmptyString;
160 static WMPropList *Yes, *No;
162 #define PWIDTH 290
163 #define PHEIGHT 360
165 static char *spec_text;
166 static void applySettings(WMButton * button, InspectorPanel * panel);
168 #define UNDEFINED_POS 0xffffff
170 static InspectorPanel *createInspectorForWindow(WWindow * wwin, int xpos, int ypos, Bool showSelectPanel);
172 static void make_keys(void)
174 if (ANoTitlebar != NULL)
175 return;
177 AIcon = WMCreatePLString("Icon");
178 ANoTitlebar = WMCreatePLString("NoTitlebar");
179 ANoResizebar = WMCreatePLString("NoResizebar");
180 ANoMiniaturizeButton = WMCreatePLString("NoMiniaturizeButton");
181 ANoCloseButton = WMCreatePLString("NoCloseButton");
182 ANoBorder = WMCreatePLString("NoBorder");
183 ANoHideOthers = WMCreatePLString("NoHideOthers");
184 ANoMouseBindings = WMCreatePLString("NoMouseBindings");
185 ANoKeyBindings = WMCreatePLString("NoKeyBindings");
186 ANoAppIcon = WMCreatePLString("NoAppIcon");
187 AKeepOnTop = WMCreatePLString("KeepOnTop");
188 AKeepOnBottom = WMCreatePLString("KeepOnBottom");
189 AOmnipresent = WMCreatePLString("Omnipresent");
190 ASkipWindowList = WMCreatePLString("SkipWindowList");
191 ASkipSwitchPanel = WMCreatePLString("SkipSwitchPanel");
192 AKeepInsideScreen = WMCreatePLString("KeepInsideScreen");
193 AUnfocusable = WMCreatePLString("Unfocusable");
194 AFocusAcrossWorkspace = WMCreatePLString("FocusAcrossWorkspace");
195 AAlwaysUserIcon = WMCreatePLString("AlwaysUserIcon");
196 AStartMiniaturized = WMCreatePLString("StartMiniaturized");
197 AStartMaximized = WMCreatePLString("StartMaximized");
198 AStartHidden = WMCreatePLString("StartHidden");
199 ADontSaveSession = WMCreatePLString("DontSaveSession");
200 AEmulateAppIcon = WMCreatePLString("EmulateAppIcon");
201 AFullMaximize = WMCreatePLString("FullMaximize");
202 ASharedAppIcon = WMCreatePLString("SharedAppIcon");
203 ANoMiniaturizable = WMCreatePLString("NoMiniaturizable");
204 #ifdef XKB_BUTTON_HINT
205 ANoLanguageButton = WMCreatePLString("NoLanguageButton");
206 #endif
208 AStartWorkspace = WMCreatePLString("StartWorkspace");
210 AnyWindow = WMCreatePLString("*");
211 EmptyString = WMCreatePLString("");
212 Yes = WMCreatePLString("Yes");
213 No = WMCreatePLString("No");
216 static void freeInspector(InspectorPanel * panel)
218 panel->destroyed = 1;
219 if (panel->choosingIcon)
220 return;
222 WMDestroyWidget(panel->win);
224 XDestroyWindow(dpy, panel->parent);
226 wfree(panel);
229 static void destroyInspector(WCoreWindow * foo, void *data, XEvent * event)
231 InspectorPanel *panel;
232 InspectorPanel *tmp;
234 panel = panelList;
235 while (panel->frame != data)
236 panel = panel->nextPtr;
238 if (panelList == panel)
239 panelList = panel->nextPtr;
240 else {
241 tmp = panelList;
242 while (tmp->nextPtr != panel) {
243 tmp = tmp->nextPtr;
245 tmp->nextPtr = panel->nextPtr;
247 panel->inspected->flags.inspector_open = 0;
248 panel->inspected->inspector = NULL;
250 WMRemoveNotificationObserver(panel);
252 wWindowUnmap(panel->frame);
253 wUnmanageWindow(panel->frame, True, False);
255 freeInspector(panel);
258 void wDestroyInspectorPanels(void)
260 InspectorPanel *panel;
262 while (panelList != NULL) {
263 panel = panelList;
264 panelList = panelList->nextPtr;
265 wUnmanageWindow(panel->frame, False, False);
266 WMDestroyWidget(panel->win);
268 panel->inspected->flags.inspector_open = 0;
269 panel->inspected->inspector = NULL;
271 wfree(panel);
275 static void changePage(WMPopUpButton * bPtr, InspectorPanel * panel)
277 int page;
279 page = WMGetPopUpButtonSelectedItem(bPtr);
281 if (page == 0) {
282 WMMapWidget(panel->specFrm);
283 WMMapWidget(panel->specLbl);
284 } else if (page == 1) {
285 WMMapWidget(panel->attrFrm);
286 } else if (page == 2) {
287 WMMapWidget(panel->moreFrm);
288 } else if (page == 3) {
289 WMMapWidget(panel->iconFrm);
290 WMMapWidget(panel->wsFrm);
291 } else {
292 WMMapWidget(panel->appFrm);
295 if (page != 0) {
296 WMUnmapWidget(panel->specFrm);
297 WMUnmapWidget(panel->specLbl);
299 if (page != 1)
300 WMUnmapWidget(panel->attrFrm);
301 if (page != 2)
302 WMUnmapWidget(panel->moreFrm);
303 if (page != 3) {
304 WMUnmapWidget(panel->iconFrm);
305 WMUnmapWidget(panel->wsFrm);
307 if (page != 4 && panel->appFrm)
308 WMUnmapWidget(panel->appFrm);
311 #define USE_TEXT_FIELD 1
312 #define UPDATE_TEXT_FIELD 2
313 #define REVERT_TO_DEFAULT 4
315 static int showIconFor(WMScreen * scrPtr, InspectorPanel * panel, char *wm_instance, char *wm_class, int flags)
317 WMPixmap *pixmap = (WMPixmap *) NULL;
318 char *file = NULL, *path = NULL;
319 char *db_icon = NULL;
321 if ((flags & USE_TEXT_FIELD) != 0) {
322 file = WMGetTextFieldText(panel->fileText);
323 if (file && file[0] == 0) {
324 wfree(file);
325 file = NULL;
327 } else {
328 db_icon = wDefaultGetIconFile(panel->inspected->screen_ptr, wm_instance, wm_class, False);
329 if (db_icon != NULL)
330 file = wstrdup(db_icon);
332 if (db_icon != NULL && (flags & REVERT_TO_DEFAULT) != 0) {
333 if (file)
334 file = wstrdup(db_icon);
335 flags |= UPDATE_TEXT_FIELD;
338 if ((flags & UPDATE_TEXT_FIELD) != 0) {
339 WMSetTextFieldText(panel->fileText, file);
342 if (file) {
343 path = FindImage(wPreferences.icon_path, file);
345 if (!path) {
346 char *buf;
347 int len = strlen(file) + 80;
349 buf = wmalloc(len);
350 snprintf(buf, len, _("Could not find icon \"%s\" specified for this window"), file);
351 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
352 wfree(buf);
353 wfree(file);
354 return -1;
357 pixmap = WMCreatePixmapFromFile(scrPtr, path);
358 wfree(path);
360 if (!pixmap) {
361 char *buf;
362 int len = strlen(file) + 80;
364 buf = wmalloc(len);
365 snprintf(buf, len, _("Could not open specified icon \"%s\":%s"),
366 file, RMessageForError(RErrorCode));
367 wMessageDialog(panel->frame->screen_ptr, _("Error"), buf, _("OK"), NULL, NULL);
368 wfree(buf);
369 wfree(file);
370 return -1;
372 wfree(file);
375 WMSetLabelImage(panel->iconLbl, pixmap);
376 if (pixmap)
377 WMReleasePixmap(pixmap);
379 return 0;
382 #if 0
383 static void updateIcon(WMButton * button, InspectorPanel * panel)
385 showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD);
387 #endif
389 static int getBool(WMPropList * value)
391 char *val;
393 if (!WMIsPLString(value)) {
394 return 0;
396 if (!(val = WMGetFromPLString(value))) {
397 return 0;
400 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y' || val[0] == 'T' || val[0] == 't' || val[0] == '1'))
401 || (strcasecmp(val, "YES") == 0 || strcasecmp(val, "TRUE") == 0)) {
403 return 1;
404 } else if ((val[1] == '\0'
405 && (val[0] == 'n' || val[0] == 'N' || val[0] == 'F' || val[0] == 'f' || val[0] == '0'))
406 || (strcasecmp(val, "NO") == 0 || strcasecmp(val, "FALSE") == 0)) {
408 return 0;
409 } else {
410 wwarning(_("can't convert \"%s\" to boolean"), val);
411 return 0;
415 #define UPDATE_DEFAULTS 1
416 #define IS_BOOLEAN 2
419 * Will insert the attribute = value; pair in window's list,
420 * if it's different from the defaults.
421 * Defaults means either defaults database, or attributes saved
422 * for the default window "*". This is to let one revert options that are
423 * global because they were saved for all windows ("*").
427 static int
428 insertAttribute(WMPropList * dict, WMPropList * window, WMPropList * attr, WMPropList * value, int flags)
430 WMPropList *def_win, *def_value = NULL;
431 int update = 0;
432 int modified = 0;
434 if (!(flags & UPDATE_DEFAULTS) && dict) {
435 if ((def_win = WMGetFromPLDictionary(dict, AnyWindow)) != NULL) {
436 def_value = WMGetFromPLDictionary(def_win, attr);
440 /* If we could not find defaults in database, fall to hardcoded values.
441 * Also this is true if we save defaults for all windows
443 if (!def_value)
444 def_value = ((flags & IS_BOOLEAN) != 0) ? No : EmptyString;
446 if ((flags & IS_BOOLEAN))
447 update = (getBool(value) != getBool(def_value));
448 else {
449 update = !WMIsPropListEqualTo(value, def_value);
452 if (update) {
453 WMPutInPLDictionary(window, attr, value);
454 modified = 1;
457 return modified;
460 static void saveSettings(WMButton * button, InspectorPanel * panel)
462 WWindow *wwin = panel->inspected;
463 WDDomain *db = WDWindowAttributes;
464 WMPropList *dict = db->dictionary;
465 WMPropList *winDic, *appDic, *value, *key, *key2;
466 char *icon_file;
467 int flags = 0;
468 int different = 0, different2 = 0;
470 /* Save will apply the changes and save them */
471 applySettings(panel->applyBtn, panel);
473 if (WMGetButtonSelected(panel->instRb) != 0)
474 key = WMCreatePLString(wwin->wm_instance);
475 else if (WMGetButtonSelected(panel->clsRb) != 0)
476 key = WMCreatePLString(wwin->wm_class);
477 else if (WMGetButtonSelected(panel->bothRb) != 0) {
478 char *buffer;
480 buffer = StrConcatDot(wwin->wm_instance, wwin->wm_class);
481 key = WMCreatePLString(buffer);
482 wfree(buffer);
483 } else if (WMGetButtonSelected(panel->defaultRb) != 0) {
484 key = WMRetainPropList(AnyWindow);
485 flags = UPDATE_DEFAULTS;
486 } else
487 key = NULL;
489 if (!key)
490 return;
492 if (!dict) {
493 dict = WMCreatePLDictionary(NULL, NULL);
494 if (dict) {
495 db->dictionary = dict;
496 } else {
497 WMReleasePropList(key);
498 return;
502 if (showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD) < 0)
503 return;
505 WMPLSetCaseSensitive(True);
507 winDic = WMCreatePLDictionary(NULL, NULL);
508 appDic = WMCreatePLDictionary(NULL, NULL);
510 /* Update icon for window */
511 icon_file = WMGetTextFieldText(panel->fileText);
512 if (icon_file) {
513 if (icon_file[0] != 0) {
514 value = WMCreatePLString(icon_file);
515 different |= insertAttribute(dict, winDic, AIcon, value, flags);
516 different2 |= insertAttribute(dict, appDic, AIcon, value, flags);
517 WMReleasePropList(value);
519 wfree(icon_file);
523 int i = WMGetPopUpButtonSelectedItem(panel->wsP);
525 i--;
527 if (i >= 0 && i < panel->frame->screen_ptr->workspace_count) {
528 value = WMCreatePLString(panel->frame->screen_ptr->workspaces[i]->name);
529 different |= insertAttribute(dict, winDic, AStartWorkspace, value, flags);
530 WMReleasePropList(value);
534 flags |= IS_BOOLEAN;
536 value = (WMGetButtonSelected(panel->alwChk) != 0) ? Yes : No;
537 different |= insertAttribute(dict, winDic, AAlwaysUserIcon, value, flags);
539 value = (WMGetButtonSelected(panel->attrChk[0]) != 0) ? Yes : No;
540 different |= insertAttribute(dict, winDic, ANoTitlebar, value, flags);
542 value = (WMGetButtonSelected(panel->attrChk[1]) != 0) ? Yes : No;
543 different |= insertAttribute(dict, winDic, ANoResizebar, value, flags);
545 value = (WMGetButtonSelected(panel->attrChk[2]) != 0) ? Yes : No;
546 different |= insertAttribute(dict, winDic, ANoCloseButton, value, flags);
548 value = (WMGetButtonSelected(panel->attrChk[3]) != 0) ? Yes : No;
549 different |= insertAttribute(dict, winDic, ANoMiniaturizeButton, value, flags);
551 value = (WMGetButtonSelected(panel->attrChk[4]) != 0) ? Yes : No;
552 different |= insertAttribute(dict, winDic, ANoBorder, value, flags);
554 value = (WMGetButtonSelected(panel->attrChk[5]) != 0) ? Yes : No;
555 different |= insertAttribute(dict, winDic, AKeepOnTop, value, flags);
557 value = (WMGetButtonSelected(panel->attrChk[6]) != 0) ? Yes : No;
558 different |= insertAttribute(dict, winDic, AKeepOnBottom, value, flags);
560 value = (WMGetButtonSelected(panel->attrChk[7]) != 0) ? Yes : No;
561 different |= insertAttribute(dict, winDic, AOmnipresent, value, flags);
563 value = (WMGetButtonSelected(panel->attrChk[8]) != 0) ? Yes : No;
564 different |= insertAttribute(dict, winDic, AStartMiniaturized, value, flags);
566 value = (WMGetButtonSelected(panel->attrChk[9]) != 0) ? Yes : No;
567 different |= insertAttribute(dict, winDic, AStartMaximized, value, flags);
569 value = (WMGetButtonSelected(panel->attrChk[10]) != 0) ? Yes : No;
570 different |= insertAttribute(dict, winDic, AFullMaximize, value, flags);
572 value = (WMGetButtonSelected(panel->moreChk[0]) != 0) ? Yes : No;
573 different |= insertAttribute(dict, winDic, ANoKeyBindings, value, flags);
575 value = (WMGetButtonSelected(panel->moreChk[1]) != 0) ? Yes : No;
576 different |= insertAttribute(dict, winDic, ANoMouseBindings, value, flags);
578 value = (WMGetButtonSelected(panel->moreChk[2]) != 0) ? Yes : No;
579 different |= insertAttribute(dict, winDic, ASkipWindowList, value, flags);
581 value = (WMGetButtonSelected(panel->moreChk[3]) != 0) ? Yes : No;
582 different |= insertAttribute(dict, winDic, ASkipSwitchPanel, value, flags);
584 value = (WMGetButtonSelected(panel->moreChk[4]) != 0) ? Yes : No;
585 different |= insertAttribute(dict, winDic, AUnfocusable, value, flags);
587 value = (WMGetButtonSelected(panel->moreChk[5]) != 0) ? Yes : No;
588 different |= insertAttribute(dict, winDic, AKeepInsideScreen, value, flags);
590 value = (WMGetButtonSelected(panel->moreChk[6]) != 0) ? Yes : No;
591 different |= insertAttribute(dict, winDic, ANoHideOthers, value, flags);
593 value = (WMGetButtonSelected(panel->moreChk[7]) != 0) ? Yes : No;
594 different |= insertAttribute(dict, winDic, ADontSaveSession, value, flags);
596 value = (WMGetButtonSelected(panel->moreChk[8]) != 0) ? Yes : No;
597 different |= insertAttribute(dict, winDic, AEmulateAppIcon, value, flags);
599 value = (WMGetButtonSelected(panel->moreChk[9]) != 0) ? Yes : No;
600 different |= insertAttribute(dict, winDic, AFocusAcrossWorkspace, value, flags);
602 value = (WMGetButtonSelected(panel->moreChk[10]) != 0) ? Yes : No;
603 different |= insertAttribute(dict, winDic, ANoMiniaturizable, value, flags);
605 #ifdef XKB_BUTTON_HINT
606 value = (WMGetButtonSelected(panel->moreChk[11]) != 0) ? Yes : No;
607 different |= insertAttribute(dict, winDic, ANoLanguageButton, value, flags);
608 #endif
610 if (wwin->main_window != None && wApplicationOf(wwin->main_window) != NULL) {
611 value = (WMGetButtonSelected(panel->appChk[0]) != 0) ? Yes : No;
612 different2 |= insertAttribute(dict, appDic, AStartHidden, value, flags);
614 value = (WMGetButtonSelected(panel->appChk[1]) != 0) ? Yes : No;
615 different2 |= insertAttribute(dict, appDic, ANoAppIcon, value, flags);
617 value = (WMGetButtonSelected(panel->appChk[2]) != 0) ? Yes : No;
618 different2 |= insertAttribute(dict, appDic, ASharedAppIcon, value, flags);
621 if (wwin->fake_group) {
622 key2 = WMCreatePLString(wwin->fake_group->identifier);
623 if (WMIsPropListEqualTo(key, key2)) {
624 WMMergePLDictionaries(winDic, appDic, True);
625 different |= different2;
626 } else {
627 WMRemoveFromPLDictionary(dict, key2);
628 if (different2) {
629 WMPutInPLDictionary(dict, key2, appDic);
632 WMReleasePropList(key2);
633 WMReleasePropList(appDic);
634 } else if (wwin->main_window != wwin->client_win) {
635 WApplication *wapp = wApplicationOf(wwin->main_window);
637 if (wapp) {
638 char *instance = wapp->main_window_desc->wm_instance;
639 char *class = wapp->main_window_desc->wm_class;
640 char *buffer;
642 buffer = StrConcatDot(instance, class);
643 key2 = WMCreatePLString(buffer);
644 wfree(buffer);
646 if (WMIsPropListEqualTo(key, key2)) {
647 WMMergePLDictionaries(winDic, appDic, True);
648 different |= different2;
649 } else {
650 WMRemoveFromPLDictionary(dict, key2);
651 if (different2)
652 WMPutInPLDictionary(dict, key2, appDic);
654 WMReleasePropList(key2);
655 WMReleasePropList(appDic);
657 } else {
658 WMMergePLDictionaries(winDic, appDic, True);
659 different |= different2;
660 WMReleasePropList(appDic);
663 WMRemoveFromPLDictionary(dict, key);
664 if (different) {
665 WMPutInPLDictionary(dict, key, winDic);
668 WMReleasePropList(key);
669 WMReleasePropList(winDic);
671 UpdateDomainFile(db);
673 /* clean up */
674 WMPLSetCaseSensitive(False);
677 static void makeAppIconFor(WApplication * wapp)
679 WScreen *scr = wapp->main_window_desc->screen_ptr;
681 if (wapp->app_icon)
682 return;
684 if (!WFLAGP(wapp->main_window_desc, no_appicon))
685 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
686 else
687 wapp->app_icon = NULL;
689 if (wapp->app_icon) {
690 WIcon *icon = wapp->app_icon->icon;
691 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
692 int x = 0, y = 0;
694 wapp->app_icon->main_window = wapp->main_window;
696 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
697 wapp->app_icon->attracted = 1;
698 if (!wapp->app_icon->icon->shadowed) {
699 wapp->app_icon->icon->shadowed = 1;
700 wapp->app_icon->icon->force_paint = 1;
702 wDockAttachIcon(clip, wapp->app_icon, x, y);
703 } else {
704 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wapp->main_window_desc));
705 wAppIconMove(wapp->app_icon, x, y);
707 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
708 XMapWindow(dpy, icon->core->window);
710 if (wPreferences.auto_arrange_icons && !wapp->app_icon->attracted)
711 wArrangeIcons(wapp->main_window_desc->screen_ptr, True);
715 static void removeAppIconFor(WApplication * wapp)
717 if (!wapp->app_icon)
718 return;
720 if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
721 wapp->app_icon->running = 0;
722 /* since we keep it, we don't care if it was attracted or not */
723 wapp->app_icon->attracted = 0;
724 wapp->app_icon->icon->shadowed = 0;
725 wapp->app_icon->main_window = None;
726 wapp->app_icon->pid = 0;
727 wapp->app_icon->icon->owner = NULL;
728 wapp->app_icon->icon->icon_win = None;
729 wapp->app_icon->icon->force_paint = 1;
730 wAppIconPaint(wapp->app_icon);
731 } else if (wapp->app_icon->docked) {
732 wapp->app_icon->running = 0;
733 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
734 } else {
735 wAppIconDestroy(wapp->app_icon);
737 wapp->app_icon = NULL;
738 if (wPreferences.auto_arrange_icons)
739 wArrangeIcons(wapp->main_window_desc->screen_ptr, True);
742 static void applySettings(WMButton * button, InspectorPanel * panel)
744 WWindow *wwin = panel->inspected;
745 WApplication *wapp = wApplicationOf(wwin->main_window);
746 int floating, sunken, skip_window_list;
747 int old_omnipresent;
748 int old_no_bind_keys;
749 int old_no_bind_mouse;
751 old_omnipresent = WFLAGP(wwin, omnipresent);
752 old_no_bind_keys = WFLAGP(wwin, no_bind_keys);
753 old_no_bind_mouse = WFLAGP(wwin, no_bind_mouse);
755 showIconFor(WMWidgetScreen(button), panel, NULL, NULL, USE_TEXT_FIELD);
757 /* Attributes... --> Window Attributes */
758 WSETUFLAG(wwin, no_titlebar, WMGetButtonSelected(panel->attrChk[0]));
759 WSETUFLAG(wwin, no_resizebar, WMGetButtonSelected(panel->attrChk[1]));
760 WSETUFLAG(wwin, no_close_button, WMGetButtonSelected(panel->attrChk[2]));
761 WSETUFLAG(wwin, no_miniaturize_button, WMGetButtonSelected(panel->attrChk[3]));
762 WSETUFLAG(wwin, no_border, WMGetButtonSelected(panel->attrChk[4]));
763 floating = WMGetButtonSelected(panel->attrChk[5]);
764 sunken = WMGetButtonSelected(panel->attrChk[6]);
765 WSETUFLAG(wwin, omnipresent, WMGetButtonSelected(panel->attrChk[7]));
766 WSETUFLAG(wwin, start_miniaturized, WMGetButtonSelected(panel->attrChk[8]));
767 WSETUFLAG(wwin, start_maximized, WMGetButtonSelected(panel->attrChk[9]));
768 WSETUFLAG(wwin, full_maximize, WMGetButtonSelected(panel->attrChk[10]));
770 /* Attributes... --> Advanced Options */
771 WSETUFLAG(wwin, no_bind_keys, WMGetButtonSelected(panel->moreChk[0]));
772 WSETUFLAG(wwin, no_bind_mouse, WMGetButtonSelected(panel->moreChk[1]));
773 skip_window_list = WMGetButtonSelected(panel->moreChk[2]);
774 WSETUFLAG(wwin, skip_switchpanel, WMGetButtonSelected(panel->moreChk[3]));
775 WSETUFLAG(wwin, no_focusable, WMGetButtonSelected(panel->moreChk[4]));
776 WSETUFLAG(wwin, dont_move_off, WMGetButtonSelected(panel->moreChk[5]));
777 WSETUFLAG(wwin, no_hide_others, WMGetButtonSelected(panel->moreChk[6]));
778 WSETUFLAG(wwin, dont_save_session, WMGetButtonSelected(panel->moreChk[7]));
779 WSETUFLAG(wwin, emulate_appicon, WMGetButtonSelected(panel->moreChk[8]));
780 WSETUFLAG(wwin, focus_across_wksp, WMGetButtonSelected(panel->moreChk[9]));
781 WSETUFLAG(wwin, no_miniaturizable, WMGetButtonSelected(panel->moreChk[10]));
782 #ifdef XKB_BUTTON_HINT
783 WSETUFLAG(wwin, no_language_button, WMGetButtonSelected(panel->moreChk[11]));
784 #endif
785 WSETUFLAG(wwin, always_user_icon, WMGetButtonSelected(panel->alwChk));
787 if (WFLAGP(wwin, no_titlebar) && wwin->flags.shaded)
788 wUnshadeWindow(wwin);
790 WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
792 if (floating) {
793 if (!WFLAGP(wwin, floating))
794 ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
795 } else if (sunken) {
796 if (!WFLAGP(wwin, sunken))
797 ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
798 } else {
799 if (WFLAGP(wwin, floating) || WFLAGP(wwin, sunken))
800 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
803 WSETUFLAG(wwin, sunken, sunken);
804 WSETUFLAG(wwin, floating, floating);
805 wwin->flags.omnipresent = 0;
807 if (WFLAGP(wwin, skip_window_list) != skip_window_list) {
808 WSETUFLAG(wwin, skip_window_list, skip_window_list);
809 UpdateSwitchMenu(wwin->screen_ptr, wwin, skip_window_list ? ACTION_REMOVE : ACTION_ADD);
810 } else {
811 if (WFLAGP(wwin, omnipresent) != old_omnipresent) {
812 WMPostNotificationName(WMNChangedState, wwin, "omnipresent");
816 if (WFLAGP(wwin, no_bind_keys) != old_no_bind_keys) {
817 if (WFLAGP(wwin, no_bind_keys)) {
818 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
819 } else {
820 wWindowSetKeyGrabs(wwin);
824 if (WFLAGP(wwin, no_bind_mouse) != old_no_bind_mouse) {
825 wWindowResetMouseGrabs(wwin);
828 wwin->frame->flags.need_texture_change = 1;
829 wWindowConfigureBorders(wwin);
830 wFrameWindowPaint(wwin->frame);
831 wNETWMUpdateActions(wwin, False);
834 * Can't apply emulate_appicon because it will probably cause problems.
836 if (wapp) {
837 /* do application wide stuff */
838 WSETUFLAG(wapp->main_window_desc, start_hidden, WMGetButtonSelected(panel->appChk[0]));
840 WSETUFLAG(wapp->main_window_desc, no_appicon, WMGetButtonSelected(panel->appChk[1]));
842 WSETUFLAG(wapp->main_window_desc, shared_appicon, WMGetButtonSelected(panel->appChk[2]));
844 if (WFLAGP(wapp->main_window_desc, no_appicon))
845 removeAppIconFor(wapp);
846 else
847 makeAppIconFor(wapp);
849 if (wapp->app_icon && wapp->main_window == wwin->client_win) {
850 char *file = WMGetTextFieldText(panel->fileText);
852 if (file[0] == 0) {
853 wfree(file);
854 file = NULL;
856 wIconChangeImageFile(wapp->app_icon->icon, file);
857 if (file)
858 wfree(file);
859 wAppIconPaint(wapp->app_icon);
864 static void revertSettings(WMButton * button, InspectorPanel * panel)
866 WWindow *wwin = panel->inspected;
867 WApplication *wapp = wApplicationOf(wwin->main_window);
868 int i, n;
869 char *wm_instance = NULL;
870 char *wm_class = NULL;
871 int workspace, level;
873 if (panel->instRb && WMGetButtonSelected(panel->instRb) != 0)
874 wm_instance = wwin->wm_instance;
875 else if (panel->clsRb && WMGetButtonSelected(panel->clsRb) != 0)
876 wm_class = wwin->wm_class;
877 else if (panel->bothRb && WMGetButtonSelected(panel->bothRb) != 0) {
878 wm_instance = wwin->wm_instance;
879 wm_class = wwin->wm_class;
881 memset(&wwin->defined_user_flags, 0, sizeof(WWindowAttributes));
882 memset(&wwin->user_flags, 0, sizeof(WWindowAttributes));
883 memset(&wwin->client_flags, 0, sizeof(WWindowAttributes));
885 wWindowSetupInitialAttributes(wwin, &level, &workspace);
887 for (i = 0; i < (sizeof(panel->attrChk) / sizeof(panel->attrChk[0])); i++) {
888 int flag = 0;
890 switch (i) {
891 case 0:
892 flag = WFLAGP(wwin, no_titlebar);
893 break;
894 case 1:
895 flag = WFLAGP(wwin, no_resizebar);
896 break;
897 case 2:
898 flag = WFLAGP(wwin, no_close_button);
899 break;
900 case 3:
901 flag = WFLAGP(wwin, no_miniaturize_button);
902 break;
903 case 4:
904 flag = WFLAGP(wwin, no_border);
905 break;
906 case 5:
907 flag = WFLAGP(wwin, floating);
908 break;
909 case 6:
910 flag = WFLAGP(wwin, sunken);
911 break;
912 case 7:
913 flag = WFLAGP(wwin, omnipresent);
914 break;
915 case 8:
916 flag = WFLAGP(wwin, start_miniaturized);
917 break;
918 case 9:
919 flag = WFLAGP(wwin, start_maximized != 0);
920 break;
921 case 10:
922 flag = WFLAGP(wwin, full_maximize);
923 break;
925 WMSetButtonSelected(panel->attrChk[i], flag);
927 for (i = 0; i < (sizeof(panel->moreChk) / sizeof(panel->moreChk[0])); i++) {
928 int flag = 0;
930 switch (i) {
931 case 0:
932 flag = WFLAGP(wwin, no_bind_keys);
933 break;
934 case 1:
935 flag = WFLAGP(wwin, no_bind_mouse);
936 break;
937 case 2:
938 flag = WFLAGP(wwin, skip_window_list);
939 break;
940 case 3:
941 flag = WFLAGP(wwin, skip_switchpanel);
942 break;
943 case 4:
944 flag = WFLAGP(wwin, no_focusable);
945 break;
946 case 5:
947 flag = WFLAGP(wwin, dont_move_off);
948 break;
949 case 6:
950 flag = WFLAGP(wwin, no_hide_others);
951 break;
952 case 7:
953 flag = WFLAGP(wwin, dont_save_session);
954 break;
955 case 8:
956 flag = WFLAGP(wwin, emulate_appicon);
957 break;
958 case 9:
959 flag = WFLAGP(wwin, focus_across_wksp);
960 break;
961 case 10:
962 flag = WFLAGP(wwin, no_miniaturizable);
963 break;
964 #ifdef XKB_BUTTON_HINT
965 case 11:
966 flag = WFLAGP(wwin, no_language_button);
967 break;
968 #endif
970 WMSetButtonSelected(panel->moreChk[i], flag);
972 if (panel->appFrm && wapp) {
973 for (i = 0; i < (sizeof(panel->appChk) / sizeof(panel->appChk[0])); i++) {
974 int flag = 0;
976 switch (i) {
977 case 0:
978 flag = WFLAGP(wapp->main_window_desc, start_hidden);
979 break;
980 case 1:
981 flag = WFLAGP(wapp->main_window_desc, no_appicon);
982 break;
983 case 2:
984 flag = WFLAGP(wapp->main_window_desc, shared_appicon);
985 break;
987 WMSetButtonSelected(panel->appChk[i], flag);
990 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
992 showIconFor(WMWidgetScreen(panel->alwChk), panel, wm_instance, wm_class, REVERT_TO_DEFAULT);
994 n = wDefaultGetStartWorkspace(wwin->screen_ptr, wm_instance, wm_class);
996 if (n >= 0 && n < wwin->screen_ptr->workspace_count) {
997 WMSetPopUpButtonSelectedItem(panel->wsP, n + 1);
998 } else {
999 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
1002 /* must auto apply, so that there wno't be internal
1003 * inconsistencies between the state in the flags and
1004 * the actual state of the window */
1005 applySettings(panel->applyBtn, panel);
1008 static void chooseIconCallback(WMWidget * self, void *clientData)
1010 char *file;
1011 InspectorPanel *panel = (InspectorPanel *) clientData;
1012 int result;
1014 panel->choosingIcon = 1;
1016 WMSetButtonEnabled(panel->browseIconBtn, False);
1018 result = wIconChooserDialog(panel->frame->screen_ptr, &file,
1019 panel->inspected->wm_instance, panel->inspected->wm_class);
1021 panel->choosingIcon = 0;
1023 if (!panel->destroyed) { /* kluge */
1024 if (result) {
1025 WMSetTextFieldText(panel->fileText, file);
1026 showIconFor(WMWidgetScreen(self), panel, NULL, NULL, USE_TEXT_FIELD);
1027 wfree(file);
1029 WMSetButtonEnabled(panel->browseIconBtn, True);
1030 } else {
1031 freeInspector(panel);
1035 static void textEditedObserver(void *observerData, WMNotification * notification)
1037 InspectorPanel *panel = (InspectorPanel *) observerData;
1039 if ((long)WMGetNotificationClientData(notification) != WMReturnTextMovement)
1040 return;
1042 showIconFor(WMWidgetScreen(panel->win), panel, NULL, NULL, USE_TEXT_FIELD);
1044 WMPerformButtonClick(panel->updateIconBtn);
1048 static void selectSpecification(WMWidget * bPtr, void *data)
1050 InspectorPanel *panel = (InspectorPanel *) data;
1051 char *str;
1052 WWindow *wwin = panel->inspected;
1053 int len;
1055 if (bPtr == panel->defaultRb && (wwin->wm_instance || wwin->wm_class))
1056 WMSetButtonEnabled(panel->applyBtn, False);
1057 else
1058 WMSetButtonEnabled(panel->applyBtn, True);
1060 len = 16 + strlen(wwin->wm_instance ? wwin->wm_instance : "?")
1061 + strlen(wwin->wm_class ? wwin->wm_class : "?");
1063 str = wmalloc(len);
1065 snprintf(str, len, _("Inspecting %s.%s"),
1066 wwin->wm_instance ? wwin->wm_instance : "?", wwin->wm_class ? wwin->wm_class : "?");
1068 wFrameWindowChangeTitle(panel->frame->frame, str);
1070 wfree(str);
1073 static void selectWindow(WMWidget * bPtr, void *data)
1075 InspectorPanel *panel = (InspectorPanel *) data;
1076 WWindow *wwin = panel->inspected;
1077 WScreen *scr = wwin->screen_ptr;
1078 XEvent event;
1079 WWindow *iwin;
1081 if (XGrabPointer(dpy, scr->root_win, True,
1082 ButtonPressMask, GrabModeAsync, GrabModeAsync, None,
1083 wCursor[WCUR_SELECT], CurrentTime) != GrabSuccess) {
1084 wwarning("could not grab mouse pointer");
1085 return;
1088 WMSetLabelText(panel->specLbl, _("Click in the window you wish to inspect."));
1090 WMMaskEvent(dpy, ButtonPressMask, &event);
1092 XUngrabPointer(dpy, CurrentTime);
1094 iwin = wWindowFor(event.xbutton.subwindow);
1096 if (iwin && !iwin->flags.internal_window && iwin != wwin && !iwin->flags.inspector_open) {
1098 iwin->flags.inspector_open = 1;
1099 iwin->inspector = createInspectorForWindow(iwin,
1100 panel->frame->frame_x, panel->frame->frame_y, True);
1101 wCloseInspectorForWindow(wwin);
1102 } else {
1103 WMSetLabelText(panel->specLbl, spec_text);
1107 static InspectorPanel *createInspectorForWindow(WWindow * wwin, int xpos, int ypos, Bool showSelectPanel)
1109 WScreen *scr = wwin->screen_ptr;
1110 InspectorPanel *panel;
1111 Window parent;
1112 int i;
1113 int x, y;
1114 int btn_width, frame_width;
1115 WMButton *selectedBtn = NULL;
1116 #ifdef wrong_behaviour
1117 WMPixmap *pixmap;
1118 #endif
1120 spec_text = _("The configuration will apply to all\n"
1121 "windows that have their WM_CLASS\n"
1122 "property set to the above selected\n" "name, when saved.");
1124 panel = wmalloc(sizeof(InspectorPanel));
1125 memset(panel, 0, sizeof(InspectorPanel));
1127 panel->destroyed = 0;
1129 panel->inspected = wwin;
1131 panel->nextPtr = panelList;
1132 panelList = panel;
1134 panel->win = WMCreateWindow(scr->wmscreen, "windowInspector");
1135 WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
1137 /**** create common stuff ****/
1139 /* command buttons */
1140 /* (PWIDTH - (left and right margin) - (btn interval)) / 3 */
1141 btn_width = (PWIDTH - (2 * 15) - (2 * 10)) / 3;
1142 panel->saveBtn = WMCreateCommandButton(panel->win);
1143 WMSetButtonAction(panel->saveBtn, (WMAction *) saveSettings, panel);
1144 WMMoveWidget(panel->saveBtn, (2 * (btn_width + 10)) + 15, PHEIGHT - 40);
1145 WMSetButtonText(panel->saveBtn, _("Save"));
1146 WMResizeWidget(panel->saveBtn, btn_width, 28);
1147 if (wPreferences.flags.noupdates || !(wwin->wm_class || wwin->wm_instance))
1148 WMSetButtonEnabled(panel->saveBtn, False);
1150 panel->applyBtn = WMCreateCommandButton(panel->win);
1151 WMSetButtonAction(panel->applyBtn, (WMAction *) applySettings, panel);
1152 WMMoveWidget(panel->applyBtn, btn_width + 10 + 15, PHEIGHT - 40);
1153 WMSetButtonText(panel->applyBtn, _("Apply"));
1154 WMResizeWidget(panel->applyBtn, btn_width, 28);
1156 panel->revertBtn = WMCreateCommandButton(panel->win);
1157 WMSetButtonAction(panel->revertBtn, (WMAction *) revertSettings, panel);
1158 WMMoveWidget(panel->revertBtn, 15, PHEIGHT - 40);
1159 WMSetButtonText(panel->revertBtn, _("Reload"));
1160 WMResizeWidget(panel->revertBtn, btn_width, 28);
1162 /* page selection popup button */
1163 panel->pagePopUp = WMCreatePopUpButton(panel->win);
1164 WMSetPopUpButtonAction(panel->pagePopUp, (WMAction *) changePage, panel);
1165 WMMoveWidget(panel->pagePopUp, 25, 15);
1166 WMResizeWidget(panel->pagePopUp, PWIDTH - 50, 20);
1168 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Specification"));
1169 WMAddPopUpButtonItem(panel->pagePopUp, _("Window Attributes"));
1170 WMAddPopUpButtonItem(panel->pagePopUp, _("Advanced Options"));
1171 WMAddPopUpButtonItem(panel->pagePopUp, _("Icon and Initial Workspace"));
1172 WMAddPopUpButtonItem(panel->pagePopUp, _("Application Specific"));
1174 /**** window spec ****/
1175 frame_width = PWIDTH - (2 * 15);
1177 panel->specFrm = WMCreateFrame(panel->win);
1178 WMSetFrameTitle(panel->specFrm, _("Window Specification"));
1179 WMMoveWidget(panel->specFrm, 15, 65);
1180 WMResizeWidget(panel->specFrm, frame_width, 145);
1182 panel->defaultRb = WMCreateRadioButton(panel->specFrm);
1183 WMMoveWidget(panel->defaultRb, 10, 78);
1184 WMResizeWidget(panel->defaultRb, frame_width - (2 * 10), 20);
1185 WMSetButtonText(panel->defaultRb, _("Defaults for all windows"));
1186 WMSetButtonSelected(panel->defaultRb, False);
1187 WMSetButtonAction(panel->defaultRb, selectSpecification, panel);
1189 if (wwin->wm_class && wwin->wm_instance) {
1190 char *str, *tmp;
1192 tmp = wstrconcat(wwin->wm_instance, ".");
1193 str = wstrconcat(tmp, wwin->wm_class);
1195 panel->bothRb = WMCreateRadioButton(panel->specFrm);
1196 WMMoveWidget(panel->bothRb, 10, 18);
1197 WMResizeWidget(panel->bothRb, frame_width - (2 * 10), 20);
1198 WMSetButtonText(panel->bothRb, str);
1199 wfree(tmp);
1200 wfree(str);
1201 WMGroupButtons(panel->defaultRb, panel->bothRb);
1203 if (!selectedBtn)
1204 selectedBtn = panel->bothRb;
1206 WMSetButtonAction(panel->bothRb, selectSpecification, panel);
1209 if (wwin->wm_instance) {
1210 panel->instRb = WMCreateRadioButton(panel->specFrm);
1211 WMMoveWidget(panel->instRb, 10, 38);
1212 WMResizeWidget(panel->instRb, frame_width - (2 * 10), 20);
1213 WMSetButtonText(panel->instRb, wwin->wm_instance);
1214 WMGroupButtons(panel->defaultRb, panel->instRb);
1216 if (!selectedBtn)
1217 selectedBtn = panel->instRb;
1219 WMSetButtonAction(panel->instRb, selectSpecification, panel);
1222 if (wwin->wm_class) {
1223 panel->clsRb = WMCreateRadioButton(panel->specFrm);
1224 WMMoveWidget(panel->clsRb, 10, 58);
1225 WMResizeWidget(panel->clsRb, frame_width - (2 * 10), 20);
1226 WMSetButtonText(panel->clsRb, wwin->wm_class);
1227 WMGroupButtons(panel->defaultRb, panel->clsRb);
1229 if (!selectedBtn)
1230 selectedBtn = panel->clsRb;
1232 WMSetButtonAction(panel->clsRb, selectSpecification, panel);
1235 panel->selWinB = WMCreateCommandButton(panel->specFrm);
1236 WMMoveWidget(panel->selWinB, 20, 145 - 24 - 10);
1237 WMResizeWidget(panel->selWinB, frame_width - 2 * 10 - 20, 24);
1238 WMSetButtonText(panel->selWinB, _("Select window"));
1239 WMSetButtonAction(panel->selWinB, selectWindow, panel);
1241 panel->specLbl = WMCreateLabel(panel->win);
1242 WMMoveWidget(panel->specLbl, 15, 210);
1243 WMResizeWidget(panel->specLbl, frame_width, 100);
1244 WMSetLabelText(panel->specLbl, spec_text);
1245 WMSetLabelWraps(panel->specLbl, True);
1247 WMSetLabelTextAlignment(panel->specLbl, WALeft);
1249 /**** attributes ****/
1250 panel->attrFrm = WMCreateFrame(panel->win);
1251 WMSetFrameTitle(panel->attrFrm, _("Attributes"));
1252 WMMoveWidget(panel->attrFrm, 15, 45);
1253 WMResizeWidget(panel->attrFrm, frame_width, 250);
1255 for (i = 0; i < (sizeof(panel->attrChk) / sizeof(panel->attrChk[0])); i++) {
1256 char *caption = NULL;
1257 int flag = 0;
1258 char *descr = NULL;
1260 switch (i) {
1261 case 0:
1262 caption = _("Disable titlebar");
1263 flag = WFLAGP(wwin, no_titlebar);
1264 descr = _("Remove the titlebar of this window.\n"
1265 "To access the window commands menu of a window\n"
1266 "without it's titlebar, press Control+Esc (or the\n"
1267 "equivalent shortcut, if you changed the default\n" "settings).");
1268 break;
1269 case 1:
1270 caption = _("Disable resizebar");
1271 flag = WFLAGP(wwin, no_resizebar);
1272 descr = _("Remove the resizebar of this window.");
1273 break;
1274 case 2:
1275 caption = _("Disable close button");
1276 flag = WFLAGP(wwin, no_close_button);
1277 descr = _("Remove the `close window' button of this window.");
1278 break;
1279 case 3:
1280 caption = _("Disable miniaturize button");
1281 flag = WFLAGP(wwin, no_miniaturize_button);
1282 descr = _("Remove the `miniaturize window' button of the window.");
1283 break;
1284 case 4:
1285 caption = _("Disable border");
1286 flag = WFLAGP(wwin, no_border);
1287 descr = _("Remove the 1 pixel black border around the window.");
1288 break;
1289 case 5:
1290 caption = _("Keep on top (floating)");
1291 flag = WFLAGP(wwin, floating);
1292 descr = _("Keep the window over other windows, not allowing\n" "them to cover it.");
1293 break;
1294 case 6:
1295 caption = _("Keep at bottom (sunken)");
1296 flag = WFLAGP(wwin, sunken);
1297 descr = _("Keep the window under all other windows.");
1298 break;
1299 case 7:
1300 caption = _("Omnipresent");
1301 flag = WFLAGP(wwin, omnipresent);
1302 descr = _("Make window present in all workspaces.");
1303 break;
1304 case 8:
1305 caption = _("Start miniaturized");
1306 flag = WFLAGP(wwin, start_miniaturized);
1307 descr = _("Make the window be automatically miniaturized when it's\n" "first shown.");
1308 break;
1309 case 9:
1310 caption = _("Start maximized");
1311 flag = WFLAGP(wwin, start_maximized != 0);
1312 descr = _("Make the window be automatically maximized when it's\n" "first shown.");
1313 break;
1314 case 10:
1315 caption = _("Full screen maximization");
1316 flag = WFLAGP(wwin, full_maximize);
1317 descr = _("Make the window use the whole screen space when it's\n"
1318 "maximized. The titlebar and resizebar will be moved\n"
1319 "to outside the screen.");
1320 break;
1322 panel->attrChk[i] = WMCreateSwitchButton(panel->attrFrm);
1323 WMMoveWidget(panel->attrChk[i], 10, 20 * (i + 1));
1324 WMResizeWidget(panel->attrChk[i], frame_width - 15, 20);
1325 WMSetButtonSelected(panel->attrChk[i], flag);
1326 WMSetButtonText(panel->attrChk[i], caption);
1328 WMSetBalloonTextForView(descr, WMWidgetView(panel->attrChk[i]));
1331 /**** more attributes ****/
1332 panel->moreFrm = WMCreateFrame(panel->win);
1333 WMSetFrameTitle(panel->moreFrm, _("Advanced"));
1334 WMMoveWidget(panel->moreFrm, 15, 45);
1335 WMResizeWidget(panel->moreFrm, frame_width, 265);
1337 for (i = 0; i < (sizeof(panel->moreChk) / sizeof(panel->moreChk[0])); i++) {
1338 char *caption = NULL;
1339 int flag = 0;
1340 char *descr = NULL;
1342 switch (i) {
1343 case 0:
1344 caption = _("Do not bind keyboard shortcuts");
1345 flag = WFLAGP(wwin, no_bind_keys);
1346 descr = _("Do not bind keyboard shortcuts from Window Maker\n"
1347 "when this window is focused. This will allow the\n"
1348 "window to receive all key combinations regardless\n"
1349 "of your shortcut configuration.");
1350 break;
1351 case 1:
1352 caption = _("Do not bind mouse clicks");
1353 flag = WFLAGP(wwin, no_bind_mouse);
1354 descr = _("Do not bind mouse actions, such as `Alt'+drag\n"
1355 "in the window (when alt is the modifier you have\n" "configured).");
1356 break;
1357 case 2:
1358 caption = _("Do not show in the window list");
1359 flag = WFLAGP(wwin, skip_window_list);
1360 descr = _("Do not list the window in the window list menu.");
1361 break;
1362 case 3:
1363 caption = _("Do not show in the switch panel");
1364 flag = WFLAGP(wwin, skip_switchpanel);
1365 descr = _("Do not include in switchpanel while alternating windows.");
1366 break;
1367 case 4:
1368 caption = _("Do not let it take focus");
1369 flag = WFLAGP(wwin, no_focusable);
1370 descr = _("Do not let the window take keyboard focus when you\n" "click on it.");
1371 break;
1372 case 5:
1373 caption = _("Keep inside screen");
1374 flag = WFLAGP(wwin, dont_move_off);
1375 descr = _("Do not allow the window to move itself completely\n"
1376 "outside the screen. For bug compatibility.\n");
1377 break;
1378 case 6:
1379 caption = _("Ignore 'Hide Others'");
1380 flag = WFLAGP(wwin, no_hide_others);
1381 descr = _("Do not hide the window when issuing the\n" "`HideOthers' command.");
1382 break;
1383 case 7:
1384 caption = _("Ignore 'Save Session'");
1385 flag = WFLAGP(wwin, dont_save_session);
1386 descr = _("Do not save the associated application in the\n"
1387 "session's state, so that it won't be restarted\n"
1388 "together with other applications when Window Maker\n" "starts.");
1389 break;
1390 case 8:
1391 caption = _("Emulate application icon");
1392 flag = WFLAGP(wwin, emulate_appicon);
1393 descr = _("Make this window act as an application that provides\n"
1394 "enough information to Window Maker for a dockable\n"
1395 "application icon to be created.");
1396 break;
1397 case 9:
1398 caption = _("Focus across workspaces");
1399 flag = WFLAGP(wwin, focus_across_wksp);
1400 descr = _("Allow Window Maker to switch workspace to satisfy\n"
1401 "a focus request (annoying).");
1402 break;
1403 case 10:
1404 caption = _("Do not let it be minimized");
1405 flag = WFLAGP(wwin, no_miniaturizable);
1406 descr = _("Do not let the window of this application be\n"
1407 "minimized.\n");
1408 break;
1409 #ifdef XKB_BUTTON_HINT
1410 case 11:
1411 caption = _("Disable language button");
1412 flag = WFLAGP(wwin, no_language_button);
1413 descr = _("Remove the `toggle language' button of the window.");
1414 break;
1415 #endif
1417 panel->moreChk[i] = WMCreateSwitchButton(panel->moreFrm);
1418 WMMoveWidget(panel->moreChk[i], 10, 20 * (i + 1));
1419 WMResizeWidget(panel->moreChk[i], frame_width - 15, 20);
1420 WMSetButtonSelected(panel->moreChk[i], flag);
1421 WMSetButtonText(panel->moreChk[i], caption);
1423 WMSetBalloonTextForView(descr, WMWidgetView(panel->moreChk[i]));
1426 /* miniwindow/workspace */
1427 panel->iconFrm = WMCreateFrame(panel->win);
1428 WMMoveWidget(panel->iconFrm, 15, 50);
1429 WMResizeWidget(panel->iconFrm, PWIDTH - (2 * 15), 170);
1430 WMSetFrameTitle(panel->iconFrm, _("Miniwindow Image"));
1432 panel->iconLbl = WMCreateLabel(panel->iconFrm);
1433 WMMoveWidget(panel->iconLbl, PWIDTH - (2 * 15) - 22 - 64, 20);
1434 WMResizeWidget(panel->iconLbl, 64, 64);
1435 WMSetLabelRelief(panel->iconLbl, WRGroove);
1436 WMSetLabelImagePosition(panel->iconLbl, WIPImageOnly);
1438 panel->browseIconBtn = WMCreateCommandButton(panel->iconFrm);
1439 WMSetButtonAction(panel->browseIconBtn, chooseIconCallback, panel);
1440 WMMoveWidget(panel->browseIconBtn, 22, 32);
1441 WMResizeWidget(panel->browseIconBtn, 120, 26);
1442 WMSetButtonText(panel->browseIconBtn, _("Browse..."));
1444 #ifdef wrong_behaviour
1445 WMSetButtonImagePosition(panel->updateIconBtn, WIPRight);
1446 pixmap = WMGetSystemPixmap(scr->wmscreen, WSIReturnArrow);
1447 WMSetButtonImage(panel->updateIconBtn, pixmap);
1448 WMReleasePixmap(pixmap);
1449 pixmap = WMGetSystemPixmap(scr->wmscreen, WSIHighlightedReturnArrow);
1450 WMSetButtonAltImage(panel->updateIconBtn, pixmap);
1451 WMReleasePixmap(pixmap);
1452 #endif
1454 panel->fileLbl = WMCreateLabel(panel->iconFrm);
1455 WMMoveWidget(panel->fileLbl, 20, 85);
1456 WMResizeWidget(panel->fileLbl, PWIDTH - (2 * 15) - (2 * 20), 14);
1457 WMSetLabelText(panel->fileLbl, _("Icon filename:"));
1459 panel->fileText = WMCreateTextField(panel->iconFrm);
1460 WMMoveWidget(panel->fileText, 20, 105);
1461 WMResizeWidget(panel->fileText, PWIDTH - (2 * 20) - (2 * 15), 20);
1462 WMSetTextFieldText(panel->fileText, NULL);
1463 WMAddNotificationObserver(textEditedObserver, panel, WMTextDidEndEditingNotification, panel->fileText);
1465 panel->alwChk = WMCreateSwitchButton(panel->iconFrm);
1466 WMMoveWidget(panel->alwChk, 20, 130);
1467 WMResizeWidget(panel->alwChk, PWIDTH - (2 * 15) - (2 * 15), 30);
1468 WMSetButtonText(panel->alwChk, _("Ignore client supplied icon"));
1469 WMSetButtonSelected(panel->alwChk, WFLAGP(wwin, always_user_icon));
1471 panel->wsFrm = WMCreateFrame(panel->win);
1472 WMMoveWidget(panel->wsFrm, 15, 225);
1473 WMResizeWidget(panel->wsFrm, PWIDTH - (2 * 15), 70);
1474 WMSetFrameTitle(panel->wsFrm, _("Initial Workspace"));
1476 WMSetBalloonTextForView(_("The workspace to place the window when it's"
1477 "first shown."), WMWidgetView(panel->wsFrm));
1479 panel->wsP = WMCreatePopUpButton(panel->wsFrm);
1480 WMMoveWidget(panel->wsP, 20, 30);
1481 WMResizeWidget(panel->wsP, PWIDTH - (2 * 15) - (2 * 20), 20);
1482 WMAddPopUpButtonItem(panel->wsP, _("Nowhere in particular"));
1483 for (i = 0; i < wwin->screen_ptr->workspace_count; i++) {
1484 WMAddPopUpButtonItem(panel->wsP, scr->workspaces[i]->name);
1487 i = wDefaultGetStartWorkspace(wwin->screen_ptr, wwin->wm_instance, wwin->wm_class);
1488 if (i >= 0 && i <= wwin->screen_ptr->workspace_count) {
1489 WMSetPopUpButtonSelectedItem(panel->wsP, i + 1);
1490 } else {
1491 WMSetPopUpButtonSelectedItem(panel->wsP, 0);
1494 /* application wide attributes */
1495 if (wwin->main_window != None) {
1496 WApplication *wapp = wApplicationOf(wwin->main_window);
1498 panel->appFrm = WMCreateFrame(panel->win);
1499 WMSetFrameTitle(panel->appFrm, _("Application Attributes"));
1500 WMMoveWidget(panel->appFrm, 15, 50);
1501 WMResizeWidget(panel->appFrm, frame_width, 240);
1503 for (i = 0; i < (sizeof(panel->appChk) / sizeof(panel->appChk[0])); i++) {
1504 char *caption = NULL;
1505 int flag = 0;
1506 char *descr = NULL;
1508 switch (i) {
1509 case 0:
1510 caption = _("Start hidden");
1511 flag = WFLAGP(wapp->main_window_desc, start_hidden);
1512 descr = _("Automatically hide application when it's started.");
1513 break;
1514 case 1:
1515 caption = _("No application icon");
1516 flag = WFLAGP(wapp->main_window_desc, no_appicon);
1517 descr = _("Disable the application icon for the application.\n"
1518 "Note that you won't be able to dock it anymore,\n"
1519 "and any icons that are already docked will stop\n"
1520 "working correctly.");
1521 break;
1522 case 2:
1523 caption = _("Shared application icon");
1524 flag = WFLAGP(wapp->main_window_desc, shared_appicon);
1525 descr = _("Use a single shared application icon for all of\n"
1526 "the instances of this application.\n");
1527 break;
1529 panel->appChk[i] = WMCreateSwitchButton(panel->appFrm);
1530 WMMoveWidget(panel->appChk[i], 10, 20 * (i + 1));
1531 WMResizeWidget(panel->appChk[i], 205, 20);
1532 WMSetButtonSelected(panel->appChk[i], flag);
1533 WMSetButtonText(panel->appChk[i], caption);
1535 WMSetBalloonTextForView(descr, WMWidgetView(panel->appChk[i]));
1538 if (WFLAGP(wwin, emulate_appicon)) {
1539 WMSetButtonEnabled(panel->appChk[1], False);
1540 WMSetButtonEnabled(panel->moreChk[7], True);
1541 } else {
1542 WMSetButtonEnabled(panel->appChk[1], True);
1543 WMSetButtonEnabled(panel->moreChk[7], False);
1545 } else {
1546 int tmp;
1548 if ((wwin->transient_for != None && wwin->transient_for != scr->root_win)
1549 || !wwin->wm_class || !wwin->wm_instance)
1550 tmp = False;
1551 else
1552 tmp = True;
1553 WMSetButtonEnabled(panel->moreChk[7], tmp);
1555 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 4, False);
1556 panel->appFrm = NULL;
1559 /* if the window is a transient, don't let it have a miniaturize
1560 * button */
1561 if (wwin->transient_for != None && wwin->transient_for != scr->root_win)
1562 WMSetButtonEnabled(panel->attrChk[3], False);
1563 else
1564 WMSetButtonEnabled(panel->attrChk[3], True);
1566 if (!wwin->wm_class && !wwin->wm_instance) {
1567 WMSetPopUpButtonItemEnabled(panel->pagePopUp, 0, False);
1570 WMRealizeWidget(panel->win);
1572 WMMapSubwidgets(panel->win);
1573 WMMapSubwidgets(panel->specFrm);
1574 WMMapSubwidgets(panel->attrFrm);
1575 WMMapSubwidgets(panel->moreFrm);
1576 WMMapSubwidgets(panel->iconFrm);
1577 WMMapSubwidgets(panel->wsFrm);
1578 if (panel->appFrm)
1579 WMMapSubwidgets(panel->appFrm);
1581 if (showSelectPanel) {
1582 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 0);
1583 changePage(panel->pagePopUp, panel);
1584 } else {
1585 WMSetPopUpButtonSelectedItem(panel->pagePopUp, 1);
1586 changePage(panel->pagePopUp, panel);
1589 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, PWIDTH, PHEIGHT, 0, 0, 0);
1590 XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
1591 panel->parent = parent;
1592 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1594 WMMapWidget(panel->win);
1596 XSetTransientForHint(dpy, parent, wwin->client_win);
1598 if (xpos == UNDEFINED_POS) {
1599 x = wwin->frame_x + wwin->frame->core->width / 2;
1600 y = wwin->frame_y + wwin->frame->top_width * 2;
1601 if (y + PHEIGHT > scr->scr_height)
1602 y = scr->scr_height - PHEIGHT - 30;
1603 if (x + PWIDTH > scr->scr_width)
1604 x = scr->scr_width - PWIDTH;
1605 } else {
1606 x = xpos;
1607 y = ypos;
1610 panel->frame = wManageInternalWindow(scr, parent, wwin->client_win, "Inspector", x, y, PWIDTH, PHEIGHT);
1612 if (!selectedBtn)
1613 selectedBtn = panel->defaultRb;
1615 WMSetButtonSelected(selectedBtn, True);
1617 selectSpecification(selectedBtn, panel);
1619 /* kluge to know who should get the key events */
1620 panel->frame->client_leader = WMWidgetXID(panel->win);
1622 WSETUFLAG(panel->frame, no_closable, 0);
1623 WSETUFLAG(panel->frame, no_close_button, 0);
1624 wWindowUpdateButtonImages(panel->frame);
1625 wFrameWindowShowButton(panel->frame->frame, WFF_RIGHT_BUTTON);
1626 panel->frame->frame->on_click_right = destroyInspector;
1628 wWindowMap(panel->frame);
1630 showIconFor(WMWidgetScreen(panel->alwChk), panel, wwin->wm_instance, wwin->wm_class, UPDATE_TEXT_FIELD);
1632 return panel;
1635 void wShowInspectorForWindow(WWindow * wwin)
1637 if (wwin->flags.inspector_open)
1638 return;
1640 WMSetBalloonEnabled(wwin->screen_ptr->wmscreen, wPreferences.help_balloon);
1642 make_keys();
1643 wwin->flags.inspector_open = 1;
1644 wwin->inspector = createInspectorForWindow(wwin, UNDEFINED_POS, UNDEFINED_POS, False);
1647 void wHideInspectorForWindow(WWindow * wwin)
1649 WWindow *pwin = wwin->inspector->frame;
1651 wWindowUnmap(pwin);
1652 pwin->flags.hidden = 1;
1654 wClientSetState(pwin, IconicState, None);
1657 void wUnhideInspectorForWindow(WWindow * wwin)
1659 WWindow *pwin = wwin->inspector->frame;
1661 pwin->flags.hidden = 0;
1662 pwin->flags.mapped = 1;
1663 XMapWindow(dpy, pwin->client_win);
1664 XMapWindow(dpy, pwin->frame->core->window);
1665 wClientSetState(pwin, NormalState, None);
1668 WWindow *wGetWindowOfInspectorForWindow(WWindow * wwin)
1670 if (wwin->inspector) {
1671 assert(wwin->flags.inspector_open != 0);
1673 return wwin->inspector->frame;
1674 } else
1675 return NULL;
1678 void wCloseInspectorForWindow(WWindow * wwin)
1680 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1682 (*pwin->frame->on_click_right) (NULL, pwin, NULL);