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