Add history to some dialog boxes
[wmaker-crm.git] / src / dialog.c
1 /* dialog.c - dialog windows for internal use
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 <X11/keysym.h>
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <dirent.h>
37 #include <limits.h>
38
39 #ifdef HAVE_MALLOC_H
40 #include <malloc.h>
41 #endif
42
43 #include <signal.h>
44 #ifdef __FreeBSD__
45 #include <sys/signal.h>
46 #endif
47
48 #ifndef PATH_MAX
49 #define PATH_MAX DEFAULT_PATH_MAX
50 #endif
51
52 #include "WindowMaker.h"
53 #include "GNUstep.h"
54 #include "screen.h"
55 #include "dialog.h"
56 #include "funcs.h"
57 #include "stacking.h"
58 #include "framewin.h"
59 #include "window.h"
60 #include "actions.h"
61 #include "defaults.h"
62 #include "xinerama.h"
63
64 extern WPreferences wPreferences;
65
66 static WMPoint getCenter(WScreen * scr, int width, int height)
67 {
68         return wGetPointToCenterRectInHead(scr, wGetHeadForPointerLocation(scr), width, height);
69 }
70
71 int wMessageDialog(WScreen * scr, char *title, char *message, char *defBtn, char *altBtn, char *othBtn)
72 {
73         WMAlertPanel *panel;
74         Window parent;
75         WWindow *wwin;
76         int result;
77         WMPoint center;
78
79         panel = WMCreateAlertPanel(scr->wmscreen, NULL, title, message, defBtn, altBtn, othBtn);
80
81         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 400, 180, 0, 0, 0);
82
83         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
84
85         center = getCenter(scr, 400, 180);
86         wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, 400, 180);
87         wwin->client_leader = WMWidgetXID(panel->win);
88
89         WMMapWidget(panel->win);
90
91         wWindowMap(wwin);
92
93         WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
94
95         result = panel->result;
96
97         WMUnmapWidget(panel->win);
98
99         wUnmanageWindow(wwin, False, False);
100
101         WMDestroyAlertPanel(panel);
102
103         XDestroyWindow(dpy, parent);
104
105         return result;
106 }
107
108 void toggleSaveSession(WMWidget * w, void *data)
109 {
110         wPreferences.save_session_on_exit = WMGetButtonSelected((WMButton *) w);
111 }
112
113 int wExitDialog(WScreen * scr, char *title, char *message, char *defBtn, char *altBtn, char *othBtn)
114 {
115         WMAlertPanel *panel;
116         WMButton *saveSessionBtn;
117         Window parent;
118         WWindow *wwin;
119         WMPoint center;
120         int result;
121
122         panel = WMCreateAlertPanel(scr->wmscreen, NULL, title, message, defBtn, altBtn, othBtn);
123
124         /* add save session button */
125         saveSessionBtn = WMCreateSwitchButton(panel->hbox);
126         WMSetButtonAction(saveSessionBtn, toggleSaveSession, NULL);
127         WMAddBoxSubview(panel->hbox, WMWidgetView(saveSessionBtn), False, True, 200, 0, 0);
128         WMSetButtonText(saveSessionBtn, _("Save workspace state"));
129         WMSetButtonSelected(saveSessionBtn, wPreferences.save_session_on_exit);
130         WMRealizeWidget(saveSessionBtn);
131         WMMapWidget(saveSessionBtn);
132
133         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 400, 180, 0, 0, 0);
134
135         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
136
137         center = getCenter(scr, 400, 180);
138         wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, 400, 180);
139
140         wwin->client_leader = WMWidgetXID(panel->win);
141
142         WMMapWidget(panel->win);
143
144         wWindowMap(wwin);
145
146         WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
147
148         result = panel->result;
149
150         WMUnmapWidget(panel->win);
151
152         wUnmanageWindow(wwin, False, False);
153
154         WMDestroyAlertPanel(panel);
155
156         XDestroyWindow(dpy, parent);
157
158         return result;
159 }
160
161 typedef struct _WMInputPanelWithHistory {
162         WMInputPanel *panel;
163         WMArray *history;
164         int histpos;
165         char *prefix;
166         char *suffix;
167         char *rest;
168         WMArray *variants;
169         int varpos;
170 } WMInputPanelWithHistory;
171
172 static char *HistoryFileName(char *name)
173 {
174         char *filename = NULL;
175
176         filename = wstrdup(wusergnusteppath());
177         filename = wstrappend(filename, "/.AppInfo/WindowMaker/History");
178         if (name && strlen(name)) {
179                 filename = wstrappend(filename, ".");
180                 filename = wstrappend(filename, name);
181         }
182         return filename;
183 }
184
185 static int matchString(void *str1, void *str2)
186 {
187         return (strcmp((char *)str1, (char *)str2) == 0 ? 1 : 0);
188 }
189
190 static WMArray *LoadHistory(char *filename, int max)
191 {
192         WMPropList *plhistory;
193         WMPropList *plitem;
194         WMArray *history;
195         int i, num;
196
197         history = WMCreateArrayWithDestructor(1, wfree);
198         WMAddToArray(history, wstrdup(""));
199
200         plhistory = WMReadPropListFromFile((char *)filename);
201
202         if (plhistory && WMIsPLArray(plhistory)) {
203                 num = WMGetPropListItemCount(plhistory);
204                 if (num > max)
205                         num = max;
206
207                 for (i = 0; i < num; ++i) {
208                         plitem = WMGetFromPLArray(plhistory, i);
209                         if (WMIsPLString(plitem) && WMFindInArray(history, matchString,
210                                                                   WMGetFromPLString(plitem)) == WANotFound)
211                                 WMAddToArray(history, WMGetFromPLString(plitem));
212                 }
213         }
214
215         return history;
216 }
217
218 static void SaveHistory(WMArray * history, char *filename)
219 {
220         int i;
221         WMPropList *plhistory;
222
223         plhistory = WMCreatePLArray(NULL);
224
225         for (i = 0; i < WMGetArrayItemCount(history); ++i)
226                 WMAddToPLArray(plhistory, WMCreatePLString(WMGetFromArray(history, i)));
227
228         WMWritePropListToFile(plhistory, (char *)filename, True);
229         WMReleasePropList(plhistory);
230 }
231
232 static int strmatch(const char *str1, const char *str2)
233 {
234         return !strcmp(str1, str2);
235 }
236
237 static int pstrcmp(const char **str1, const char **str2)
238 {
239         return strcmp(*str1, *str2);
240 }
241
242 static void
243 ScanFiles(const char *dir, const char *prefix, unsigned acceptmask, unsigned declinemask, WMArray * result)
244 {
245         int prefixlen;
246         DIR *d;
247         struct dirent *de;
248         struct stat sb;
249         char *fullfilename, *suffix;
250
251         prefixlen = strlen(prefix);
252         if ((d = opendir(dir)) != NULL) {
253                 while ((de = readdir(d)) != NULL) {
254                         if (strlen(de->d_name) > prefixlen &&
255                             !strncmp(prefix, de->d_name, prefixlen) &&
256                             strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..")) {
257                                 fullfilename = wstrconcat((char *)dir, "/");
258                                 fullfilename = wstrappend(fullfilename, de->d_name);
259
260                                 if (stat(fullfilename, &sb) == 0 &&
261                                     (sb.st_mode & acceptmask) &&
262                                     !(sb.st_mode & declinemask) &&
263                                     WMFindInArray(result, (WMMatchDataProc *) strmatch,
264                                                   de->d_name + prefixlen) == WANotFound) {
265                                         suffix = wstrdup(de->d_name + prefixlen);
266                                         WMAddToArray(result, suffix);
267                                 }
268                                 wfree(fullfilename);
269                         }
270                 }
271                 closedir(d);
272         }
273 }
274
275 static WMArray *GenerateVariants(const char *complete)
276 {
277         Bool firstWord = True;
278         WMArray *variants = NULL;
279         char *pos = NULL, *path = NULL, *tmp = NULL, *dir = NULL, *prefix = NULL;
280
281         variants = WMCreateArrayWithDestructor(0, wfree);
282
283         while (*complete == ' ')
284                 ++complete;
285
286         if ((pos = strrchr(complete, ' ')) != NULL) {
287                 complete = pos + 1;
288                 firstWord = False;
289         }
290
291         if ((pos = strrchr(complete, '/')) != NULL) {
292                 tmp = wstrndup((char *)complete, pos - complete + 1);
293                 if (*tmp == '~' && *(tmp + 1) == '/' && getenv("HOME")) {
294                         dir = wstrdup(getenv("HOME"));
295                         dir = wstrappend(dir, tmp + 1);
296                         wfree(tmp);
297                 } else {
298                         dir = tmp;
299                 }
300                 prefix = wstrdup(pos + 1);
301                 ScanFiles(dir, prefix, (unsigned)-1, 0, variants);
302                 wfree(dir);
303                 wfree(prefix);
304         } else if (*complete == '~') {
305                 WMAddToArray(variants, wstrdup("/"));
306         } else if (firstWord) {
307                 path = getenv("PATH");
308                 while (path) {
309                         pos = strchr(path, ':');
310                         if (pos) {
311                                 tmp = wstrndup(path, pos - path);
312                                 path = pos + 1;
313                         } else if (*path != '\0') {
314                                 tmp = wstrdup(path);
315                                 path = NULL;
316                         } else
317                                 break;
318                         ScanFiles(tmp, complete, S_IXOTH | S_IXGRP | S_IXUSR, S_IFDIR, variants);
319                         wfree(tmp);
320                 }
321         }
322
323         WMSortArray(variants, (WMCompareDataProc *) pstrcmp);
324         return variants;
325 }
326
327 static void handleHistoryKeyPress(XEvent * event, void *clientData)
328 {
329         char *text;
330         unsigned pos;
331         WMInputPanelWithHistory *p = (WMInputPanelWithHistory *) clientData;
332         KeySym ksym;
333
334         ksym = XLookupKeysym(&event->xkey, 0);
335
336         switch (ksym) {
337         case XK_Up:
338                 if (p->histpos < WMGetArrayItemCount(p->history) - 1) {
339                         if (p->histpos == 0)
340                                 wfree(WMReplaceInArray(p->history, 0, WMGetTextFieldText(p->panel->text)));
341                         p->histpos++;
342                         WMSetTextFieldText(p->panel->text, WMGetFromArray(p->history, p->histpos));
343                 }
344                 break;
345         case XK_Down:
346                 if (p->histpos > 0) {
347                         p->histpos--;
348                         WMSetTextFieldText(p->panel->text, WMGetFromArray(p->history, p->histpos));
349                 }
350                 break;
351         case XK_Tab:
352                 if (!p->variants) {
353                         text = WMGetTextFieldText(p->panel->text);
354                         pos = WMGetTextFieldCursorPosition(p->panel->text);
355                         p->prefix = wstrndup(text, pos);
356                         p->suffix = wstrdup(text + pos);
357                         wfree(text);
358                         p->variants = GenerateVariants(p->prefix);
359                         p->varpos = 0;
360                         if (!p->variants) {
361                                 wfree(p->prefix);
362                                 wfree(p->suffix);
363                                 p->prefix = NULL;
364                                 p->suffix = NULL;
365                         }
366                 }
367                 if (p->variants && p->prefix && p->suffix) {
368                         p->varpos++;
369                         if (p->varpos > WMGetArrayItemCount(p->variants))
370                                 p->varpos = 0;
371                         if (p->varpos > 0)
372                                 text = wstrconcat(p->prefix, WMGetFromArray(p->variants, p->varpos - 1));
373                         else
374                                 text = wstrdup(p->prefix);
375                         pos = strlen(text);
376                         text = wstrappend(text, p->suffix);
377                         WMSetTextFieldText(p->panel->text, text);
378                         WMSetTextFieldCursorPosition(p->panel->text, pos);
379                         wfree(text);
380                 }
381                 break;
382         }
383         if (ksym != XK_Tab) {
384                 if (p->prefix) {
385                         wfree(p->prefix);
386                         p->prefix = NULL;
387                 }
388                 if (p->suffix) {
389                         wfree(p->suffix);
390                         p->suffix = NULL;
391                 }
392                 if (p->variants) {
393                         WMFreeArray(p->variants);
394                         p->variants = NULL;
395                 }
396         }
397 }
398
399 int wAdvancedInputDialog(WScreen * scr, char *title, char *message, char *name, char **text)
400 {
401         WWindow *wwin;
402         Window parent;
403         char *result;
404         WMPoint center;
405         WMInputPanelWithHistory *p;
406         char *filename;
407
408         filename = HistoryFileName(name);
409         p = wmalloc(sizeof(WMInputPanelWithHistory));
410         p->panel = WMCreateInputPanel(scr->wmscreen, NULL, title, message, *text, _("OK"), _("Cancel"));
411         p->history = LoadHistory(filename, wPreferences.history_lines);
412         p->histpos = 0;
413         p->prefix = NULL;
414         p->suffix = NULL;
415         p->rest = NULL;
416         p->variants = NULL;
417         p->varpos = 0;
418         WMCreateEventHandler(WMWidgetView(p->panel->text), KeyPressMask, handleHistoryKeyPress, p);
419
420         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 320, 160, 0, 0, 0);
421         XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
422
423         XReparentWindow(dpy, WMWidgetXID(p->panel->win), parent, 0, 0);
424
425         center = getCenter(scr, 320, 160);
426         wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, 320, 160);
427
428         wwin->client_leader = WMWidgetXID(p->panel->win);
429
430         WMMapWidget(p->panel->win);
431
432         wWindowMap(wwin);
433
434         WMRunModalLoop(WMWidgetScreen(p->panel->win), WMWidgetView(p->panel->win));
435
436         if (p->panel->result == WAPRDefault) {
437                 result = WMGetTextFieldText(p->panel->text);
438                 wfree(WMReplaceInArray(p->history, 0, wstrdup(result)));
439                 SaveHistory(p->history, filename);
440         } else
441                 result = NULL;
442
443         wUnmanageWindow(wwin, False, False);
444
445         WMDestroyInputPanel(p->panel);
446         WMFreeArray(p->history);
447         wfree(p);
448         wfree(filename);
449
450         XDestroyWindow(dpy, parent);
451
452         if (result == NULL)
453                 return False;
454         else {
455                 if (*text)
456                         wfree(*text);
457                 *text = result;
458
459                 return True;
460         }
461 }
462
463 int wInputDialog(WScreen * scr, char *title, char *message, char **text)
464 {
465         WWindow *wwin;
466         Window parent;
467         WMInputPanel *panel;
468         char *result;
469         WMPoint center;
470
471         panel = WMCreateInputPanel(scr->wmscreen, NULL, title, message, *text, _("OK"), _("Cancel"));
472
473         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 320, 160, 0, 0, 0);
474         XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
475
476         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
477
478         center = getCenter(scr, 320, 160);
479         wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, 320, 160);
480
481         wwin->client_leader = WMWidgetXID(panel->win);
482
483         WMMapWidget(panel->win);
484
485         wWindowMap(wwin);
486
487         WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
488
489         if (panel->result == WAPRDefault)
490                 result = WMGetTextFieldText(panel->text);
491         else
492                 result = NULL;
493
494         wUnmanageWindow(wwin, False, False);
495
496         WMDestroyInputPanel(panel);
497
498         XDestroyWindow(dpy, parent);
499
500         if (result == NULL)
501                 return False;
502         else {
503                 if (*text)
504                         wfree(*text);
505                 *text = result;
506
507                 return True;
508         }
509 }
510
511 /*
512  *****************************************************************
513  * Icon Selection Panel
514  *****************************************************************
515  */
516
517 typedef struct IconPanel {
518
519         WScreen *scr;
520
521         WMWindow *win;
522
523         WMLabel *dirLabel;
524         WMLabel *iconLabel;
525
526         WMList *dirList;
527         WMList *iconList;
528         WMFont *normalfont;
529
530         WMButton *previewButton;
531
532         WMLabel *iconView;
533
534         WMLabel *fileLabel;
535         WMTextField *fileField;
536
537         WMButton *okButton;
538         WMButton *cancelButton;
539 #if 0
540         WMButton *chooseButton;
541 #endif
542         short done;
543         short result;
544         short preview;
545 } IconPanel;
546
547 static void listPixmaps(WScreen * scr, WMList * lPtr, char *path)
548 {
549         struct dirent *dentry;
550         DIR *dir;
551         char pbuf[PATH_MAX + 16];
552         char *apath;
553         IconPanel *panel = WMGetHangedData(lPtr);
554
555         panel->preview = False;
556
557         apath = wexpandpath(path);
558         dir = opendir(apath);
559
560         if (!dir) {
561                 char *msg;
562                 char *tmp;
563                 tmp = _("Could not open directory ");
564                 msg = wmalloc(strlen(tmp) + strlen(path) + 6);
565                 strcpy(msg, tmp);
566                 strcat(msg, path);
567
568                 wMessageDialog(scr, _("Error"), msg, _("OK"), NULL, NULL);
569                 wfree(msg);
570                 wfree(apath);
571                 return;
572         }
573
574         /* list contents in the column */
575         while ((dentry = readdir(dir))) {
576                 struct stat statb;
577
578                 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
579                         continue;
580
581                 strcpy(pbuf, apath);
582                 strcat(pbuf, "/");
583                 strcat(pbuf, dentry->d_name);
584
585                 if (stat(pbuf, &statb) < 0)
586                         continue;
587
588                 if (statb.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)
589                     && statb.st_mode & (S_IFREG | S_IFLNK)) {
590                         WMAddListItem(lPtr, dentry->d_name);
591                 }
592         }
593         WMSortListItems(lPtr);
594
595         closedir(dir);
596         wfree(apath);
597         panel->preview = True;
598 }
599
600 static void setViewedImage(IconPanel * panel, char *file)
601 {
602         WMPixmap *pixmap;
603         RColor color;
604
605         color.red = 0xae;
606         color.green = 0xaa;
607         color.blue = 0xae;
608         color.alpha = 0;
609         pixmap = WMCreateBlendedPixmapFromFile(WMWidgetScreen(panel->win), file, &color);
610         if (!pixmap) {
611                 WMSetButtonEnabled(panel->okButton, False);
612
613                 WMSetLabelText(panel->iconView, _("Could not load image file "));
614
615                 WMSetLabelImage(panel->iconView, NULL);
616         } else {
617                 WMSetButtonEnabled(panel->okButton, True);
618
619                 WMSetLabelText(panel->iconView, NULL);
620                 WMSetLabelImage(panel->iconView, pixmap);
621                 WMReleasePixmap(pixmap);
622         }
623 }
624
625 static void listCallback(void *self, void *data)
626 {
627         WMList *lPtr = (WMList *) self;
628         IconPanel *panel = (IconPanel *) data;
629         char *path;
630
631         if (lPtr == panel->dirList) {
632                 WMListItem *item = WMGetListSelectedItem(lPtr);
633
634                 if (item == NULL)
635                         return;
636                 path = item->text;
637
638                 WMSetTextFieldText(panel->fileField, path);
639
640                 WMSetLabelImage(panel->iconView, NULL);
641
642                 WMSetButtonEnabled(panel->okButton, False);
643
644                 WMClearList(panel->iconList);
645                 listPixmaps(panel->scr, panel->iconList, path);
646         } else {
647                 char *tmp, *iconFile;
648                 WMListItem *item = WMGetListSelectedItem(panel->dirList);
649
650                 if (item == NULL)
651                         return;
652                 path = item->text;
653                 tmp = wexpandpath(path);
654
655                 item = WMGetListSelectedItem(panel->iconList);
656                 if (item == NULL)
657                         return;
658                 iconFile = item->text;
659
660                 path = wmalloc(strlen(tmp) + strlen(iconFile) + 4);
661                 strcpy(path, tmp);
662                 strcat(path, "/");
663                 strcat(path, iconFile);
664                 wfree(tmp);
665                 WMSetTextFieldText(panel->fileField, path);
666                 setViewedImage(panel, path);
667                 wfree(path);
668         }
669 }
670
671 static void listIconPaths(WMList * lPtr)
672 {
673         char *paths;
674         char *path;
675
676         paths = wstrdup(wPreferences.icon_path);
677
678         path = strtok(paths, ":");
679
680         do {
681                 char *tmp;
682
683                 tmp = wexpandpath(path);
684                 /* do not sort, because the order implies the order of
685                  * directories searched */
686                 if (access(tmp, X_OK) == 0)
687                         WMAddListItem(lPtr, path);
688                 wfree(tmp);
689         } while ((path = strtok(NULL, ":")) != NULL);
690
691         wfree(paths);
692 }
693
694 static void drawIconProc(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
695 {
696         IconPanel *panel = WMGetHangedData(lPtr);
697         WScreen *scr = panel->scr;
698         GC gc = scr->draw_gc;
699         GC copygc = scr->copy_gc;
700         char *file, *dirfile;
701         WMPixmap *pixmap;
702         WMColor *back;
703         WMSize size;
704         WMScreen *wmscr = WMWidgetScreen(panel->win);
705         RColor color;
706         int x, y, width, height, len;
707
708         if (!panel->preview)
709                 return;
710
711         x = rect->pos.x;
712         y = rect->pos.y;
713         width = rect->size.width;
714         height = rect->size.height;
715
716         back = (state & WLDSSelected) ? scr->white : scr->gray;
717
718         dirfile = wexpandpath(WMGetListSelectedItem(panel->dirList)->text);
719         len = strlen(dirfile) + strlen(text) + 4;
720         file = wmalloc(len);
721         snprintf(file, len, "%s/%s", dirfile, text);
722         wfree(dirfile);
723
724         color.red = WMRedComponentOfColor(back) >> 8;
725         color.green = WMGreenComponentOfColor(back) >> 8;
726         color.blue = WMBlueComponentOfColor(back) >> 8;
727         color.alpha = WMGetColorAlpha(back) >> 8;
728
729         pixmap = WMCreateBlendedPixmapFromFile(wmscr, file, &color);
730         wfree(file);
731
732         if (!pixmap) {
733                 /*WMRemoveListItem(lPtr, index); */
734                 return;
735         }
736
737         XFillRectangle(dpy, d, WMColorGC(back), x, y, width, height);
738
739         XSetClipMask(dpy, gc, None);
740         /*XDrawRectangle(dpy, d, WMColorGC(white), x+5, y+5, width-10, 54); */
741         XDrawLine(dpy, d, WMColorGC(scr->white), x, y + height - 1, x + width, y + height - 1);
742
743         size = WMGetPixmapSize(pixmap);
744
745         XSetClipMask(dpy, copygc, WMGetPixmapMaskXID(pixmap));
746         XSetClipOrigin(dpy, copygc, x + (width - size.width) / 2, y + 2);
747         XCopyArea(dpy, WMGetPixmapXID(pixmap), d, copygc, 0, 0,
748                   size.width > 100 ? 100 : size.width, size.height > 64 ? 64 : size.height,
749                   x + (width - size.width) / 2, y + 2);
750
751         {
752                 int i, j;
753                 int fheight = WMFontHeight(panel->normalfont);
754                 int tlen = strlen(text);
755                 int twidth = WMWidthOfString(panel->normalfont, text, tlen);
756                 int ofx, ofy;
757
758                 ofx = x + (width - twidth) / 2;
759                 ofy = y + 64 - fheight;
760
761                 for (i = -1; i < 2; i++)
762                         for (j = -1; j < 2; j++)
763                                 WMDrawString(wmscr, d, scr->white, panel->normalfont,
764                                              ofx + i, ofy + j, text, tlen);
765
766                 WMDrawString(wmscr, d, scr->black, panel->normalfont, ofx, ofy, text, tlen);
767         }
768
769         WMReleasePixmap(pixmap);
770         /* I hope it is better to do not use cache / on my box it is fast nuff */
771         XFlush(dpy);
772 }
773
774 static void buttonCallback(void *self, void *clientData)
775 {
776         WMButton *bPtr = (WMButton *) self;
777         IconPanel *panel = (IconPanel *) clientData;
778
779         if (bPtr == panel->okButton) {
780                 panel->done = True;
781                 panel->result = True;
782         } else if (bPtr == panel->cancelButton) {
783                 panel->done = True;
784                 panel->result = False;
785         } else if (bPtr == panel->previewButton) {
786         /**** Previewer ****/
787                 WMSetButtonEnabled(bPtr, False);
788                 WMSetListUserDrawItemHeight(panel->iconList, 68);
789                 WMSetListUserDrawProc(panel->iconList, drawIconProc);
790                 WMRedisplayWidget(panel->iconList);
791                 /* for draw proc to access screen/gc */
792         /*** end preview ***/
793         }
794 #if 0
795         else if (bPtr == panel->chooseButton) {
796                 WMOpenPanel *op;
797
798                 op = WMCreateOpenPanel(WMWidgetScreen(bPtr));
799
800                 if (WMRunModalFilePanelForDirectory(op, NULL, "/usr/local", NULL, NULL)) {
801                         char *path;
802                         path = WMGetFilePanelFile(op);
803                         WMSetTextFieldText(panel->fileField, path);
804                         setViewedImage(panel, path);
805                         wfree(path);
806                 }
807                 WMDestroyFilePanel(op);
808         }
809 #endif
810 }
811
812 static void keyPressHandler(XEvent * event, void *data)
813 {
814         IconPanel *panel = (IconPanel *) data;
815         char buffer[32];
816         int count;
817         KeySym ksym;
818         int iidx;
819         int didx;
820         int item = 0;
821         WMList *list = NULL;
822
823         if (event->type == KeyRelease)
824                 return;
825
826         buffer[0] = 0;
827         count = XLookupString(&event->xkey, buffer, sizeof(buffer), &ksym, NULL);
828
829         iidx = WMGetListSelectedItemRow(panel->iconList);
830         didx = WMGetListSelectedItemRow(panel->dirList);
831
832         switch (ksym) {
833         case XK_Up:
834                 if (iidx > 0)
835                         item = iidx - 1;
836                 else
837                         item = iidx;
838                 list = panel->iconList;
839                 break;
840         case XK_Down:
841                 if (iidx < WMGetListNumberOfRows(panel->iconList) - 1)
842                         item = iidx + 1;
843                 else
844                         item = iidx;
845                 list = panel->iconList;
846                 break;
847         case XK_Home:
848                 item = 0;
849                 list = panel->iconList;
850                 break;
851         case XK_End:
852                 item = WMGetListNumberOfRows(panel->iconList) - 1;
853                 list = panel->iconList;
854                 break;
855         case XK_Next:
856                 if (didx < WMGetListNumberOfRows(panel->dirList) - 1)
857                         item = didx + 1;
858                 else
859                         item = didx;
860                 list = panel->dirList;
861                 break;
862         case XK_Prior:
863                 if (didx > 0)
864                         item = didx - 1;
865                 else
866                         item = 0;
867                 list = panel->dirList;
868                 break;
869         case XK_Return:
870                 WMPerformButtonClick(panel->okButton);
871                 break;
872         case XK_Escape:
873                 WMPerformButtonClick(panel->cancelButton);
874                 break;
875         }
876
877         if (list) {
878                 WMSelectListItem(list, item);
879                 WMSetListPosition(list, item - 5);
880                 listCallback(list, panel);
881         }
882 }
883
884 Bool wIconChooserDialog(WScreen * scr, char **file, char *instance, char *class)
885 {
886         WWindow *wwin;
887         Window parent;
888         IconPanel *panel;
889         WMColor *color;
890         WMFont *boldFont;
891         Bool result;
892
893         panel = wmalloc(sizeof(IconPanel));
894         memset(panel, 0, sizeof(IconPanel));
895
896         panel->scr = scr;
897
898         panel->win = WMCreateWindow(scr->wmscreen, "iconChooser");
899         WMResizeWidget(panel->win, 450, 280);
900
901         WMCreateEventHandler(WMWidgetView(panel->win), KeyPressMask | KeyReleaseMask, keyPressHandler, panel);
902
903         boldFont = WMBoldSystemFontOfSize(scr->wmscreen, 12);
904         panel->normalfont = WMSystemFontOfSize(WMWidgetScreen(panel->win), 12);
905
906         panel->dirLabel = WMCreateLabel(panel->win);
907         WMResizeWidget(panel->dirLabel, 200, 20);
908         WMMoveWidget(panel->dirLabel, 10, 7);
909         WMSetLabelText(panel->dirLabel, _("Directories"));
910         WMSetLabelFont(panel->dirLabel, boldFont);
911         WMSetLabelTextAlignment(panel->dirLabel, WACenter);
912
913         WMSetLabelRelief(panel->dirLabel, WRSunken);
914
915         panel->iconLabel = WMCreateLabel(panel->win);
916         WMResizeWidget(panel->iconLabel, 140, 20);
917         WMMoveWidget(panel->iconLabel, 215, 7);
918         WMSetLabelText(panel->iconLabel, _("Icons"));
919         WMSetLabelFont(panel->iconLabel, boldFont);
920         WMSetLabelTextAlignment(panel->iconLabel, WACenter);
921
922         WMReleaseFont(boldFont);
923
924         color = WMWhiteColor(scr->wmscreen);
925         WMSetLabelTextColor(panel->dirLabel, color);
926         WMSetLabelTextColor(panel->iconLabel, color);
927         WMReleaseColor(color);
928
929         color = WMDarkGrayColor(scr->wmscreen);
930         WMSetWidgetBackgroundColor(panel->iconLabel, color);
931         WMSetWidgetBackgroundColor(panel->dirLabel, color);
932         WMReleaseColor(color);
933
934         WMSetLabelRelief(panel->iconLabel, WRSunken);
935
936         panel->dirList = WMCreateList(panel->win);
937         WMResizeWidget(panel->dirList, 200, 170);
938         WMMoveWidget(panel->dirList, 10, 30);
939         WMSetListAction(panel->dirList, listCallback, panel);
940
941         panel->iconList = WMCreateList(panel->win);
942         WMResizeWidget(panel->iconList, 140, 170);
943         WMMoveWidget(panel->iconList, 215, 30);
944         WMSetListAction(panel->iconList, listCallback, panel);
945
946         WMHangData(panel->iconList, panel);
947
948         panel->previewButton = WMCreateCommandButton(panel->win);
949         WMResizeWidget(panel->previewButton, 75, 26);
950         WMMoveWidget(panel->previewButton, 365, 130);
951         WMSetButtonText(panel->previewButton, _("Preview"));
952         WMSetButtonAction(panel->previewButton, buttonCallback, panel);
953
954         panel->iconView = WMCreateLabel(panel->win);
955         WMResizeWidget(panel->iconView, 75, 75);
956         WMMoveWidget(panel->iconView, 365, 40);
957         WMSetLabelImagePosition(panel->iconView, WIPOverlaps);
958         WMSetLabelRelief(panel->iconView, WRSunken);
959         WMSetLabelTextAlignment(panel->iconView, WACenter);
960
961         panel->fileLabel = WMCreateLabel(panel->win);
962         WMResizeWidget(panel->fileLabel, 80, 20);
963         WMMoveWidget(panel->fileLabel, 10, 210);
964         WMSetLabelText(panel->fileLabel, _("File Name:"));
965
966         panel->fileField = WMCreateTextField(panel->win);
967         WMSetViewNextResponder(WMWidgetView(panel->fileField), WMWidgetView(panel->win));
968         WMResizeWidget(panel->fileField, 345, 20);
969         WMMoveWidget(panel->fileField, 95, 210);
970         WMSetTextFieldEditable(panel->fileField, False);
971
972         panel->okButton = WMCreateCommandButton(panel->win);
973         WMResizeWidget(panel->okButton, 80, 26);
974         WMMoveWidget(panel->okButton, 360, 240);
975         WMSetButtonText(panel->okButton, _("OK"));
976         WMSetButtonEnabled(panel->okButton, False);
977         WMSetButtonAction(panel->okButton, buttonCallback, panel);
978
979         panel->cancelButton = WMCreateCommandButton(panel->win);
980         WMResizeWidget(panel->cancelButton, 80, 26);
981         WMMoveWidget(panel->cancelButton, 270, 240);
982         WMSetButtonText(panel->cancelButton, _("Cancel"));
983         WMSetButtonAction(panel->cancelButton, buttonCallback, panel);
984 #if 0
985         panel->chooseButton = WMCreateCommandButton(panel->win);
986         WMResizeWidget(panel->chooseButton, 110, 26);
987         WMMoveWidget(panel->chooseButton, 150, 240);
988         WMSetButtonText(panel->chooseButton, _("Choose File"));
989         WMSetButtonAction(panel->chooseButton, buttonCallback, panel);
990 #endif
991         WMRealizeWidget(panel->win);
992         WMMapSubwidgets(panel->win);
993
994         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 450, 280, 0, 0, 0);
995
996         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
997
998         {
999                 char *tmp;
1000                 int len = (instance ? strlen(instance) : 0)
1001                     + (class ? strlen(class) : 0) + 32;
1002                 WMPoint center;
1003
1004                 tmp = wmalloc(len);
1005
1006                 if (tmp && (instance || class))
1007                         snprintf(tmp, len, "%s [%s.%s]", _("Icon Chooser"), instance, class);
1008                 else
1009                         strcpy(tmp, _("Icon Chooser"));
1010
1011                 center = getCenter(scr, 450, 280);
1012
1013                 wwin = wManageInternalWindow(scr, parent, None, tmp, center.x, center.y, 450, 280);
1014                 wfree(tmp);
1015         }
1016
1017         /* put icon paths in the list */
1018         listIconPaths(panel->dirList);
1019
1020         WMMapWidget(panel->win);
1021
1022         wWindowMap(wwin);
1023
1024         while (!panel->done) {
1025                 XEvent event;
1026
1027                 WMNextEvent(dpy, &event);
1028                 WMHandleEvent(&event);
1029         }
1030
1031         if (panel->result) {
1032                 char *defaultPath, *wantedPath;
1033
1034                 /* check if the file the user selected is not the one that
1035                  * would be loaded by default with the current search path */
1036                 *file = WMGetListSelectedItem(panel->iconList)->text;
1037                 if (**file == 0) {
1038                         wfree(*file);
1039                         *file = NULL;
1040                 } else {
1041                         defaultPath = FindImage(wPreferences.icon_path, *file);
1042                         wantedPath = WMGetTextFieldText(panel->fileField);
1043                         /* if the file is not the default, use full path */
1044                         if (strcmp(wantedPath, defaultPath) != 0) {
1045                                 *file = wantedPath;
1046                         } else {
1047                                 *file = wstrdup(*file);
1048                                 wfree(wantedPath);
1049                         }
1050                         wfree(defaultPath);
1051                 }
1052         } else {
1053                 *file = NULL;
1054         }
1055
1056         result = panel->result;
1057
1058         WMReleaseFont(panel->normalfont);
1059
1060         WMUnmapWidget(panel->win);
1061
1062         WMDestroyWidget(panel->win);
1063
1064         wUnmanageWindow(wwin, False, False);
1065
1066         wfree(panel);
1067
1068         XDestroyWindow(dpy, parent);
1069
1070         return result;
1071 }
1072
1073 /*
1074  ***********************************************************************
1075  * Info Panel
1076  ***********************************************************************
1077  */
1078
1079 typedef struct {
1080         WScreen *scr;
1081
1082         WWindow *wwin;
1083
1084         WMWindow *win;
1085
1086         WMLabel *logoL;
1087         WMLabel *name1L;
1088         WMFrame *lineF;
1089         WMLabel *name2L;
1090
1091         WMLabel *versionL;
1092
1093         WMLabel *infoL;
1094
1095         WMLabel *copyrL;
1096
1097 #ifdef SILLYNESS
1098         WMHandlerID timer;
1099         int cycle;
1100         RImage *icon;
1101         RImage *pic;
1102         WMPixmap *oldPix;
1103         WMFont *oldFont;
1104         char *str;
1105         int x;
1106 #endif
1107 } InfoPanel;
1108
1109 #define COPYRIGHT_TEXT  \
1110     "Copyright \xc2\xa9 1997-2006 Alfredo K. Kojima\n"\
1111     "Copyright \xc2\xa9 1998-2006 Dan Pascu"
1112
1113 static InfoPanel *thePanel = NULL;
1114
1115 static void destroyInfoPanel(WCoreWindow * foo, void *data, XEvent * event)
1116 {
1117 #ifdef SILLYNESS
1118         if (thePanel->timer) {
1119                 WMDeleteTimerHandler(thePanel->timer);
1120         }
1121         if (thePanel->oldPix) {
1122                 WMReleasePixmap(thePanel->oldPix);
1123         }
1124         if (thePanel->oldFont) {
1125                 WMReleaseFont(thePanel->oldFont);
1126         }
1127         if (thePanel->icon) {
1128                 RReleaseImage(thePanel->icon);
1129         }
1130         if (thePanel->pic) {
1131                 RReleaseImage(thePanel->pic);
1132         }
1133 #endif                          /* SILLYNESS */
1134         WMUnmapWidget(thePanel);
1135
1136         wUnmanageWindow(thePanel->wwin, False, False);
1137
1138         WMDestroyWidget(thePanel->win);
1139
1140         wfree(thePanel);
1141
1142         thePanel = NULL;
1143 }
1144
1145 #ifdef SILLYNESS
1146
1147 extern WMPixmap *DoXThing();
1148 extern Bool InitXThing();
1149
1150 static void logoPushCallback(void *data)
1151 {
1152         InfoPanel *panel = (InfoPanel *) data;
1153         char buffer[512];
1154         int i;
1155         static int oldi = 0;
1156         int len;
1157         static int jingobeu[] = {
1158                 329, 150, -1, 100, 329, 150, -1, 100, 329, 300, -1, 250,
1159                 329, 150, -1, 100, 329, 150, -1, 100, 329, 300, -1, 250,
1160                 329, 150, 392, 150, 261, 150, 293, 150, 329, 400, -1, 400, 0
1161         };
1162         static int c = 0;
1163
1164         if (panel->x) {
1165                 XKeyboardControl kc;
1166                 XKeyboardState ksave;
1167                 unsigned long mask = KBBellPitch | KBBellDuration | KBBellPercent;
1168
1169                 XGetKeyboardControl(dpy, &ksave);
1170
1171                 if (panel->x > 0) {
1172                         if (jingobeu[panel->x - 1] == 0) {
1173                                 panel->x = -1;
1174                         } else if (jingobeu[panel->x - 1] < 0) {
1175                                 panel->x++;
1176                                 c = jingobeu[panel->x - 1] / 50;
1177                                 panel->x++;
1178                         } else if (c == 0) {
1179                                 kc.bell_percent = 50;
1180                                 kc.bell_pitch = jingobeu[panel->x - 1];
1181                                 panel->x++;
1182                                 kc.bell_duration = jingobeu[panel->x - 1];
1183                                 c = jingobeu[panel->x - 1] / 50;
1184                                 panel->x++;
1185                                 XChangeKeyboardControl(dpy, mask, &kc);
1186                                 XBell(dpy, 50);
1187                                 XFlush(dpy);
1188                         } else {
1189                                 c--;
1190                         }
1191                 }
1192                 if (!(panel->cycle % 4)) {
1193                         WMPixmap *p;
1194
1195                         p = DoXThing(panel->wwin);
1196                         WMSetLabelImage(panel->logoL, p);
1197                 }
1198                 kc.bell_pitch = ksave.bell_pitch;
1199                 kc.bell_percent = ksave.bell_percent;
1200                 kc.bell_duration = ksave.bell_duration;
1201                 XChangeKeyboardControl(dpy, mask, &kc);
1202         } else if (panel->cycle < 30) {
1203                 RImage *image;
1204                 WMPixmap *pix;
1205                 RColor gray;
1206
1207                 gray.red = 0xae;
1208                 gray.green = 0xaa;
1209                 gray.blue = 0xae;
1210                 gray.alpha = 0;
1211
1212                 image = RScaleImage(panel->icon, panel->pic->width, panel->pic->height);
1213                 RCombineImagesWithOpaqueness(image, panel->pic, panel->cycle * 255 / 30);
1214                 pix = WMCreateBlendedPixmapFromRImage(panel->scr->wmscreen, image, &gray);
1215                 RReleaseImage(image);
1216                 WMSetLabelImage(panel->logoL, pix);
1217                 WMReleasePixmap(pix);
1218         }
1219
1220         /* slow down text a little */
1221         i = (int)(panel->cycle * 50.0 / 85.0) % 200;
1222
1223         if (i != oldi) {
1224                 len = strlen(panel->str);
1225
1226                 strncpy(buffer, panel->str, i < len ? i : len);
1227                 if (i >= len)
1228                         memset(&buffer[len], ' ', i - len);
1229
1230                 strncpy(buffer, panel->str, i < len ? i : len);
1231                 if (i >= len)
1232                         memset(&buffer[len], ' ', i - len);
1233                 buffer[i] = 0;
1234
1235                 WMSetLabelText(panel->versionL, buffer);
1236
1237                 XFlush(WMScreenDisplay(WMWidgetScreen(panel->versionL)));
1238
1239                 oldi = i;
1240         }
1241
1242         panel->timer = WMAddTimerHandler(50, logoPushCallback, panel);
1243         panel->cycle++;
1244 }
1245
1246 static void handleLogoPush(XEvent * event, void *data)
1247 {
1248         InfoPanel *panel = (InfoPanel *) data;
1249         static int broken = 0;
1250         static int clicks = 0;
1251         static char *pic_data[] = {
1252                 "45 45 57 1",
1253                 "       c None",
1254                 ".      c #000000",
1255                 "X      c #383C00",
1256                 "o      c #515500",
1257                 "O      c #616100",
1258                 "+      c #616900",
1259                 "@      c #696D00",
1260                 "#      c #697100",
1261                 "$      c #495100",
1262                 "%      c #202800",
1263                 "&      c #969600",
1264                 "*      c #CFCF00",
1265                 "=      c #D7DB00",
1266                 "-      c #D7D700",
1267                 ";      c #C7CB00",
1268                 ":      c #A6AA00",
1269                 ">      c #494900",
1270                 ",      c #8E8E00",
1271                 "<      c #DFE700",
1272                 "1      c #F7FF00",
1273                 "2      c #FFFF00",
1274                 "3      c #E7EB00",
1275                 "4      c #B6B600",
1276                 "5      c #595900",
1277                 "6      c #717500",
1278                 "7      c #AEB200",
1279                 "8      c #CFD300",
1280                 "9      c #E7EF00",
1281                 "0      c #EFF300",
1282                 "q      c #9EA200",
1283                 "w      c #F7FB00",
1284                 "e      c #F7F700",
1285                 "r      c #BEBE00",
1286                 "t      c #8E9200",
1287                 "y      c #EFF700",
1288                 "u      c #969A00",
1289                 "i      c #414500",
1290                 "p      c #595D00",
1291                 "a      c #E7E700",
1292                 "s      c #C7C700",
1293                 "d      c #797D00",
1294                 "f      c #BEC300",
1295                 "g      c #DFE300",
1296                 "h      c #868600",
1297                 "j      c #EFEF00",
1298                 "k      c #9E9E00",
1299                 "l      c #616500",
1300                 "z      c #DFDF00",
1301                 "x      c #868A00",
1302                 "c      c #969200",
1303                 "v      c #B6BA00",
1304                 "b      c #A6A600",
1305                 "n      c #8E8A00",
1306                 "m      c #717100",
1307                 "M      c #AEAE00",
1308                 "N      c #AEAA00",
1309                 "B      c #868200",
1310                 "               ...............               ",
1311                 "             ....XoO+@##+O$%....             ",
1312                 "           ...%X&*========-;;:o...           ",
1313                 "         ...>.>,<122222222222134@...         ",
1314                 "        ..>5678912222222222222220q%..        ",
1315                 "       ..$.&-w2222222222222222222er>..       ",
1316                 "      ..O.t31222222222222222222222y4>..      ",
1317                 "    ...O5u3222222222222222222222222yri...    ",
1318                 "    ..>p&a22222222222222222222222222wso..    ",
1319                 "   ..ids91222222222222222222222222222wfi..   ",
1320                 "  ..X.7w222222wgs-w2222222213=g0222222<hi..  ",
1321                 "  ..Xuj2222222<@X5=222222229k@l:022222y4i..  ",
1322                 "  .Xdz22222222*X%.s22222222axo%$-222222<c>.. ",
1323                 " ..o7y22222222v...r222222223hX.i82222221si.. ",
1324                 "..io*222222222&...u22222222yt..%*22222220:%. ",
1325                 "..>k02222222227...f222222222v..X=222222229t. ",
1326                 "..dz12222222220ui:y2222222223d%qw222222221g. ",
1327                 ".%vw222222222221y2222222222219*y2222222222wd.",
1328                 ".X;2222222222222222222222222222222222222222b.",
1329                 ".i*2222222222222222222222222222222222222222v.",
1330                 ".i*2222222222222222222222222222222222222222;.",
1331                 ".i*22222222222222222222222222222222222222228.",
1332                 ".>*2222222222222222222222222222222222222222=.",
1333                 ".i*22222222222222222222222222222222222222228.",
1334                 ".i*2222222222222222222222222222222222222222;.",
1335                 ".X*222222222222222222222222222222we12222222r.",
1336                 ".Xs12222222w3aw22222222222222222y8s0222222wk.",
1337                 ".Xq02222222a,na22222222222222222zm6zwy2222gi.",
1338                 "..>*22222y<:Xcj22222222222222222-o$k;;02228..",
1339                 "..i7y2220rhX.:y22222222222222222jtiXd,a220,..",
1340                 " .X@z222a,do%kj2222222222222222wMX5q;gw228%..",
1341                 " ..58222wagsh6ry222222222222221;>Of0w222y:...",
1342                 " ...:e2222218mdz22222222222222a&$vw222220@...",
1343                 " ...O-122222y:.u02222222222229q$uj222221r... ",
1344                 "  ..%&a1222223&573w2222222219NOxz122221z>... ",
1345                 "   ...t3222221-l$nr8ay1222yzbo,=12222w-5...  ",
1346                 "    ..X:022222w-k+>o,7s**s7xOn=12221<f5...   ",
1347                 "     ..o:9222221j8:&Bl>>>>ihv<12221=dX...    ",
1348                 "      ..Xb9122222109g-****;<y22221zn%...     ",
1349                 "       ..X&801222222222222222222w-h....      ",
1350                 "        ...o:=022222222222222221=lX...       ",
1351                 "          ..X@:;3w2222222222210fO...         ",
1352                 "           ...XX&v8<30000003-N@...           ",
1353                 "             .....XmnbN:q&Bo....             ",
1354                 "                 ............                "
1355         };
1356         static char *msgs[] = {
1357                 "Have a nice day!",
1358                 "Focus follow mouse users will burn in hell!!!",
1359                 "Mooo Canada!!!!",
1360                 "Hi! My name is bobby...",
1361                 "AHH! The neurotic monkeys are after me!",
1362                 "WE GET SIGNAL",
1363                 "HOW ARE YOU GENTLEMEN?",
1364                 "WHAT YOU SAY??",
1365                 "SOMEBODY SET UP US THE BOMB",
1366                 "ALL YOUR BASE ARE BELONG TO US!",
1367                 "Oh My God!!! Larry is back!",
1368                 "Alex Perez is aliveeeeeeee!!!"
1369         };
1370
1371         clicks++;
1372
1373         if (!panel->timer && !broken && clicks > 0) {
1374                 WMFont *font;
1375
1376                 panel->x = 0;
1377                 clicks = 0;
1378                 if (!panel->icon) {
1379                         panel->icon = WMGetApplicationIconImage(panel->scr->wmscreen);
1380                         if (!panel->icon) {
1381                                 broken = 1;
1382                                 return;
1383                         } else {
1384                                 RColor color;
1385
1386                                 color.red = 0xae;
1387                                 color.green = 0xaa;
1388                                 color.blue = 0xae;
1389                                 color.alpha = 0;
1390
1391                                 panel->icon = RCloneImage(panel->icon);
1392                                 RCombineImageWithColor(panel->icon, &color);
1393                         }
1394                 }
1395                 if (!panel->pic) {
1396                         panel->pic = RGetImageFromXPMData(panel->scr->rcontext, pic_data);
1397                         if (!panel->pic) {
1398                                 broken = 1;
1399                                 RReleaseImage(panel->icon);
1400                                 panel->icon = NULL;
1401                                 return;
1402                         }
1403                 }
1404
1405                 panel->str = msgs[rand() % (sizeof(msgs) / sizeof(char *))];
1406
1407                 panel->timer = WMAddTimerHandler(50, logoPushCallback, panel);
1408                 panel->cycle = 0;
1409                 panel->oldPix = WMRetainPixmap(WMGetLabelImage(panel->logoL));
1410                 /* If we don't use a fixed font, scrolling will be jumpy */
1411                 /* Alternatively we can draw text in a pixmap and scroll it smoothly */
1412                 if ((panel->oldFont = WMGetLabelFont(panel->versionL)) != NULL)
1413                         WMRetainFont(panel->oldFont);
1414                 font = WMCreateFont(WMWidgetScreen(panel->versionL),
1415                                     "Lucida Console,Courier New,monospace:pixelsize=12");
1416                 if (font) {
1417                         WMSetLabelFont(panel->versionL, font);
1418                         WMReleaseFont(font);
1419                 }
1420                 WMSetLabelText(panel->versionL, "");
1421         } else if (panel->timer) {
1422                 char version[20];
1423
1424                 panel->x = 0;
1425                 clicks = 0;
1426                 WMSetLabelImage(panel->logoL, panel->oldPix);
1427                 WMReleasePixmap(panel->oldPix);
1428                 panel->oldPix = NULL;
1429
1430                 WMDeleteTimerHandler(panel->timer);
1431                 panel->timer = NULL;
1432
1433                 WMSetLabelFont(panel->versionL, panel->oldFont);
1434                 if (panel->oldFont) {
1435                         WMReleaseFont(panel->oldFont);
1436                         panel->oldFont = NULL;
1437                 }
1438                 snprintf(version, sizeof(version), _("Version %s"), VERSION);
1439                 WMSetLabelText(panel->versionL, version);
1440                 XFlush(WMScreenDisplay(WMWidgetScreen(panel->versionL)));
1441         }
1442
1443         {
1444                 XEvent ev;
1445                 while (XCheckTypedWindowEvent(dpy, WMWidgetXID(panel->versionL), ButtonPress, &ev)) ;
1446         }
1447 }
1448 #endif                          /* SILLYNESS */
1449
1450 void wShowInfoPanel(WScreen * scr)
1451 {
1452         InfoPanel *panel;
1453         WMPixmap *logo;
1454         WMSize size;
1455         WMFont *font;
1456         char *strbuf = NULL;
1457         char buffer[256];
1458         char *name;
1459         Window parent;
1460         WWindow *wwin;
1461         char **strl;
1462         int i, width = 50, sepHeight;
1463         char *visuals[] = {
1464                 "StaticGray",
1465                 "GrayScale",
1466                 "StaticColor",
1467                 "PseudoColor",
1468                 "TrueColor",
1469                 "DirectColor"
1470         };
1471
1472         if (thePanel) {
1473                 if (thePanel->scr == scr) {
1474                         wRaiseFrame(thePanel->wwin->frame->core);
1475                         wSetFocusTo(scr, thePanel->wwin);
1476                 }
1477                 return;
1478         }
1479
1480         panel = wmalloc(sizeof(InfoPanel));
1481         memset(panel, 0, sizeof(InfoPanel));
1482
1483         panel->scr = scr;
1484
1485         panel->win = WMCreateWindow(scr->wmscreen, "info");
1486         WMResizeWidget(panel->win, 390, 230);
1487
1488         logo = WMCreateApplicationIconBlendedPixmap(scr->wmscreen, (RColor *) NULL);
1489         if (!logo) {
1490                 logo = WMRetainPixmap(WMGetApplicationIconPixmap(scr->wmscreen));
1491         }
1492         if (logo) {
1493                 size = WMGetPixmapSize(logo);
1494                 panel->logoL = WMCreateLabel(panel->win);
1495                 WMResizeWidget(panel->logoL, 64, 64);
1496                 WMMoveWidget(panel->logoL, 30, 20);
1497                 WMSetLabelImagePosition(panel->logoL, WIPImageOnly);
1498                 WMSetLabelImage(panel->logoL, logo);
1499 #ifdef SILLYNESS
1500                 WMCreateEventHandler(WMWidgetView(panel->logoL), ButtonPressMask, handleLogoPush, panel);
1501 #endif
1502                 WMReleasePixmap(logo);
1503         }
1504
1505         sepHeight = 3;
1506         panel->name1L = WMCreateLabel(panel->win);
1507         WMResizeWidget(panel->name1L, 240, 30 + 2);
1508         WMMoveWidget(panel->name1L, 100, 30 - 2 - sepHeight);
1509
1510         name = "Lucida Sans,Comic Sans MS,URW Gothic L,Trebuchet MS" ":italic:pixelsize=28:antialias=true";
1511         font = WMCreateFont(scr->wmscreen, name);
1512         strbuf = "Window Maker";
1513         if (font) {
1514                 width = WMWidthOfString(font, strbuf, strlen(strbuf));
1515                 WMSetLabelFont(panel->name1L, font);
1516                 WMReleaseFont(font);
1517         }
1518         WMSetLabelTextAlignment(panel->name1L, WACenter);
1519         WMSetLabelText(panel->name1L, strbuf);
1520
1521         panel->lineF = WMCreateFrame(panel->win);
1522         WMResizeWidget(panel->lineF, width, sepHeight);
1523         WMMoveWidget(panel->lineF, 100 + (240 - width) / 2, 60 - sepHeight);
1524         WMSetFrameRelief(panel->lineF, WRSimple);
1525         WMSetWidgetBackgroundColor(panel->lineF, scr->black);
1526
1527         panel->name2L = WMCreateLabel(panel->win);
1528         WMResizeWidget(panel->name2L, 240, 24);
1529         WMMoveWidget(panel->name2L, 100, 60);
1530         name = "URW Gothic L,Nimbus Sans L:pixelsize=16:antialias=true";
1531         font = WMCreateFont(scr->wmscreen, name);
1532         if (font) {
1533                 WMSetLabelFont(panel->name2L, font);
1534                 WMReleaseFont(font);
1535                 font = NULL;
1536         }
1537         WMSetLabelTextAlignment(panel->name2L, WACenter);
1538         WMSetLabelText(panel->name2L, _("Window Manager for X"));
1539
1540         snprintf(buffer, sizeof(buffer), _("Version %s"), VERSION);
1541         panel->versionL = WMCreateLabel(panel->win);
1542         WMResizeWidget(panel->versionL, 310, 16);
1543         WMMoveWidget(panel->versionL, 30, 95);
1544         WMSetLabelTextAlignment(panel->versionL, WARight);
1545         WMSetLabelText(panel->versionL, buffer);
1546         WMSetLabelWraps(panel->versionL, False);
1547
1548         panel->copyrL = WMCreateLabel(panel->win);
1549         WMResizeWidget(panel->copyrL, 360, 40);
1550         WMMoveWidget(panel->copyrL, 15, 185);
1551         WMSetLabelTextAlignment(panel->copyrL, WALeft);
1552         WMSetLabelText(panel->copyrL, COPYRIGHT_TEXT);
1553         font = WMSystemFontOfSize(scr->wmscreen, 11);
1554         if (font) {
1555                 WMSetLabelFont(panel->copyrL, font);
1556                 WMReleaseFont(font);
1557                 font = NULL;
1558         }
1559
1560         strbuf = NULL;
1561         snprintf(buffer, sizeof(buffer), _("Using visual 0x%x: %s %ibpp "),
1562                  (unsigned)scr->w_visual->visualid, visuals[scr->w_visual->class], scr->w_depth);
1563
1564         strbuf = wstrappend(strbuf, buffer);
1565
1566         switch (scr->w_depth) {
1567         case 15:
1568                 strbuf = wstrappend(strbuf, _("(32 thousand colors)\n"));
1569                 break;
1570         case 16:
1571                 strbuf = wstrappend(strbuf, _("(64 thousand colors)\n"));
1572                 break;
1573         case 24:
1574         case 32:
1575                 strbuf = wstrappend(strbuf, _("(16 million colors)\n"));
1576                 break;
1577         default:
1578                 snprintf(buffer, sizeof(buffer), _("(%d colors)\n"), 1 << scr->w_depth);
1579                 strbuf = wstrappend(strbuf, buffer);
1580                 break;
1581         }
1582
1583 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
1584         {
1585                 struct mallinfo ma = mallinfo();
1586                 snprintf(buffer, sizeof(buffer),
1587                          _("Total allocated memory: %i kB. Total memory in use: %i kB.\n"),
1588                          (ma.arena + ma.hblkhd) / 1024, (ma.uordblks + ma.hblkhd) / 1024);
1589
1590                 strbuf = wstrappend(strbuf, buffer);
1591         }
1592 #endif
1593
1594         strbuf = wstrappend(strbuf, _("Supported image formats: "));
1595         strl = RSupportedFileFormats();
1596         for (i = 0; strl[i] != NULL; i++) {
1597                 strbuf = wstrappend(strbuf, strl[i]);
1598                 strbuf = wstrappend(strbuf, " ");
1599         }
1600
1601         strbuf = wstrappend(strbuf, _("\nAdditional support for: "));
1602         {
1603                 char *list[9];
1604                 char buf[80];
1605                 int j = 0;
1606
1607 #ifdef NETWM_HINTS
1608                 list[j++] = "WMSPEC";
1609 #endif
1610 #ifdef MWM_HINTS
1611                 list[j++] = "MWM";
1612 #endif
1613
1614                 buf[0] = 0;
1615                 for (i = 0; i < j; i++) {
1616                         if (i > 0) {
1617                                 if (i == j - 1)
1618                                         strcat(buf, _(" and "));
1619                                 else
1620                                         strcat(buf, ", ");
1621                         }
1622                         strcat(buf, list[i]);
1623                 }
1624                 strbuf = wstrappend(strbuf, buf);
1625         }
1626
1627         if (wPreferences.no_sound) {
1628                 strbuf = wstrappend(strbuf, _("\nSound disabled"));
1629         } else {
1630                 strbuf = wstrappend(strbuf, _("\nSound enabled"));
1631         }
1632
1633 #ifdef VIRTUAL_DESKTOP
1634         if (wPreferences.vdesk_enable)
1635                 strbuf = wstrappend(strbuf, _(", VirtualDesktop enabled"));
1636         else
1637                 strbuf = wstrappend(strbuf, _(", VirtualDesktop disabled"));
1638 #endif
1639
1640 #ifdef XINERAMA
1641         strbuf = wstrappend(strbuf, _("\n"));
1642 #ifdef SOLARIS_XINERAMA
1643         strbuf = wstrappend(strbuf, _("Solaris "));
1644 #endif
1645         strbuf = wstrappend(strbuf, _("Xinerama: "));
1646         {
1647                 char tmp[128];
1648                 snprintf(tmp, sizeof(tmp) - 1, "%d heads found.", scr->xine_info.count);
1649                 strbuf = wstrappend(strbuf, tmp);
1650         }
1651 #endif
1652
1653         panel->infoL = WMCreateLabel(panel->win);
1654         WMResizeWidget(panel->infoL, 350, 75);
1655         WMMoveWidget(panel->infoL, 15, 115);
1656         WMSetLabelText(panel->infoL, strbuf);
1657         font = WMSystemFontOfSize(scr->wmscreen, 11);
1658         if (font) {
1659                 WMSetLabelFont(panel->infoL, font);
1660                 WMReleaseFont(font);
1661                 font = NULL;
1662         }
1663         wfree(strbuf);
1664
1665         WMRealizeWidget(panel->win);
1666         WMMapSubwidgets(panel->win);
1667
1668         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 382, 230, 0, 0, 0);
1669
1670         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1671
1672         WMMapWidget(panel->win);
1673
1674         {
1675                 WMPoint center = getCenter(scr, 382, 230);
1676
1677                 wwin = wManageInternalWindow(scr, parent, None, _("Info"), center.x, center.y, 382, 230);
1678         }
1679
1680         WSETUFLAG(wwin, no_closable, 0);
1681         WSETUFLAG(wwin, no_close_button, 0);
1682 #ifdef XKB_BUTTON_HINT
1683         wFrameWindowHideButton(wwin->frame, WFF_LANGUAGE_BUTTON);
1684 #endif
1685         wWindowUpdateButtonImages(wwin);
1686         wFrameWindowShowButton(wwin->frame, WFF_RIGHT_BUTTON);
1687         wwin->frame->on_click_right = destroyInfoPanel;
1688
1689         wWindowMap(wwin);
1690
1691         panel->wwin = wwin;
1692
1693         thePanel = panel;
1694 #ifdef SILLYNESS
1695         if (InitXThing(panel->scr)) {
1696                 panel->timer = WMAddTimerHandler(100, logoPushCallback, panel);
1697                 panel->cycle = 0;
1698                 panel->x = 1;
1699                 panel->str = _("Merry Christmas!");
1700                 panel->oldPix = WMRetainPixmap(WMGetLabelImage(panel->logoL));
1701         }
1702 #endif
1703 }
1704
1705 /*
1706  ***********************************************************************
1707  * Legal Panel
1708  ***********************************************************************
1709  */
1710
1711 typedef struct {
1712         WScreen *scr;
1713
1714         WWindow *wwin;
1715
1716         WMWindow *win;
1717
1718         WMLabel *licenseL;
1719 } LegalPanel;
1720
1721 static LegalPanel *legalPanel = NULL;
1722
1723 static void destroyLegalPanel(WCoreWindow * foo, void *data, XEvent * event)
1724 {
1725         WMUnmapWidget(legalPanel->win);
1726
1727         WMDestroyWidget(legalPanel->win);
1728
1729         wUnmanageWindow(legalPanel->wwin, False, False);
1730
1731         wfree(legalPanel);
1732
1733         legalPanel = NULL;
1734 }
1735
1736 void wShowLegalPanel(WScreen * scr)
1737 {
1738         LegalPanel *panel;
1739         Window parent;
1740         WWindow *wwin;
1741
1742         if (legalPanel) {
1743                 if (legalPanel->scr == scr) {
1744                         wRaiseFrame(legalPanel->wwin->frame->core);
1745                         wSetFocusTo(scr, legalPanel->wwin);
1746                 }
1747                 return;
1748         }
1749
1750         panel = wmalloc(sizeof(LegalPanel));
1751
1752         panel->scr = scr;
1753
1754         panel->win = WMCreateWindow(scr->wmscreen, "legal");
1755         WMResizeWidget(panel->win, 420, 250);
1756
1757         panel->licenseL = WMCreateLabel(panel->win);
1758         WMSetLabelWraps(panel->licenseL, True);
1759         WMResizeWidget(panel->licenseL, 400, 230);
1760         WMMoveWidget(panel->licenseL, 10, 10);
1761         WMSetLabelTextAlignment(panel->licenseL, WALeft);
1762         WMSetLabelText(panel->licenseL,
1763                        _("    Window Maker is free software; you can redistribute it and/or\n"
1764                          "modify it under the terms of the GNU General Public License as\n"
1765                          "published by the Free Software Foundation; either version 2 of the\n"
1766                          "License, or (at your option) any later version.\n\n"
1767                          "    Window Maker is distributed in the hope that it will be useful,\n"
1768                          "but WITHOUT ANY WARRANTY; without even the implied warranty\n"
1769                          "of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
1770                          "See the GNU General Public License for more details.\n\n"
1771                          "    You should have received a copy of the GNU General Public\n"
1772                          "License along with this program; if not, write to the Free Software\n"
1773                          "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n" "02111-1307, USA."));
1774         WMSetLabelRelief(panel->licenseL, WRGroove);
1775
1776         WMRealizeWidget(panel->win);
1777         WMMapSubwidgets(panel->win);
1778
1779         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 420, 250, 0, 0, 0);
1780
1781         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1782
1783         {
1784                 WMPoint center = getCenter(scr, 420, 250);
1785
1786                 wwin = wManageInternalWindow(scr, parent, None, _("Legal"), center.x, center.y, 420, 250);
1787         }
1788
1789         WSETUFLAG(wwin, no_closable, 0);
1790         WSETUFLAG(wwin, no_close_button, 0);
1791         wWindowUpdateButtonImages(wwin);
1792         wFrameWindowShowButton(wwin->frame, WFF_RIGHT_BUTTON);
1793 #ifdef XKB_BUTTON_HINT
1794         wFrameWindowHideButton(wwin->frame, WFF_LANGUAGE_BUTTON);
1795 #endif
1796         wwin->frame->on_click_right = destroyLegalPanel;
1797
1798         panel->wwin = wwin;
1799
1800         WMMapWidget(panel->win);
1801
1802         wWindowMap(wwin);
1803
1804         legalPanel = panel;
1805 }
1806
1807 /*
1808  ***********************************************************************
1809  * Crashing Dialog Panel
1810  ***********************************************************************
1811  */
1812
1813 extern WDDomain *WDWindowAttributes;
1814
1815 typedef struct _CrashPanel {
1816         WMWindow *win;          /* main window */
1817
1818         WMLabel *iconL;         /* application icon */
1819         WMLabel *nameL;         /* title of panel */
1820
1821         WMFrame *sepF;          /* separator frame */
1822
1823         WMLabel *noteL;         /* Title of note */
1824         WMLabel *note2L;        /* body of note with what happened */
1825
1826         WMFrame *whatF;         /* "what to do next" frame */
1827         WMPopUpButton *whatP;   /* action selection popup button */
1828
1829         WMButton *okB;          /* ok button */
1830
1831         Bool done;              /* if finished with this dialog */
1832         int action;             /* what to do after */
1833
1834         KeyCode retKey;
1835
1836 } CrashPanel;
1837
1838 static void handleKeyPress(XEvent * event, void *clientData)
1839 {
1840         CrashPanel *panel = (CrashPanel *) clientData;
1841
1842         if (event->xkey.keycode == panel->retKey) {
1843                 WMPerformButtonClick(panel->okB);
1844         }
1845 }
1846
1847 static void okButtonCallback(void *self, void *clientData)
1848 {
1849         CrashPanel *panel = (CrashPanel *) clientData;
1850
1851         panel->done = True;
1852 }
1853
1854 static void setCrashAction(void *self, void *clientData)
1855 {
1856         WMPopUpButton *pop = (WMPopUpButton *) self;
1857         CrashPanel *panel = (CrashPanel *) clientData;
1858
1859         panel->action = WMGetPopUpButtonSelectedItem(pop);
1860 }
1861
1862 /* Make this read the logo from a compiled in pixmap -Dan */
1863 static WMPixmap *getWindowMakerIconImage(WMScreen * scr)
1864 {
1865         WMPropList *dict, *key, *option, *value = NULL;
1866         WMPixmap *pix = NULL;
1867         char *path;
1868
1869         if (!WDWindowAttributes || !WDWindowAttributes->dictionary)
1870                 return NULL;
1871
1872         WMPLSetCaseSensitive(True);
1873
1874         key = WMCreatePLString("Logo.WMPanel");
1875         option = WMCreatePLString("Icon");
1876
1877         dict = WMGetFromPLDictionary(WDWindowAttributes->dictionary, key);
1878
1879         if (dict) {
1880                 value = WMGetFromPLDictionary(dict, option);
1881         }
1882
1883         WMReleasePropList(key);
1884         WMReleasePropList(option);
1885
1886         WMPLSetCaseSensitive(False);
1887
1888         if (value && WMIsPLString(value)) {
1889                 path = FindImage(wPreferences.icon_path, WMGetFromPLString(value));
1890
1891                 if (path) {
1892                         RColor gray;
1893
1894                         gray.red = 0xae;
1895                         gray.green = 0xaa;
1896                         gray.blue = 0xae;
1897                         gray.alpha = 0;
1898
1899                         pix = WMCreateBlendedPixmapFromFile(scr, path, &gray);
1900                         wfree(path);
1901                 }
1902         }
1903
1904         return pix;
1905 }
1906
1907 #define PWIDTH  295
1908 #define PHEIGHT 345
1909
1910 int wShowCrashingDialogPanel(int whatSig)
1911 {
1912         CrashPanel *panel;
1913         WMScreen *scr;
1914         WMFont *font;
1915         WMPixmap *logo;
1916         int screen_no, scr_width, scr_height;
1917         int action;
1918         char buf[256];
1919
1920         panel = wmalloc(sizeof(CrashPanel));
1921         memset(panel, 0, sizeof(CrashPanel));
1922
1923         screen_no = DefaultScreen(dpy);
1924         scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_no));
1925         scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_no));
1926
1927         scr = WMCreateScreen(dpy, screen_no);
1928         if (!scr) {
1929                 wsyserror(_("cannot open connection for crashing dialog panel. Aborting."));
1930                 return WMAbort;
1931         }
1932
1933         panel->retKey = XKeysymToKeycode(dpy, XK_Return);
1934
1935         panel->win = WMCreateWindow(scr, "crashingDialog");
1936         WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
1937         WMMoveWidget(panel->win, (scr_width - PWIDTH) / 2, (scr_height - PHEIGHT) / 2);
1938
1939         logo = getWindowMakerIconImage(scr);
1940         if (logo) {
1941                 panel->iconL = WMCreateLabel(panel->win);
1942                 WMResizeWidget(panel->iconL, 64, 64);
1943                 WMMoveWidget(panel->iconL, 10, 10);
1944                 WMSetLabelImagePosition(panel->iconL, WIPImageOnly);
1945                 WMSetLabelImage(panel->iconL, logo);
1946         }
1947
1948         panel->nameL = WMCreateLabel(panel->win);
1949         WMResizeWidget(panel->nameL, 200, 30);
1950         WMMoveWidget(panel->nameL, 80, 25);
1951         WMSetLabelTextAlignment(panel->nameL, WALeft);
1952         font = WMBoldSystemFontOfSize(scr, 24);
1953         WMSetLabelFont(panel->nameL, font);
1954         WMReleaseFont(font);
1955         WMSetLabelText(panel->nameL, _("Fatal error"));
1956
1957         panel->sepF = WMCreateFrame(panel->win);
1958         WMResizeWidget(panel->sepF, PWIDTH + 4, 2);
1959         WMMoveWidget(panel->sepF, -2, 80);
1960
1961         panel->noteL = WMCreateLabel(panel->win);
1962         WMResizeWidget(panel->noteL, PWIDTH - 20, 40);
1963         WMMoveWidget(panel->noteL, 10, 90);
1964         WMSetLabelTextAlignment(panel->noteL, WAJustified);
1965 #ifdef SYS_SIGLIST_DECLARED
1966         snprintf(buf, sizeof(buf), _("Window Maker received signal %i\n(%s)."), whatSig, sys_siglist[whatSig]);
1967 #else
1968         snprintf(buf, sizeof(buf), _("Window Maker received signal %i."), whatSig);
1969 #endif
1970         WMSetLabelText(panel->noteL, buf);
1971
1972         panel->note2L = WMCreateLabel(panel->win);
1973         WMResizeWidget(panel->note2L, PWIDTH - 20, 100);
1974         WMMoveWidget(panel->note2L, 10, 130);
1975         WMSetLabelTextAlignment(panel->note2L, WALeft);
1976         WMSetLabelText(panel->note2L,
1977                        _(" This fatal error occured probably due to a bug."
1978                          " Please fill the included BUGFORM and " "report it to bugs@windowmaker.info."));
1979         WMSetLabelWraps(panel->note2L, True);
1980
1981         panel->whatF = WMCreateFrame(panel->win);
1982         WMResizeWidget(panel->whatF, PWIDTH - 20, 50);
1983         WMMoveWidget(panel->whatF, 10, 240);
1984         WMSetFrameTitle(panel->whatF, _("What do you want to do now?"));
1985
1986         panel->whatP = WMCreatePopUpButton(panel->whatF);
1987         WMResizeWidget(panel->whatP, PWIDTH - 20 - 70, 20);
1988         WMMoveWidget(panel->whatP, 35, 20);
1989         WMSetPopUpButtonPullsDown(panel->whatP, False);
1990         WMSetPopUpButtonText(panel->whatP, _("Select action"));
1991         WMAddPopUpButtonItem(panel->whatP, _("Abort and leave a core file"));
1992         WMAddPopUpButtonItem(panel->whatP, _("Restart Window Maker"));
1993         WMAddPopUpButtonItem(panel->whatP, _("Start alternate window manager"));
1994         WMSetPopUpButtonAction(panel->whatP, setCrashAction, panel);
1995         WMSetPopUpButtonSelectedItem(panel->whatP, WMRestart);
1996         panel->action = WMRestart;
1997
1998         WMMapSubwidgets(panel->whatF);
1999
2000         panel->okB = WMCreateCommandButton(panel->win);
2001         WMResizeWidget(panel->okB, 80, 26);
2002         WMMoveWidget(panel->okB, 205, 309);
2003         WMSetButtonText(panel->okB, _("OK"));
2004         WMSetButtonImage(panel->okB, WMGetSystemPixmap(scr, WSIReturnArrow));
2005         WMSetButtonAltImage(panel->okB, WMGetSystemPixmap(scr, WSIHighlightedReturnArrow));
2006         WMSetButtonImagePosition(panel->okB, WIPRight);
2007         WMSetButtonAction(panel->okB, okButtonCallback, panel);
2008
2009         panel->done = 0;
2010
2011         WMCreateEventHandler(WMWidgetView(panel->win), KeyPressMask, handleKeyPress, panel);
2012
2013         WMRealizeWidget(panel->win);
2014         WMMapSubwidgets(panel->win);
2015
2016         WMMapWidget(panel->win);
2017
2018         XSetInputFocus(dpy, WMWidgetXID(panel->win), RevertToParent, CurrentTime);
2019
2020         while (!panel->done) {
2021                 XEvent event;
2022
2023                 WMNextEvent(dpy, &event);
2024                 WMHandleEvent(&event);
2025         }
2026
2027         action = panel->action;
2028
2029         WMUnmapWidget(panel->win);
2030         WMDestroyWidget(panel->win);
2031         wfree(panel);
2032
2033         return action;
2034 }
2035
2036 /*****************************************************************************
2037  *                      About GNUstep Panel
2038  *****************************************************************************/
2039
2040 static void
2041 drawGNUstepLogo(Display * dpy, Drawable d, int width, int height,
2042                 unsigned long blackPixel, unsigned long whitePixel)
2043 {
2044         GC gc;
2045         XGCValues gcv;
2046         XRectangle rects[3];
2047
2048         gcv.foreground = blackPixel;
2049         gc = XCreateGC(dpy, d, GCForeground, &gcv);
2050
2051         XFillArc(dpy, d, gc, width / 45, height / 45,
2052                  width - 2 * width / 45, height - 2 * height / 45, 0, 360 * 64);
2053
2054         rects[0].x = 0;
2055         rects[0].y = 37 * height / 45;
2056         rects[0].width = width / 3;
2057         rects[0].height = height - rects[0].y;
2058
2059         rects[1].x = rects[0].width;
2060         rects[1].y = height / 2;
2061         rects[1].width = width - 2 * width / 3;
2062         rects[1].height = height - rects[1].y;
2063
2064         rects[2].x = 2 * width / 3;
2065         rects[2].y = height - 37 * height / 45;
2066         rects[2].width = width / 3;
2067         rects[2].height = height - rects[2].y;
2068
2069         XSetClipRectangles(dpy, gc, 0, 0, rects, 3, Unsorted);
2070         XFillRectangle(dpy, d, gc, 0, 0, width, height);
2071
2072         XSetForeground(dpy, gc, whitePixel);
2073         XFillArc(dpy, d, gc, width / 45, height / 45,
2074                  width - 2 * width / 45, height - 2 * height / 45, 0, 360 * 64);
2075
2076         XFreeGC(dpy, gc);
2077 }
2078
2079 typedef struct {
2080         WScreen *scr;
2081
2082         WWindow *wwin;
2083
2084         WMWindow *win;
2085
2086         WMLabel *gstepL;
2087         WMLabel *textL;
2088 } GNUstepPanel;
2089
2090 static GNUstepPanel *gnustepPanel = NULL;
2091
2092 static void destroyGNUstepPanel(WCoreWindow * foo, void *data, XEvent * event)
2093 {
2094         WMUnmapWidget(gnustepPanel->win);
2095
2096         WMDestroyWidget(gnustepPanel->win);
2097
2098         wUnmanageWindow(gnustepPanel->wwin, False, False);
2099
2100         wfree(gnustepPanel);
2101
2102         gnustepPanel = NULL;
2103 }
2104
2105 void wShowGNUstepPanel(WScreen * scr)
2106 {
2107         GNUstepPanel *panel;
2108         Window parent;
2109         WWindow *wwin;
2110         WMPixmap *pixmap;
2111         WMColor *color;
2112
2113         if (gnustepPanel) {
2114                 if (gnustepPanel->scr == scr) {
2115                         wRaiseFrame(gnustepPanel->wwin->frame->core);
2116                         wSetFocusTo(scr, gnustepPanel->wwin);
2117                 }
2118                 return;
2119         }
2120
2121         panel = wmalloc(sizeof(GNUstepPanel));
2122
2123         panel->scr = scr;
2124
2125         panel->win = WMCreateWindow(scr->wmscreen, "About GNUstep");
2126         WMResizeWidget(panel->win, 325, 205);
2127
2128         pixmap = WMCreatePixmap(scr->wmscreen, 130, 130, WMScreenDepth(scr->wmscreen), True);
2129
2130         color = WMCreateNamedColor(scr->wmscreen, "gray50", True);
2131
2132         drawGNUstepLogo(dpy, WMGetPixmapXID(pixmap), 130, 130, WMColorPixel(color), scr->white_pixel);
2133
2134         WMReleaseColor(color);
2135
2136         XSetForeground(dpy, scr->mono_gc, 0);
2137         XFillRectangle(dpy, WMGetPixmapMaskXID(pixmap), scr->mono_gc, 0, 0, 130, 130);
2138         drawGNUstepLogo(dpy, WMGetPixmapMaskXID(pixmap), 130, 130, 1, 1);
2139
2140         panel->gstepL = WMCreateLabel(panel->win);
2141         WMResizeWidget(panel->gstepL, 285, 64);
2142         WMMoveWidget(panel->gstepL, 20, 0);
2143         WMSetLabelTextAlignment(panel->gstepL, WARight);
2144         WMSetLabelText(panel->gstepL, "GNUstep");
2145         {
2146                 WMFont *font = WMBoldSystemFontOfSize(scr->wmscreen, 24);
2147
2148                 WMSetLabelFont(panel->gstepL, font);
2149                 WMReleaseFont(font);
2150         }
2151
2152         panel->textL = WMCreateLabel(panel->win);
2153         WMResizeWidget(panel->textL, 305, 140);
2154         WMMoveWidget(panel->textL, 10, 50);
2155         WMSetLabelTextAlignment(panel->textL, WARight);
2156         WMSetLabelImagePosition(panel->textL, WIPOverlaps);
2157         WMSetLabelText(panel->textL,
2158                        _("Window Maker is part of the GNUstep project.\n"
2159                          "The GNUstep project aims to create a free\n"
2160                          "implementation of the OpenStep(tm) specification\n"
2161                          "which is a object-oriented framework for\n"
2162                          "creating advanced graphical, multi-platform\n"
2163                          "applications. Additionally, a development and\n"
2164                          "user desktop enviroment will be created on top\n"
2165                          "of the framework. For more information about\n"
2166                          "GNUstep, please visit: www.gnustep.org"));
2167         WMSetLabelImage(panel->textL, pixmap);
2168
2169         WMReleasePixmap(pixmap);
2170
2171         WMRealizeWidget(panel->win);
2172         WMMapSubwidgets(panel->win);
2173
2174         parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 325, 200, 0, 0, 0);
2175
2176         XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
2177
2178         {
2179                 WMPoint center = getCenter(scr, 325, 200);
2180
2181                 wwin = wManageInternalWindow(scr, parent, None, _("About GNUstep"), center.x, center.y, 325, 200);
2182         }
2183
2184         WSETUFLAG(wwin, no_closable, 0);
2185         WSETUFLAG(wwin, no_close_button, 0);
2186         wWindowUpdateButtonImages(wwin);
2187         wFrameWindowShowButton(wwin->frame, WFF_RIGHT_BUTTON);
2188 #ifdef XKB_BUTTON_HINT
2189         wFrameWindowHideButton(wwin->frame, WFF_LANGUAGE_BUTTON);
2190 #endif
2191         wwin->frame->on_click_right = destroyGNUstepPanel;
2192
2193         panel->wwin = wwin;
2194
2195         WMMapWidget(panel->win);
2196
2197         wWindowMap(wwin);
2198
2199         gnustepPanel = panel;
2200 }