Update Serbian translation from master branch
[wmaker-crm.git] / src / dialog.c
blob391dda23aedf38ca12402738f02c5e0306fbb868
1 /* dialog.c - dialog windows for internal use
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
7 * Copyright (c) 2014-2023 Window Maker Team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "wconfig.h"
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/keysym.h>
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 #include <errno.h>
39 #include <time.h>
40 #include <sys/utsname.h>
42 #ifdef HAVE_MALLOC_H
43 #include <malloc.h>
44 #endif
46 #include <signal.h>
47 #ifdef __FreeBSD__
48 #include <sys/signal.h>
49 #endif
51 #ifndef PATH_MAX
52 #define PATH_MAX DEFAULT_PATH_MAX
53 #endif
55 #include "WindowMaker.h"
56 #include "GNUstep.h"
57 #include "screen.h"
58 #include "window.h"
59 #include "dialog.h"
60 #include "misc.h"
61 #include "stacking.h"
62 #include "framewin.h"
63 #include "window.h"
64 #include "actions.h"
65 #include "xinerama.h"
68 static WMPoint getCenter(WScreen * scr, int width, int height)
70 return wGetPointToCenterRectInHead(scr, wGetHeadForPointerLocation(scr), width, height);
73 int wMessageDialog(WScreen *scr, const char *title, const char *message, const char *defBtn, const char *altBtn, const char *othBtn)
75 WMAlertPanel *panel;
76 Window parent;
77 WWindow *wwin;
78 int result;
79 WMPoint center;
80 int pwidth, pheight;
82 panel = WMCreateScaledAlertPanel(scr->wmscreen, NULL, title, message, defBtn, altBtn, othBtn);
83 pwidth = WMWidgetWidth(panel->win);
84 pheight = WMWidgetHeight(panel->win);
86 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
88 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
90 center = getCenter(scr, pwidth, pheight);
91 wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, pwidth, pheight);
92 wwin->client_leader = WMWidgetXID(panel->win);
94 WMMapWidget(panel->win);
96 wWindowMap(wwin);
98 WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
100 result = panel->result;
102 WMUnmapWidget(panel->win);
104 wUnmanageWindow(wwin, False, False);
106 WMDestroyAlertPanel(panel);
108 XDestroyWindow(dpy, parent);
110 return result;
113 static void toggleSaveSession(WMWidget *w, void *data)
115 /* Parameter not used, but tell the compiler that it is ok */
116 (void) data;
118 wPreferences.save_session_on_exit = WMGetButtonSelected((WMButton *) w);
121 int wExitDialog(WScreen *scr, const char *title, const char *message, const char *defBtn, const char *altBtn, const char *othBtn)
123 WMAlertPanel *panel;
124 WMButton *saveSessionBtn;
125 Window parent;
126 WWindow *wwin;
127 WMPoint center;
128 int result;
129 int pwidth, pheight;
131 panel = WMCreateScaledAlertPanel(scr->wmscreen, NULL, title, message, defBtn, altBtn, othBtn);
132 pwidth = WMWidgetWidth(panel->win);
133 pheight = WMWidgetHeight(panel->win);
135 /* add save session button */
136 saveSessionBtn = WMCreateSwitchButton(panel->hbox);
137 WMSetButtonAction(saveSessionBtn, toggleSaveSession, NULL);
138 WMAddBoxSubview(panel->hbox, WMWidgetView(saveSessionBtn), False, True, pwidth / 2, 0, 0);
139 WMSetButtonText(saveSessionBtn, _("Save workspace state"));
140 WMSetButtonSelected(saveSessionBtn, wPreferences.save_session_on_exit);
141 WMRealizeWidget(saveSessionBtn);
142 WMMapWidget(saveSessionBtn);
144 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
146 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
148 center = getCenter(scr, pwidth, pheight);
149 wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, pwidth, pheight);
151 wwin->client_leader = WMWidgetXID(panel->win);
153 WMMapWidget(panel->win);
155 wWindowMap(wwin);
157 WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
159 result = panel->result;
161 WMUnmapWidget(panel->win);
163 wUnmanageWindow(wwin, False, False);
165 WMDestroyAlertPanel(panel);
167 XDestroyWindow(dpy, parent);
169 return result;
172 typedef struct _WMInputPanelWithHistory {
173 WMInputPanel *panel;
174 WMArray *history;
175 int histpos;
176 char *prefix;
177 char *suffix;
178 char *rest;
179 WMArray *variants;
180 int varpos;
181 } WMInputPanelWithHistory;
183 static char *HistoryFileName(const char *name)
185 char *filename = NULL;
187 filename = getenv("XDG_STATE_HOME");
188 if (filename)
189 filename = wstrappend(wexpandpath(filename), "/" PACKAGE_TARNAME "/History");
190 else
191 filename = wstrconcat(wusergnusteppath(), "/.AppInfo/" PACKAGE_TARNAME "/History");
193 if (name && strlen(name)) {
194 filename = wstrappend(filename, ".");
195 filename = wstrappend(filename, name);
197 return filename;
200 static int strmatch(const void *str1, const void *str2)
202 return !strcmp((const char *)str1, (const char *)str2);
205 static WMArray *LoadHistory(const char *filename, int max)
207 WMPropList *plhistory;
208 WMPropList *plitem;
209 WMArray *history;
210 int i, num;
211 char *str;
213 history = WMCreateArrayWithDestructor(1, wfree);
214 WMAddToArray(history, wstrdup(""));
216 plhistory = WMReadPropListFromFile(filename);
218 if (plhistory) {
219 if (WMIsPLArray(plhistory)) {
220 num = WMGetPropListItemCount(plhistory);
222 for (i = 0; i < num; ++i) {
223 plitem = WMGetFromPLArray(plhistory, i);
224 if (WMIsPLString(plitem)) {
225 str = WMGetFromPLString(plitem);
226 if (WMFindInArray(history, strmatch, str) == WANotFound) {
228 * The string here is duplicated because it will be freed
229 * automatically when the array is deleted. This is not really
230 * great because it is already an allocated string,
231 * unfortunately we cannot re-use it because it will be freed
232 * when we discard the PL (and we don't want to waste the PL's
233 * memory either)
235 WMAddToArray(history, wstrdup(str));
236 if (--max <= 0)
237 break;
242 WMReleasePropList(plhistory);
245 return history;
248 static void SaveHistory(WMArray * history, const char *filename)
250 int i;
251 WMPropList *plhistory;
253 plhistory = WMCreatePLArray(NULL);
255 for (i = 0; i < WMGetArrayItemCount(history); ++i)
256 WMAddToPLArray(plhistory, WMCreatePLString(WMGetFromArray(history, i)));
258 WMWritePropListToFile(plhistory, filename);
259 WMReleasePropList(plhistory);
262 static int pstrcmp(const char **str1, const char **str2)
264 return strcmp(*str1, *str2);
267 static void
268 ScanFiles(const char *dir, const char *prefix, unsigned acceptmask, unsigned declinemask, WMArray * result)
270 int prefixlen;
271 DIR *d;
272 struct dirent *de;
273 struct stat sb;
274 char *fullfilename, *suffix;
276 prefixlen = strlen(prefix);
277 d = opendir(dir);
278 if (d != NULL) {
279 while ((de = readdir(d)) != NULL) {
280 if (strlen(de->d_name) > prefixlen &&
281 !strncmp(prefix, de->d_name, prefixlen) &&
282 strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..")) {
283 fullfilename = wstrconcat((char *)dir, "/");
284 fullfilename = wstrappend(fullfilename, de->d_name);
286 if (stat(fullfilename, &sb) == 0 &&
287 (sb.st_mode & acceptmask) &&
288 !(sb.st_mode & declinemask) &&
289 WMFindInArray(result, (WMMatchDataProc *) strmatch,
290 de->d_name + prefixlen) == WANotFound) {
291 suffix = wstrdup(de->d_name + prefixlen);
292 if (sb.st_mode & S_IFDIR)
293 suffix = wstrappend(suffix, "/");
294 WMAddToArray(result, suffix);
296 wfree(fullfilename);
299 closedir(d);
303 static WMArray *GenerateVariants(const char *complete)
305 Bool firstWord = True;
306 WMArray *variants = NULL;
307 char *pos = NULL, *path = NULL, *tmp = NULL, *dir = NULL, *prefix = NULL;
309 variants = WMCreateArrayWithDestructor(0, wfree);
311 while (*complete == ' ')
312 ++complete;
314 pos = strrchr(complete, ' ');
315 if (pos != NULL) {
316 complete = pos + 1;
317 firstWord = False;
320 pos = strrchr(complete, '/');
321 if (pos != NULL) {
322 tmp = wstrndup((char *)complete, pos - complete + 1);
323 if (*tmp == '~' && *(tmp + 1) == '/' && getenv("HOME")) {
324 dir = wstrdup(getenv("HOME"));
325 dir = wstrappend(dir, tmp + 1);
326 wfree(tmp);
327 } else {
328 dir = tmp;
330 prefix = wstrdup(pos + 1);
331 ScanFiles(dir, prefix, (unsigned)-1, 0, variants);
332 wfree(dir);
333 wfree(prefix);
334 } else if (*complete == '~') {
335 WMAddToArray(variants, wstrdup("/"));
336 } else if (firstWord) {
337 path = getenv("PATH");
338 while (path) {
339 pos = strchr(path, ':');
340 if (pos) {
341 tmp = wstrndup(path, pos - path);
342 path = pos + 1;
343 } else if (*path != '\0') {
344 tmp = wstrdup(path);
345 path = NULL;
346 } else
347 break;
348 ScanFiles(tmp, complete, S_IXOTH | S_IXGRP | S_IXUSR, S_IFDIR, variants);
349 wfree(tmp);
353 WMSortArray(variants, (WMCompareDataProc *) pstrcmp);
354 return variants;
357 static void handleHistoryKeyPress(XEvent * event, void *clientData)
359 char *text;
360 unsigned pos;
361 WMInputPanelWithHistory *p = (WMInputPanelWithHistory *) clientData;
362 KeySym ksym;
364 ksym = XLookupKeysym(&event->xkey, 0);
366 switch (ksym) {
367 case XK_Up:
368 if (p->histpos < WMGetArrayItemCount(p->history) - 1) {
369 if (p->histpos == 0)
370 wfree(WMReplaceInArray(p->history, 0, WMGetTextFieldText(p->panel->text)));
371 p->histpos++;
372 WMSetTextFieldText(p->panel->text, WMGetFromArray(p->history, p->histpos));
374 break;
375 case XK_Down:
376 if (p->histpos > 0) {
377 p->histpos--;
378 WMSetTextFieldText(p->panel->text, WMGetFromArray(p->history, p->histpos));
380 break;
381 case XK_Tab:
382 if (!p->variants) {
383 text = WMGetTextFieldText(p->panel->text);
384 pos = WMGetTextFieldCursorPosition(p->panel->text);
385 p->prefix = wstrndup(text, pos);
386 p->suffix = wstrdup(text + pos);
387 wfree(text);
388 p->variants = GenerateVariants(p->prefix);
389 p->varpos = 0;
390 if (!p->variants) {
391 wfree(p->prefix);
392 wfree(p->suffix);
393 p->prefix = NULL;
394 p->suffix = NULL;
397 if (p->variants && p->prefix && p->suffix) {
398 p->varpos++;
399 if (p->varpos > WMGetArrayItemCount(p->variants))
400 p->varpos = 0;
401 if (p->varpos > 0)
402 text = wstrconcat(p->prefix, WMGetFromArray(p->variants, p->varpos - 1));
403 else
404 text = wstrdup(p->prefix);
405 pos = strlen(text);
406 text = wstrappend(text, p->suffix);
407 WMSetTextFieldText(p->panel->text, text);
408 WMSetTextFieldCursorPosition(p->panel->text, pos);
409 wfree(text);
411 break;
413 if (ksym != XK_Tab) {
414 if (p->prefix) {
415 wfree(p->prefix);
416 p->prefix = NULL;
418 if (p->suffix) {
419 wfree(p->suffix);
420 p->suffix = NULL;
422 if (p->variants) {
423 WMFreeArray(p->variants);
424 p->variants = NULL;
429 int wAdvancedInputDialog(WScreen *scr, const char *title, const char *message, const char *name, char **text)
431 WWindow *wwin;
432 Window parent;
433 char *result;
434 WMPoint center;
435 WMInputPanelWithHistory *p;
436 char *filename;
437 int pwidth, pheight;
439 filename = HistoryFileName(name);
440 p = wmalloc(sizeof(WMInputPanelWithHistory));
441 p->panel = WMCreateScaledInputPanel(scr->wmscreen, NULL, title, message, *text, _("OK"), _("Cancel"));
442 p->history = LoadHistory(filename, wPreferences.history_lines);
443 p->histpos = 0;
444 p->prefix = NULL;
445 p->suffix = NULL;
446 p->rest = NULL;
447 p->variants = NULL;
448 p->varpos = 0;
449 WMCreateEventHandler(WMWidgetView(p->panel->text), KeyPressMask, handleHistoryKeyPress, p);
450 pwidth = WMWidgetWidth(p->panel->win);
451 pheight = WMWidgetHeight(p->panel->win);
453 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
454 XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
456 XReparentWindow(dpy, WMWidgetXID(p->panel->win), parent, 0, 0);
458 center = getCenter(scr, pwidth, pheight);
459 wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, pwidth, pheight);
461 wwin->client_leader = WMWidgetXID(p->panel->win);
463 WMMapWidget(p->panel->win);
465 wWindowMap(wwin);
467 WMRunModalLoop(WMWidgetScreen(p->panel->win), WMWidgetView(p->panel->win));
469 if (p->panel->result == WAPRDefault) {
470 result = WMGetTextFieldText(p->panel->text);
471 wfree(WMReplaceInArray(p->history, 0, wstrdup(result)));
472 SaveHistory(p->history, filename);
473 } else
474 result = NULL;
476 wUnmanageWindow(wwin, False, False);
478 WMDestroyInputPanel(p->panel);
479 WMFreeArray(p->history);
480 wfree(p);
481 wfree(filename);
483 XDestroyWindow(dpy, parent);
485 if (result == NULL)
486 return False;
487 else {
488 if (*text)
489 wfree(*text);
490 *text = result;
492 return True;
496 int wInputDialog(WScreen *scr, const char *title, const char *message, char **text)
498 WWindow *wwin;
499 Window parent;
500 WMInputPanel *panel;
501 char *result;
502 WMPoint center;
503 int pwidth, pheight;
505 panel = WMCreateScaledInputPanel(scr->wmscreen, NULL, title, message, *text, _("OK"), _("Cancel"));
506 pwidth = WMWidgetWidth(panel->win);
507 pheight = WMWidgetHeight(panel->win);
509 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
510 XSelectInput(dpy, parent, KeyPressMask | KeyReleaseMask);
512 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
514 center = getCenter(scr, pwidth, pheight);
515 wwin = wManageInternalWindow(scr, parent, None, NULL, center.x, center.y, pwidth, pheight);
517 wwin->client_leader = WMWidgetXID(panel->win);
519 WMMapWidget(panel->win);
521 wWindowMap(wwin);
523 WMRunModalLoop(WMWidgetScreen(panel->win), WMWidgetView(panel->win));
525 if (panel->result == WAPRDefault)
526 result = WMGetTextFieldText(panel->text);
527 else
528 result = NULL;
530 wUnmanageWindow(wwin, False, False);
532 WMDestroyInputPanel(panel);
534 XDestroyWindow(dpy, parent);
536 if (result == NULL)
537 return False;
538 else {
539 if (*text)
540 wfree(*text);
541 *text = result;
543 return True;
548 *****************************************************************
549 * Icon Selection Panel
550 *****************************************************************
553 typedef struct IconPanel {
555 WScreen *scr;
557 WMWindow *win;
559 WMLabel *dirLabel;
560 WMLabel *iconLabel;
562 WMList *dirList;
563 WMList *iconList;
564 WMFont *normalfont;
566 WMButton *previewButton;
568 WMLabel *iconView;
570 WMLabel *fileLabel;
571 WMTextField *fileField;
573 WMButton *okButton;
574 WMButton *cancelButton;
575 #if 0
576 WMButton *chooseButton;
577 #endif
578 short done;
579 short result;
580 short preview;
581 } IconPanel;
583 static void listPixmaps(WScreen *scr, WMList *lPtr, const char *path)
585 struct dirent *dentry;
586 DIR *dir;
587 char pbuf[PATH_MAX + 16];
588 char *apath;
589 IconPanel *panel = WMGetHangedData(lPtr);
591 panel->preview = False;
593 apath = wexpandpath(path);
594 dir = opendir(apath);
596 if (!dir) {
597 wfree(apath);
598 snprintf(pbuf, sizeof(pbuf),
599 _("Could not open directory \"%s\":\n%s"),
600 path, strerror(errno));
601 wMessageDialog(scr, _("Error"), pbuf, _("OK"), NULL, NULL);
602 return;
605 /* list contents in the column */
606 while ((dentry = readdir(dir))) {
607 struct stat statb;
609 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
610 continue;
612 if (wstrlcpy(pbuf, apath, sizeof(pbuf)) >= sizeof(pbuf) ||
613 wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf) ||
614 wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf)) {
615 wwarning(_("full path for file \"%s\" in \"%s\" is longer than %d bytes, skipped"),
616 dentry->d_name, path, (int) (sizeof(pbuf) - 1) );
617 continue;
620 if (stat(pbuf, &statb) < 0)
621 continue;
623 if (statb.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)
624 && statb.st_mode & (S_IFREG | S_IFLNK)) {
625 WMAddListItem(lPtr, dentry->d_name);
628 WMSortListItems(lPtr);
630 closedir(dir);
631 wfree(apath);
632 panel->preview = True;
635 static void setViewedImage(IconPanel *panel, const char *file)
637 WMPixmap *pixmap;
638 RColor color;
639 int iwidth, iheight;
641 color.red = 0xae;
642 color.green = 0xaa;
643 color.blue = 0xae;
644 color.alpha = 0;
645 iwidth = WMWidgetWidth(panel->iconView);
646 iheight = WMWidgetHeight(panel->iconView);
647 pixmap = WMCreateScaledBlendedPixmapFromFile(WMWidgetScreen(panel->win), file, &color, iwidth, iheight);
649 if (!pixmap) {
650 WMSetButtonEnabled(panel->okButton, False);
652 WMSetLabelText(panel->iconView, _("Could not load image file "));
654 WMSetLabelImage(panel->iconView, NULL);
655 } else {
656 WMSetButtonEnabled(panel->okButton, True);
658 WMSetLabelText(panel->iconView, NULL);
659 WMSetLabelImage(panel->iconView, pixmap);
660 WMReleasePixmap(pixmap);
664 static void listCallback(void *self, void *data)
666 WMList *lPtr = (WMList *) self;
667 IconPanel *panel = (IconPanel *) data;
668 char *path;
670 if (lPtr == panel->dirList) {
671 WMListItem *item = WMGetListSelectedItem(lPtr);
673 if (item == NULL)
674 return;
675 path = item->text;
677 WMSetTextFieldText(panel->fileField, path);
679 WMSetLabelImage(panel->iconView, NULL);
681 WMSetButtonEnabled(panel->okButton, False);
683 WMClearList(panel->iconList);
684 listPixmaps(panel->scr, panel->iconList, path);
685 } else {
686 char *tmp, *iconFile;
687 WMListItem *item = WMGetListSelectedItem(panel->dirList);
689 if (item == NULL)
690 return;
691 path = item->text;
693 item = WMGetListSelectedItem(panel->iconList);
694 if (item == NULL)
695 return;
696 iconFile = item->text;
698 tmp = wexpandpath(path);
699 path = wmalloc(strlen(tmp) + strlen(iconFile) + 4);
700 strcpy(path, tmp);
701 strcat(path, "/");
702 strcat(path, iconFile);
703 wfree(tmp);
704 WMSetTextFieldText(panel->fileField, path);
705 setViewedImage(panel, path);
706 wfree(path);
710 static void listIconPaths(WMList * lPtr)
712 char *paths;
713 char *path;
715 paths = wstrdup(wPreferences.icon_path);
717 path = strtok(paths, ":");
719 do {
720 char *tmp;
722 tmp = wexpandpath(path);
723 /* do not sort, because the order implies the order of
724 * directories searched */
725 if (access(tmp, X_OK) == 0)
726 WMAddListItem(lPtr, path);
727 wfree(tmp);
728 } while ((path = strtok(NULL, ":")) != NULL);
730 wfree(paths);
733 static void drawIconProc(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
735 IconPanel *panel = WMGetHangedData(lPtr);
736 WScreen *scr = panel->scr;
737 GC gc = scr->draw_gc;
738 GC copygc = scr->copy_gc;
739 char *file, *dirfile;
740 WMPixmap *pixmap;
741 WMColor *back;
742 WMSize size;
743 WMScreen *wmscr = WMWidgetScreen(panel->win);
744 RColor color;
745 int x, y, width, height, len;
747 /* Parameter not used, but tell the compiler that it is ok */
748 (void) index;
750 if (!panel->preview)
751 return;
753 x = rect->pos.x;
754 y = rect->pos.y;
755 width = rect->size.width;
756 height = rect->size.height;
758 back = (state & WLDSSelected) ? scr->white : scr->gray;
760 dirfile = wexpandpath(WMGetListSelectedItem(panel->dirList)->text);
761 len = strlen(dirfile) + strlen(text) + 4;
762 file = wmalloc(len);
763 snprintf(file, len, "%s/%s", dirfile, text);
764 wfree(dirfile);
766 color.red = WMRedComponentOfColor(back) >> 8;
767 color.green = WMGreenComponentOfColor(back) >> 8;
768 color.blue = WMBlueComponentOfColor(back) >> 8;
769 color.alpha = WMGetColorAlpha(back) >> 8;
771 pixmap = WMCreateScaledBlendedPixmapFromFile(wmscr, file, &color, width - 2, height - 2);
772 wfree(file);
774 if (!pixmap) {
775 /*WMRemoveListItem(lPtr, index); */
776 return;
779 XFillRectangle(dpy, d, WMColorGC(back), x, y, width, height);
781 XSetClipMask(dpy, gc, None);
782 /*XDrawRectangle(dpy, d, WMColorGC(white), x+5, y+5, width-10, 54); */
783 XDrawLine(dpy, d, WMColorGC(scr->white), x, y + height - 1, x + width, y + height - 1);
785 size = WMGetPixmapSize(pixmap);
787 XSetClipMask(dpy, copygc, WMGetPixmapMaskXID(pixmap));
788 XSetClipOrigin(dpy, copygc, x + (width - size.width) / 2, y + 2);
789 XCopyArea(dpy, WMGetPixmapXID(pixmap), d, copygc, 0, 0,
790 size.width > 100 ? 100 : size.width, size.height > 64 ? 64 : size.height,
791 x + (width - size.width) / 2, y + 2);
794 int i, j;
795 int fheight = WMFontHeight(panel->normalfont);
796 int tlen = strlen(text);
797 int twidth = WMWidthOfString(panel->normalfont, text, tlen);
798 int ofx, ofy;
800 ofx = x + (width - twidth) / 2;
801 ofy = y + 64 - fheight;
803 for (i = -1; i < 2; i++)
804 for (j = -1; j < 2; j++)
805 WMDrawString(wmscr, d, scr->white, panel->normalfont,
806 ofx + i, ofy + j, text, tlen);
808 WMDrawString(wmscr, d, scr->black, panel->normalfont, ofx, ofy, text, tlen);
811 WMReleasePixmap(pixmap);
812 /* I hope it is better to do not use cache / on my box it is fast nuff */
813 XFlush(dpy);
816 static void buttonCallback(void *self, void *clientData)
818 WMButton *bPtr = (WMButton *) self;
819 IconPanel *panel = (IconPanel *) clientData;
821 if (bPtr == panel->okButton) {
822 panel->done = True;
823 panel->result = True;
824 } else if (bPtr == panel->cancelButton) {
825 panel->done = True;
826 panel->result = False;
827 } else if (bPtr == panel->previewButton) {
828 /**** Previewer ****/
829 WMSetButtonEnabled(bPtr, False);
830 WMSetListUserDrawItemHeight(panel->iconList, 68);
831 WMSetListUserDrawProc(panel->iconList, drawIconProc);
832 WMRedisplayWidget(panel->iconList);
833 /* for draw proc to access screen/gc */
834 /*** end preview ***/
836 #if 0
837 else if (bPtr == panel->chooseButton) {
838 WMOpenPanel *op;
840 op = WMCreateOpenPanel(WMWidgetScreen(bPtr));
842 if (WMRunModalFilePanelForDirectory(op, NULL, "/usr/local", NULL, NULL)) {
843 char *path;
844 path = WMGetFilePanelFile(op);
845 WMSetTextFieldText(panel->fileField, path);
846 setViewedImage(panel, path);
847 wfree(path);
849 WMDestroyFilePanel(op);
851 #endif
854 static void keyPressHandler(XEvent * event, void *data)
856 IconPanel *panel = (IconPanel *) data;
857 char buffer[32];
858 KeySym ksym;
859 int iidx;
860 int didx;
861 int item = 0;
862 WMList *list = NULL;
864 if (event->type == KeyRelease)
865 return;
867 buffer[0] = 0;
868 XLookupString(&event->xkey, buffer, sizeof(buffer), &ksym, NULL);
870 iidx = WMGetListSelectedItemRow(panel->iconList);
871 didx = WMGetListSelectedItemRow(panel->dirList);
873 switch (ksym) {
874 case XK_Up:
875 if (iidx > 0)
876 item = iidx - 1;
877 else
878 item = iidx;
879 list = panel->iconList;
880 break;
881 case XK_Down:
882 if (iidx < WMGetListNumberOfRows(panel->iconList) - 1)
883 item = iidx + 1;
884 else
885 item = iidx;
886 list = panel->iconList;
887 break;
888 case XK_Home:
889 item = 0;
890 list = panel->iconList;
891 break;
892 case XK_End:
893 item = WMGetListNumberOfRows(panel->iconList) - 1;
894 list = panel->iconList;
895 break;
896 case XK_Next:
897 if (didx < WMGetListNumberOfRows(panel->dirList) - 1)
898 item = didx + 1;
899 else
900 item = didx;
901 list = panel->dirList;
902 break;
903 case XK_Prior:
904 if (didx > 0)
905 item = didx - 1;
906 else
907 item = 0;
908 list = panel->dirList;
909 break;
910 case XK_Return:
911 WMPerformButtonClick(panel->okButton);
912 break;
913 case XK_Escape:
914 WMPerformButtonClick(panel->cancelButton);
915 break;
918 if (list) {
919 WMSelectListItem(list, item);
920 WMSetListPosition(list, item - 5);
921 listCallback(list, panel);
925 Bool wIconChooserDialog(WScreen *scr, char **file, const char *instance, const char *class)
927 WWindow *wwin;
928 Window parent;
929 IconPanel *panel;
930 WMColor *color;
931 WMFont *boldFont;
932 Bool result;
933 int wmScaleWidth, wmScaleHeight;
934 int pwidth, pheight;
936 panel = wmalloc(sizeof(IconPanel));
938 panel->scr = scr;
940 panel->win = WMCreateWindow(scr->wmscreen, "iconChooser");
941 WMGetScaleBaseFromSystemFont(scr->wmscreen, &wmScaleWidth, &wmScaleHeight);
942 pwidth = WMScaleX(450);
943 pheight = WMScaleY(280);
944 WMResizeWidget(panel->win, pwidth, pheight);
946 WMCreateEventHandler(WMWidgetView(panel->win), KeyPressMask | KeyReleaseMask, keyPressHandler, panel);
948 boldFont = WMBoldSystemFontOfSize(scr->wmscreen, WMScaleY(12));
949 panel->normalfont = WMSystemFontOfSize(WMWidgetScreen(panel->win), WMScaleY(12));
951 panel->dirLabel = WMCreateLabel(panel->win);
952 WMResizeWidget(panel->dirLabel, WMScaleX(200), WMScaleY(20));
953 WMMoveWidget(panel->dirLabel, WMScaleX(10), WMScaleY(7));
954 WMSetLabelText(panel->dirLabel, _("Directories"));
955 WMSetLabelFont(panel->dirLabel, boldFont);
956 WMSetLabelTextAlignment(panel->dirLabel, WACenter);
958 WMSetLabelRelief(panel->dirLabel, WRSunken);
960 panel->iconLabel = WMCreateLabel(panel->win);
961 WMResizeWidget(panel->iconLabel, WMScaleX(140), WMScaleY(20));
962 WMMoveWidget(panel->iconLabel, WMScaleX(215), WMScaleY(7));
963 WMSetLabelText(panel->iconLabel, _("Icons"));
964 WMSetLabelFont(panel->iconLabel, boldFont);
965 WMSetLabelTextAlignment(panel->iconLabel, WACenter);
967 WMReleaseFont(boldFont);
969 color = WMWhiteColor(scr->wmscreen);
970 WMSetLabelTextColor(panel->dirLabel, color);
971 WMSetLabelTextColor(panel->iconLabel, color);
972 WMReleaseColor(color);
974 color = WMDarkGrayColor(scr->wmscreen);
975 WMSetWidgetBackgroundColor(panel->iconLabel, color);
976 WMSetWidgetBackgroundColor(panel->dirLabel, color);
977 WMReleaseColor(color);
979 WMSetLabelRelief(panel->iconLabel, WRSunken);
981 panel->dirList = WMCreateList(panel->win);
982 WMResizeWidget(panel->dirList, WMScaleX(200), WMScaleY(170));
983 WMMoveWidget(panel->dirList, WMScaleX(10), WMScaleY(30));
984 WMSetListAction(panel->dirList, listCallback, panel);
986 panel->iconList = WMCreateList(panel->win);
987 WMResizeWidget(panel->iconList, WMScaleX(140), WMScaleY(170));
988 WMMoveWidget(panel->iconList, WMScaleX(215), WMScaleY(30));
989 WMSetListAction(panel->iconList, listCallback, panel);
991 WMHangData(panel->iconList, panel);
993 panel->previewButton = WMCreateCommandButton(panel->win);
994 WMResizeWidget(panel->previewButton, WMScaleX(75), WMScaleY(26));
995 WMMoveWidget(panel->previewButton, WMScaleX(365), WMScaleY(130));
996 WMSetButtonText(panel->previewButton, _("Preview"));
997 WMSetButtonAction(panel->previewButton, buttonCallback, panel);
999 panel->iconView = WMCreateLabel(panel->win);
1000 WMResizeWidget(panel->iconView, WMScaleX(75), WMScaleY(75));
1001 WMMoveWidget(panel->iconView, WMScaleX(365), WMScaleY(40));
1002 WMSetLabelImagePosition(panel->iconView, WIPOverlaps);
1003 WMSetLabelRelief(panel->iconView, WRSunken);
1004 WMSetLabelTextAlignment(panel->iconView, WACenter);
1006 panel->fileLabel = WMCreateLabel(panel->win);
1007 WMResizeWidget(panel->fileLabel, WMScaleX(80), WMScaleY(20));
1008 WMMoveWidget(panel->fileLabel, WMScaleX(10), WMScaleY(210));
1009 WMSetLabelText(panel->fileLabel, _("File Name:"));
1011 panel->fileField = WMCreateTextField(panel->win);
1012 WMSetViewNextResponder(WMWidgetView(panel->fileField), WMWidgetView(panel->win));
1013 WMResizeWidget(panel->fileField, WMScaleX(345), WMScaleY(20));
1014 WMMoveWidget(panel->fileField, WMScaleX(95), WMScaleY(210));
1015 WMSetTextFieldEditable(panel->fileField, False);
1017 panel->okButton = WMCreateCommandButton(panel->win);
1018 WMResizeWidget(panel->okButton, WMScaleX(80), WMScaleY(26));
1019 WMMoveWidget(panel->okButton, WMScaleX(360), WMScaleY(242));
1020 WMSetButtonText(panel->okButton, _("OK"));
1021 WMSetButtonEnabled(panel->okButton, False);
1022 WMSetButtonAction(panel->okButton, buttonCallback, panel);
1024 panel->cancelButton = WMCreateCommandButton(panel->win);
1025 WMResizeWidget(panel->cancelButton, WMScaleX(80), WMScaleY(26));
1026 WMMoveWidget(panel->cancelButton, WMScaleX(270), WMScaleY(242));
1027 WMSetButtonText(panel->cancelButton, _("Cancel"));
1028 WMSetButtonAction(panel->cancelButton, buttonCallback, panel);
1029 #if 0
1030 panel->chooseButton = WMCreateCommandButton(panel->win);
1031 WMResizeWidget(panel->chooseButton, WMScaleX(110), WMScaleY(26));
1032 WMMoveWidget(panel->chooseButton, WMScaleX(150), WMScaleY(242));
1033 WMSetButtonText(panel->chooseButton, _("Choose File"));
1034 WMSetButtonAction(panel->chooseButton, buttonCallback, panel);
1035 #endif
1036 WMRealizeWidget(panel->win);
1037 WMMapSubwidgets(panel->win);
1039 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
1041 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1044 static const char *prefix = NULL;
1045 char *title;
1046 int len;
1047 WMPoint center;
1049 if (prefix == NULL)
1050 prefix = _("Icon Chooser");
1052 len = strlen(prefix)
1053 + 2 // " ["
1054 + (instance ? strlen(instance) : 0)
1055 + 1 // "."
1056 + (class ? strlen(class) : 0)
1057 + 1 // "]"
1058 + 1; // final NUL
1060 title = wmalloc(len);
1061 strcpy(title, prefix);
1063 if (instance || class) {
1064 strcat(title, " [");
1065 if (instance != NULL)
1066 strcat(title, instance);
1067 if (instance && class)
1068 strcat(title, ".");
1069 if (class != NULL)
1070 strcat(title, class);
1071 strcat(title, "]");
1074 center = getCenter(scr, pwidth, pheight);
1076 wwin = wManageInternalWindow(scr, parent, None, title, center.x, center.y, pwidth, pheight);
1077 wfree(title);
1080 /* put icon paths in the list */
1081 listIconPaths(panel->dirList);
1083 WMMapWidget(panel->win);
1085 wWindowMap(wwin);
1087 while (!panel->done) {
1088 XEvent event;
1090 WMNextEvent(dpy, &event);
1091 WMHandleEvent(&event);
1094 if (panel->result) {
1095 char *defaultPath, *wantedPath;
1097 /* check if the file the user selected is not the one that
1098 * would be loaded by default with the current search path */
1099 *file = WMGetListSelectedItem(panel->iconList)->text;
1100 if (**file == 0) {
1101 wfree(*file);
1102 *file = NULL;
1103 } else {
1104 defaultPath = FindImage(wPreferences.icon_path, *file);
1105 wantedPath = WMGetTextFieldText(panel->fileField);
1106 if (defaultPath) {
1107 /* if the file is not the default, use full path */
1108 if (strcmp(wantedPath, defaultPath) != 0) {
1109 *file = wstrdup(wantedPath);
1110 } else {
1111 *file = wstrdup(*file);
1113 wfree(defaultPath);
1115 wfree(wantedPath);
1117 } else {
1118 *file = NULL;
1121 result = panel->result;
1123 WMReleaseFont(panel->normalfont);
1125 WMUnmapWidget(panel->win);
1127 WMDestroyWidget(panel->win);
1129 wUnmanageWindow(wwin, False, False);
1131 wfree(panel);
1133 XDestroyWindow(dpy, parent);
1135 return result;
1139 ***********************************************************************
1140 * Info Panel
1141 ***********************************************************************
1144 typedef struct {
1145 WScreen *scr;
1146 WWindow *wwin;
1147 WMWindow *win;
1148 WMLabel *logoL;
1149 WMLabel *name1L;
1150 WMFrame *lineF;
1151 WMLabel *name2L;
1152 WMLabel *versionL;
1153 WMLabel *infoL;
1154 WMLabel *copyrL;
1155 } InfoPanel;
1157 #define COPYRIGHT_TEXT \
1158 "Copyright \xc2\xa9 1997-2006 Alfredo K. Kojima\n"\
1159 "Copyright \xc2\xa9 1998-2006 Dan Pascu\n"\
1160 "Copyright \xc2\xa9 2013-%hu Window Maker Developers Team"
1162 static InfoPanel *infoPanel = NULL;
1164 static void destroyInfoPanel(WCoreWindow *foo, void *data, XEvent *event)
1166 /* Parameter not used, but tell the compiler that it is ok */
1167 (void) foo;
1168 (void) data;
1169 (void) event;
1171 WMUnmapWidget(infoPanel);
1172 wUnmanageWindow(infoPanel->wwin, False, False);
1173 WMDestroyWidget(infoPanel->win);
1174 wfree(infoPanel);
1175 infoPanel = NULL;
1178 char *getPrettyOSName(void)
1180 char line[200];
1181 char *token;
1182 char *posn = NULL;
1183 const char s[2] = "=";
1184 FILE *fp;
1186 fp = fopen("/etc/os-release", "r");
1187 if (!fp) {
1188 fp = fopen("/usr/lib/os-release", "r");
1189 if (!fp) {
1190 wwarning(_("no os-release file on the system"));
1191 return NULL;
1195 while (fgets(line, sizeof(line), fp) != NULL) {
1196 if (strncmp(line, "PRETTY_NAME", strlen("PRETTY_NAME")) == 0) {
1197 line[strcspn(line, "\r\n")] = 0;
1198 token = strtok(line, s);
1199 if (token) {
1200 //get straight to the second part of the line
1201 token = strtok(NULL, s);
1202 if (token) {
1203 //removing potential quotes
1204 char *dst = token;
1205 char *src = token;
1206 char c;
1208 while ((c = *src++) != '\0') {
1209 if (c == '\\') {
1210 *dst++ = c;
1211 if ((c = *src++) == '\0')
1212 break;
1213 *dst++ = c;
1214 } else if (c != '"' && c != '\'')
1215 *dst++ = c;
1217 *dst = '\0';
1218 posn = wmalloc(strlen(token) + 1);
1219 strcpy(posn, token);
1222 break;
1225 fclose(fp);
1226 return posn;
1229 void wShowInfoPanel(WScreen *scr)
1231 InfoPanel *panel;
1232 WMPixmap *logo;
1233 WMFont *font;
1234 char *strbuf = NULL;
1235 const char *separator;
1236 char buffer[256];
1237 Window parent;
1238 WWindow *wwin;
1239 WMPoint center;
1240 char **strl;
1241 int i, width = 50, sepHeight;
1242 char *visuals[] = {
1243 "StaticGray",
1244 "GrayScale",
1245 "StaticColor",
1246 "PseudoColor",
1247 "TrueColor",
1248 "DirectColor"
1250 int wmScaleWidth, wmScaleHeight;
1251 int pwidth, pheight;
1252 int current_year = 2020;
1253 time_t s;
1254 struct tm *current_time;
1255 struct utsname uts;
1257 s = time(NULL);
1258 if (s) {
1259 current_time = localtime(&s);
1260 if (current_time->tm_year > (current_year - 1900))
1261 current_year = current_time->tm_year + 1900;
1264 if (infoPanel) {
1265 if (infoPanel->scr == scr) {
1266 wRaiseFrame(infoPanel->wwin->frame->core);
1267 wSetFocusTo(scr, infoPanel->wwin);
1269 return;
1272 panel = wmalloc(sizeof(InfoPanel));
1274 panel->scr = scr;
1276 panel->win = WMCreateWindow(scr->wmscreen, "info");
1277 WMGetScaleBaseFromSystemFont(scr->wmscreen, &wmScaleWidth, &wmScaleHeight);
1278 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2) && defined(DEBUG)
1279 pwidth = WMScaleX(412);
1280 #else
1281 pwidth = WMScaleX(382);
1282 #endif
1283 pheight = WMScaleY(270);
1284 WMResizeWidget(panel->win, pwidth, pheight);
1286 logo = WMCreateApplicationIconBlendedPixmap(scr->wmscreen, (RColor *) NULL);
1287 if (!logo) {
1288 logo = WMRetainPixmap(WMGetApplicationIconPixmap(scr->wmscreen));
1290 if (logo) {
1291 panel->logoL = WMCreateLabel(panel->win);
1292 WMResizeWidget(panel->logoL, WMScaleX(64), WMScaleY(64));
1293 WMMoveWidget(panel->logoL, WMScaleX(30), WMScaleY(20));
1294 WMSetLabelImagePosition(panel->logoL, WIPImageOnly);
1295 WMSetLabelImage(panel->logoL, logo);
1296 WMReleasePixmap(logo);
1299 sepHeight = WMScaleY(3);
1300 panel->name1L = WMCreateLabel(panel->win);
1301 WMResizeWidget(panel->name1L, WMScaleX(240), WMScaleY(30) + WMScaleY(2));
1302 WMMoveWidget(panel->name1L, WMScaleX(100), WMScaleY(30) - WMScaleY(2) - sepHeight);
1304 snprintf(buffer,
1305 sizeof(buffer),
1306 "Lucida Sans,Comic Sans MS,URW Gothic L,Trebuchet MS:italic:pixelsize=%d:antialias=true",
1307 WMScaleY(24));
1308 font = WMCreateFont(scr->wmscreen, buffer);
1309 strbuf = "Window Maker";
1310 if (font) {
1311 width = WMWidthOfString(font, strbuf, strlen(strbuf));
1312 WMSetLabelFont(panel->name1L, font);
1313 WMReleaseFont(font);
1315 WMSetLabelTextAlignment(panel->name1L, WACenter);
1316 WMSetLabelText(panel->name1L, strbuf);
1318 panel->lineF = WMCreateFrame(panel->win);
1319 WMResizeWidget(panel->lineF, width, sepHeight);
1320 WMMoveWidget(panel->lineF, WMScaleX(100) + (WMScaleX(240) - width) / 2, WMScaleY(60) - sepHeight);
1321 WMSetFrameRelief(panel->lineF, WRSimple);
1322 WMSetWidgetBackgroundColor(panel->lineF, scr->black);
1324 panel->name2L = WMCreateLabel(panel->win);
1325 WMResizeWidget(panel->name2L, WMScaleX(240), WMScaleY(24));
1326 WMMoveWidget(panel->name2L, WMScaleX(100), WMScaleY(60));
1327 snprintf(buffer, sizeof(buffer), "URW Gothic L,Nimbus Sans L:pixelsize=%d:antialias=true", WMScaleY(16));
1328 font = WMCreateFont(scr->wmscreen, buffer);
1329 if (font) {
1330 WMSetLabelFont(panel->name2L, font);
1331 WMReleaseFont(font);
1332 font = NULL;
1334 WMSetLabelTextAlignment(panel->name2L, WACenter);
1335 WMSetLabelText(panel->name2L, _("Window Manager for X"));
1337 snprintf(buffer, sizeof(buffer), _("Version %s"), VERSION);
1338 panel->versionL = WMCreateLabel(panel->win);
1339 WMResizeWidget(panel->versionL, WMScaleX(310), WMScaleY(16));
1340 WMMoveWidget(panel->versionL, WMScaleX(30), WMScaleY(95));
1341 WMSetLabelTextAlignment(panel->versionL, WARight);
1342 WMSetLabelText(panel->versionL, buffer);
1343 WMSetLabelWraps(panel->versionL, False);
1345 panel->copyrL = WMCreateLabel(panel->win);
1346 WMResizeWidget(panel->copyrL, WMScaleX(360), WMScaleY(60));
1347 WMMoveWidget(panel->copyrL, WMScaleX(15), WMScaleY(210));
1348 WMSetLabelTextAlignment(panel->copyrL, WALeft);
1350 snprintf(buffer, sizeof(buffer), COPYRIGHT_TEXT, current_year);
1351 WMSetLabelText(panel->copyrL, buffer);
1352 font = WMSystemFontOfSize(scr->wmscreen, WMScaleY(11));
1353 if (font) {
1354 WMSetLabelFont(panel->copyrL, font);
1355 WMReleaseFont(font);
1356 font = NULL;
1359 strbuf = NULL;
1360 if (uname(&uts) != -1) {
1361 char *posn = getPrettyOSName();
1362 if (posn) {
1363 snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), posn, uts.machine);
1364 free(posn);
1366 else
1367 snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), uts.sysname, uts.machine);
1368 strbuf = wstrappend(strbuf, buffer);
1371 snprintf(buffer, sizeof(buffer), _("Using visual 0x%x: %s %ibpp "),
1372 (unsigned)scr->w_visual->visualid, visuals[scr->w_visual->class], scr->w_depth);
1373 strbuf = wstrappend(strbuf, buffer);
1375 switch (scr->w_depth) {
1376 case 15:
1377 strbuf = wstrappend(strbuf, _("(32 thousand colors)\n"));
1378 break;
1379 case 16:
1380 strbuf = wstrappend(strbuf, _("(64 thousand colors)\n"));
1381 break;
1382 case 24:
1383 case 32:
1384 strbuf = wstrappend(strbuf, _("(16 million colors)\n"));
1385 break;
1386 case 30:
1387 case 40:
1388 strbuf = wstrappend(strbuf, _("(1 billion colors)\n"));
1389 break;
1390 default:
1391 snprintf(buffer, sizeof(buffer), _("(%d colors)\n"), 1 << scr->w_depth);
1392 strbuf = wstrappend(strbuf, buffer);
1393 break;
1396 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2)
1398 struct mallinfo2 ma = mallinfo2();
1399 snprintf(buffer, sizeof(buffer),
1400 #ifdef DEBUG
1401 _("Total memory allocated: %lu kB (in use: %lu kB, %lu free chunks)\n"),
1402 #else
1403 _("Total memory allocated: %lu kB (in use: %lu kB)\n"),
1404 #endif
1405 (ma.arena + ma.hblkhd) / 1024,
1406 (ma.uordblks + ma.hblkhd) / 1024
1407 #ifdef DEBUG
1409 * This information is representative of the memory
1410 * fragmentation. In ideal case it should be 1, but
1411 * that is never possible
1413 , ma.ordblks
1414 #endif
1417 strbuf = wstrappend(strbuf, buffer);
1419 #endif
1421 strbuf = wstrappend(strbuf, _("Image formats: "));
1422 strl = RSupportedFileFormats();
1423 separator = NULL;
1424 for (i = 0; strl[i] != NULL; i++) {
1425 if (separator != NULL)
1426 strbuf = wstrappend(strbuf, separator);
1427 strbuf = wstrappend(strbuf, strl[i]);
1428 separator = ", ";
1431 strbuf = wstrappend(strbuf, _("\nAdditional support for: "));
1432 strbuf = wstrappend(strbuf, "WMSPEC");
1434 #ifdef USE_MWM_HINTS
1435 strbuf = wstrappend(strbuf, ", MWM");
1436 #endif
1438 #ifdef USE_DOCK_XDND
1439 strbuf = wstrappend(strbuf, ", XDnD");
1440 #endif
1442 #ifdef USE_XRES
1443 strbuf = wstrappend(strbuf, ", XRes");
1444 #endif
1446 #ifdef USE_MAGICK
1447 strbuf = wstrappend(strbuf, ", ImageMagick");
1448 #endif
1450 #ifdef USE_XINERAMA
1451 strbuf = wstrappend(strbuf, _("\n"));
1452 #ifdef SOLARIS_XINERAMA
1453 strbuf = wstrappend(strbuf, _("Solaris "));
1454 #endif
1455 strbuf = wstrappend(strbuf, _("Xinerama: "));
1457 char tmp[128];
1458 snprintf(tmp, sizeof(tmp) - 1, _("%d head(s) found"), scr->xine_info.count);
1459 strbuf = wstrappend(strbuf, tmp);
1461 #endif
1463 #ifdef USE_RANDR
1464 strbuf = wstrappend(strbuf, _("\n"));
1465 strbuf = wstrappend(strbuf, "RandR: ");
1466 if (w_global.xext.randr.supported)
1467 strbuf = wstrappend(strbuf, _("supported"));
1468 else
1469 strbuf = wstrappend(strbuf, _("unsupported"));
1470 #endif
1472 panel->infoL = WMCreateLabel(panel->win);
1473 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2) && defined(DEBUG)
1474 WMResizeWidget(panel->infoL, WMScaleX(380), WMScaleY(100));
1475 #else
1476 WMResizeWidget(panel->infoL, WMScaleX(350), WMScaleY(100));
1477 #endif
1478 WMMoveWidget(panel->infoL, WMScaleX(15), WMScaleY(115));
1479 WMSetLabelText(panel->infoL, strbuf);
1480 font = WMSystemFontOfSize(scr->wmscreen, WMScaleY(11));
1481 if (font) {
1482 WMSetLabelFont(panel->infoL, font);
1483 WMReleaseFont(font);
1484 font = NULL;
1486 wfree(strbuf);
1488 WMRealizeWidget(panel->win);
1489 WMMapSubwidgets(panel->win);
1491 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
1493 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1495 WMMapWidget(panel->win);
1497 center = getCenter(scr, pwidth, pheight);
1498 wwin = wManageInternalWindow(scr, parent, None, _("Info"), center.x, center.y, pwidth, pheight);
1500 WSETUFLAG(wwin, no_closable, 0);
1501 WSETUFLAG(wwin, no_close_button, 0);
1502 #ifdef XKB_BUTTON_HINT
1503 wFrameWindowHideButton(wwin->frame, WFF_LANGUAGE_BUTTON);
1504 #endif
1505 wWindowUpdateButtonImages(wwin);
1506 wFrameWindowShowButton(wwin->frame, WFF_RIGHT_BUTTON);
1507 wwin->frame->on_click_right = destroyInfoPanel;
1509 wWindowMap(wwin);
1511 panel->wwin = wwin;
1512 infoPanel = panel;
1516 ***********************************************************************
1517 * Legal Panel
1518 ***********************************************************************
1521 typedef struct {
1522 WScreen *scr;
1523 WWindow *wwin;
1524 WMWindow *win;
1525 WMFrame *frame;
1526 WMLabel *licenseL;
1527 } LegalPanel;
1529 static LegalPanel *legalPanel = NULL;
1531 static void destroyLegalPanel(WCoreWindow * foo, void *data, XEvent * event)
1533 /* Parameter not used, but tell the compiler that it is ok */
1534 (void) foo;
1535 (void) data;
1536 (void) event;
1538 WMUnmapWidget(legalPanel->win);
1539 WMDestroyWidget(legalPanel->win);
1540 wUnmanageWindow(legalPanel->wwin, False, False);
1541 wfree(legalPanel);
1542 legalPanel = NULL;
1545 void wShowLegalPanel(WScreen *scr)
1547 LegalPanel *panel;
1548 Window parent;
1549 WWindow *wwin;
1550 WMPoint center;
1551 int wmScaleWidth, wmScaleHeight;
1552 int pwidth, pheight;
1554 if (legalPanel) {
1555 if (legalPanel->scr == scr) {
1556 wRaiseFrame(legalPanel->wwin->frame->core);
1557 wSetFocusTo(scr, legalPanel->wwin);
1559 return;
1562 panel = wmalloc(sizeof(LegalPanel));
1563 panel->scr = scr;
1564 panel->win = WMCreateWindow(scr->wmscreen, "legal");
1565 WMGetScaleBaseFromSystemFont(scr->wmscreen, &wmScaleWidth, &wmScaleHeight);
1566 pwidth = WMScaleX(440);
1567 pheight = WMScaleY(270);
1568 WMResizeWidget(panel->win, pwidth, pheight);
1570 panel->frame = WMCreateFrame(panel->win);
1571 WMResizeWidget(panel->frame, pwidth - (2 * WMScaleX(10)), pheight - (2 * WMScaleY(10)));
1572 WMMoveWidget(panel->frame, WMScaleX(10), WMScaleY(10));
1573 WMSetFrameTitle(panel->frame, NULL);
1575 panel->licenseL = WMCreateLabel(panel->frame);
1576 WMSetLabelWraps(panel->licenseL, True);
1577 WMResizeWidget(panel->licenseL, pwidth - (4 * WMScaleX(10)), pheight - (4 * WMScaleY(10)));
1578 WMMoveWidget(panel->licenseL, WMScaleX(8), WMScaleY(8));
1579 WMSetLabelTextAlignment(panel->licenseL, WALeft);
1580 WMSetLabelText(panel->licenseL,
1581 _(" Window Maker is free software; you can redistribute it and/or "
1582 "modify it under the terms of the GNU General Public License as "
1583 "published by the Free Software Foundation; either version 2 of the "
1584 "License, or (at your option) any later version.\n\n"
1585 " Window Maker is distributed in the hope that it will be useful, "
1586 "but WITHOUT ANY WARRANTY; without even the implied warranty "
1587 "of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. "
1588 "See the GNU General Public License for more details.\n\n"
1589 " You should have received a copy of the GNU General Public "
1590 "License along with this program; if not, write to the Free Software "
1591 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA"
1592 "02110-1301 USA."));
1594 WMRealizeWidget(panel->win);
1595 WMMapSubwidgets(panel->win);
1596 WMMapSubwidgets(panel->frame);
1598 parent = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, pwidth, pheight, 0, 0, 0);
1599 XReparentWindow(dpy, WMWidgetXID(panel->win), parent, 0, 0);
1600 center = getCenter(scr, pwidth, pheight);
1601 wwin = wManageInternalWindow(scr, parent, None, _("Legal"), center.x, center.y, pwidth, pheight);
1603 WSETUFLAG(wwin, no_closable, 0);
1604 WSETUFLAG(wwin, no_close_button, 0);
1605 wWindowUpdateButtonImages(wwin);
1606 wFrameWindowShowButton(wwin->frame, WFF_RIGHT_BUTTON);
1607 #ifdef XKB_BUTTON_HINT
1608 wFrameWindowHideButton(wwin->frame, WFF_LANGUAGE_BUTTON);
1609 #endif
1610 wwin->frame->on_click_right = destroyLegalPanel;
1611 panel->wwin = wwin;
1613 WMMapWidget(panel->win);
1614 wWindowMap(wwin);
1615 legalPanel = panel;
1619 ***********************************************************************
1620 * Crashing Dialog Panel
1621 ***********************************************************************
1624 typedef struct _CrashPanel {
1625 WMWindow *win; /* main window */
1627 WMLabel *iconL; /* application icon */
1628 WMLabel *nameL; /* title of panel */
1630 WMFrame *sepF; /* separator frame */
1632 WMLabel *noteL; /* Title of note */
1633 WMLabel *note2L; /* body of note with what happened */
1635 WMFrame *whatF; /* "what to do next" frame */
1636 WMPopUpButton *whatP; /* action selection popup button */
1638 WMButton *okB; /* ok button */
1640 Bool done; /* if finished with this dialog */
1641 int action; /* what to do after */
1643 KeyCode retKey;
1645 } CrashPanel;
1647 static void handleKeyPress(XEvent * event, void *clientData)
1649 CrashPanel *panel = (CrashPanel *) clientData;
1651 if (event->xkey.keycode == panel->retKey) {
1652 WMPerformButtonClick(panel->okB);
1656 static void okButtonCallback(void *self, void *clientData)
1658 CrashPanel *panel = (CrashPanel *) clientData;
1660 /* Parameter not used, but tell the compiler that it is ok */
1661 (void) self;
1663 panel->done = True;
1666 static void setCrashAction(void *self, void *clientData)
1668 WMPopUpButton *pop = (WMPopUpButton *) self;
1669 CrashPanel *panel = (CrashPanel *) clientData;
1671 panel->action = WMGetPopUpButtonSelectedItem(pop);
1674 /* Make this read the logo from a compiled in pixmap -Dan */
1675 static WMPixmap *getWindowMakerIconImage(WMScreen *scr)
1677 WMPixmap *pix = NULL;
1678 char *path = NULL;
1680 /* Get the Logo icon, without the default icon */
1681 path = get_icon_filename("Logo", "WMPanel", NULL, False);
1683 if (path) {
1684 RColor gray;
1686 gray.red = 0xae;
1687 gray.green = 0xaa;
1688 gray.blue = 0xae;
1689 gray.alpha = 0;
1691 pix = WMCreateBlendedPixmapFromFile(scr, path, &gray);
1692 wfree(path);
1695 return pix;
1698 #define PWIDTH 295
1699 #define PHEIGHT 345
1701 int wShowCrashingDialogPanel(int whatSig)
1703 CrashPanel *panel;
1704 WMScreen *scr;
1705 WMFont *font;
1706 WMPixmap *logo;
1707 int screen_no, scr_width, scr_height;
1708 int action;
1709 char buf[256];
1711 screen_no = DefaultScreen(dpy);
1712 scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_no));
1713 scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_no));
1715 scr = WMCreateScreen(dpy, screen_no);
1716 if (!scr) {
1717 werror(_("cannot open connection for crashing dialog panel. Aborting."));
1718 return WMAbort;
1721 panel = wmalloc(sizeof(CrashPanel));
1723 panel->retKey = XKeysymToKeycode(dpy, XK_Return);
1725 panel->win = WMCreateWindow(scr, "crashingDialog");
1726 WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
1727 WMMoveWidget(panel->win, (scr_width - PWIDTH) / 2, (scr_height - PHEIGHT) / 2);
1729 logo = getWindowMakerIconImage(scr);
1730 if (logo) {
1731 panel->iconL = WMCreateLabel(panel->win);
1732 WMResizeWidget(panel->iconL, 64, 64);
1733 WMMoveWidget(panel->iconL, 10, 10);
1734 WMSetLabelImagePosition(panel->iconL, WIPImageOnly);
1735 WMSetLabelImage(panel->iconL, logo);
1738 panel->nameL = WMCreateLabel(panel->win);
1739 WMResizeWidget(panel->nameL, 200, 30);
1740 WMMoveWidget(panel->nameL, 80, 25);
1741 WMSetLabelTextAlignment(panel->nameL, WALeft);
1742 font = WMBoldSystemFontOfSize(scr, 24);
1743 WMSetLabelFont(panel->nameL, font);
1744 WMReleaseFont(font);
1745 WMSetLabelText(panel->nameL, _("Fatal error"));
1747 panel->sepF = WMCreateFrame(panel->win);
1748 WMResizeWidget(panel->sepF, PWIDTH + 4, 2);
1749 WMMoveWidget(panel->sepF, -2, 80);
1751 panel->noteL = WMCreateLabel(panel->win);
1752 WMResizeWidget(panel->noteL, PWIDTH - 20, 40);
1753 WMMoveWidget(panel->noteL, 10, 90);
1754 WMSetLabelTextAlignment(panel->noteL, WAJustified);
1755 snprintf(buf, sizeof(buf), _("Window Maker received signal %i."), whatSig);
1756 WMSetLabelText(panel->noteL, buf);
1758 panel->note2L = WMCreateLabel(panel->win);
1759 WMResizeWidget(panel->note2L, PWIDTH - 20, 100);
1760 WMMoveWidget(panel->note2L, 10, 130);
1761 WMSetLabelTextAlignment(panel->note2L, WALeft);
1762 snprintf(buf, sizeof(buf), /* Comment for the PO file: the %s is an email address */
1763 _(" This fatal error occurred probably due to a bug."
1764 " Please fill the included BUGFORM and report it to %s."),
1765 PACKAGE_BUGREPORT);
1766 WMSetLabelText(panel->note2L, buf);
1767 WMSetLabelWraps(panel->note2L, True);
1769 panel->whatF = WMCreateFrame(panel->win);
1770 WMResizeWidget(panel->whatF, PWIDTH - 20, 50);
1771 WMMoveWidget(panel->whatF, 10, 240);
1772 WMSetFrameTitle(panel->whatF, _("What do you want to do now?"));
1774 panel->whatP = WMCreatePopUpButton(panel->whatF);
1775 WMResizeWidget(panel->whatP, PWIDTH - 20 - 70, 20);
1776 WMMoveWidget(panel->whatP, 35, 20);
1777 WMSetPopUpButtonPullsDown(panel->whatP, False);
1778 WMSetPopUpButtonText(panel->whatP, _("Select action"));
1779 WMAddPopUpButtonItem(panel->whatP, _("Abort and leave a core file"));
1780 WMAddPopUpButtonItem(panel->whatP, _("Restart Window Maker"));
1781 WMAddPopUpButtonItem(panel->whatP, _("Start alternate window manager"));
1782 WMSetPopUpButtonAction(panel->whatP, setCrashAction, panel);
1783 WMSetPopUpButtonSelectedItem(panel->whatP, WMRestart);
1784 panel->action = WMRestart;
1786 WMMapSubwidgets(panel->whatF);
1788 panel->okB = WMCreateCommandButton(panel->win);
1789 WMResizeWidget(panel->okB, 80, 26);
1790 WMMoveWidget(panel->okB, 205, 309);
1791 WMSetButtonText(panel->okB, _("OK"));
1792 WMSetButtonImage(panel->okB, WMGetSystemPixmap(scr, WSIReturnArrow));
1793 WMSetButtonAltImage(panel->okB, WMGetSystemPixmap(scr, WSIHighlightedReturnArrow));
1794 WMSetButtonImagePosition(panel->okB, WIPRight);
1795 WMSetButtonAction(panel->okB, okButtonCallback, panel);
1797 panel->done = 0;
1799 WMCreateEventHandler(WMWidgetView(panel->win), KeyPressMask, handleKeyPress, panel);
1801 WMRealizeWidget(panel->win);
1802 WMMapSubwidgets(panel->win);
1804 WMMapWidget(panel->win);
1806 XSetInputFocus(dpy, WMWidgetXID(panel->win), RevertToParent, CurrentTime);
1808 while (!panel->done) {
1809 XEvent event;
1811 WMNextEvent(dpy, &event);
1812 WMHandleEvent(&event);
1815 action = panel->action;
1817 WMUnmapWidget(panel->win);
1818 WMDestroyWidget(panel->win);
1819 wfree(panel);
1821 return action;